In this example we use the lifting line method to solve the aerodynamics of a $36^\circ$ swept-back wing with a cambered NACA 64(1)-612 airfoil from the NACA RM A50K27 Flying Wing​ report.

#=##############################################################################
# DESCRIPTION
    36deg swept-back wing with a cambered NACA 64(1)-612 airfoil from the NACA 
    RM A50K27 Flying Wing​ report. This wing has an aspect ratio of 15 and tapper 
    ratio of 0.5. The experiment was run at Re_c = 2e6 and Mach 0.27.

    This example uses the nonlinear lifting line method.

# AUTHORSHIP
  * Author    : Eduardo J. Alvarez
  * Email     : Edo.AlvarezR@gmail.com
  * Created   : Jan 2026
  * License   : MIT License
=###############################################################################

import FLOWPanel as pnl
import FLOWPanel: mean, norm, dot, cross

import PyPlot as plt



run_name        = "ll-a50k27"                   # Name of this run

save_path       = run_name                      # Where to save outputs
airfoil_path    = joinpath(pnl.examples_path, "data") # Where to find 2D polars

paraview        = false                         # Whether to visualize with Paraview


# ----------------- SIMULATION PARAMETERS --------------------------------------
magUinf         = 91.3                          # (m/s) freestream velocity
rho             = 1.225                         # (kg/m^3) air density


# ------------------ GEOMETRY PARAMETERS ---------------------------------------

# High-level parameters
b               = 2*1.5490                      # (m) wing span

# Discretization parameters
nelements       = 40                            # Number of stripwise elements per semi-span
discretization  = [                             # Multi-discretization of wing (seg length, ndivs, expansion, central)
                    (1.00,  nelements, 1/10, false),
                  ]
symmetric       = true                          # Whether the wing is symmetric

# Chord distribution (nondim y-position, nondim chord)
chord_distribution = [
#   2*y/b   c/b
    0.0     0.132989
    1.0     0.0664945
]

# Twist distribution (nondim y-position, twist)
twist_distribution = [
#   2*y/b   twist (deg)
    0.0     0.0
    1.0     0.0
]

# Sweep distribution (nondim y-position, sweep)
sweep_distribution = [
#   2*y/b   sweep (deg)
    0.0     36.2603
    1.0     36.2603
]

# Dihedral distribution (nondim y-position, dihedral)
dihedral_distribution = [
#   2*y/b   dihedral (deg)
    0.0     0.0
    1.0     0.0
]

# Span-axis distribution: chordwise point about which the wing is twisted, 
# swept, and dihedralized (nondim y-position, nondim chord-position)
spanaxis_distribution = [
#   2*y/b   x/c
    0.0     0.25
    1.0     0.25
]

# Airfoil contour distribution (nondim y-position, polar, airfoil type)
airfoil_distribution = [
#    2*y/b  polar file                                airfoil type
    (0.00, "n64_1_A612-Re0p5e6-neuralfoil180-3.csv",  pnl.SimpleAirfoil),
    (1.00, "n64_1_A612-Re0p5e6-neuralfoil180-3.csv",  pnl.SimpleAirfoil)
]

element_optargs = (;    path = airfoil_path,
                        plot_polars = true,
                        extrapolatepolar = false,   # Whether to extrapolate the 2D polars to ±180 deg
                    )


# ------------------ SOLVER PARAMETERS -----------------------------------------
deltasb         = 1.0                           # Blending distance, deltasb = 2*dy/b
deltajoint      = 1.0                           # Joint distance, deltajoint = dx/c

sigmafactor     = 0.0                           # Dragging line amplification factor (set to -1.0 for rebust post-stall method)
sigmaexponent   = 1.0                           # Dragging line amplification exponent (no effects if `sigmafactor==0.0`)

                                                # Nonlinear solver
solver          = pnl.SimpleNonlinearSolve.SimpleDFSane()              # Indifferent to initial guess, but somewhat not robust
# solver        = pnl.SimpleNonlinearSolve.SimpleTrustRegion()         # Trust region needs a good initial guess, but it converges very reliably

solver_optargs  = (; 
                    abstol = 1e-9,  
                    maxiters = 800,
                    )

align_joints_with_Uinfs = true                  # Whether to align joint bound vortices with the freestream
use_Uind_for_force = false                      # Whether to use Uind as opposed to selfUind for force postprocessing
                                                # (`true` for more accurate spanwise cd distribution, but worse integrated CD)

X0              = [0.595, 0, 0]                 # Center about which to calculate moments

cref            = 0.2472                        # (m) reference chord
Aref            = 0.957                         # (m^2) reference area
nondim          = 0.5*rho*magUinf^2*Aref        # Normalization factor


# ------------------ GENERATE LIFTING LINE -------------------------------------

ll = pnl.LiftingLine{Float64}(
                                airfoil_distribution; 
                                b, chord_distribution, twist_distribution,
                                sweep_distribution, dihedral_distribution,
                                spanaxis_distribution,
                                discretization,
                                symmetric,
                                deltasb, deltajoint, sigmafactor, sigmaexponent,
                                element_optargs,
                                plot_discretization = true,
                                )

display(ll)


# ------------------ OUTPUT GEOMETRY -------------------------------------------
if !isnothing(save_path)
    
    str = pnl.save(ll, run_name; path=save_path, debug=true) # Use `debug=true` to output the effective horseshoes

    if paraview
        run(`paraview --data=$(joinpath(save_path, str))`)
    end
    
end



# ----------------- AOA SWEEP --------------------------------------------------

# Sequence of sweeps to run
# NOTE: To help convergence and speed it up the sweep, we recommend starting
#       each sweep at 0deg AOA since the sweep steps over points using the last
#       converged solution as the initial guess
sweep_neg = range(0, -50, step=-0.5)        # Sweep from 0 into deep negative stall (-50deg)
sweep_pos = range(0, 50, step=0.5)          # Sweep from 0 into deep positive stall (50deg)


@time wingpolar = pnl.run_polarsweep(ll,
                            magUinf, rho, X0, cref, b; 
                            Aref,
                            aoa_sweeps = (sweep_neg, sweep_pos),
                            solver,
                            solver_optargs,
                            align_joints_with_Uinfs, 
                            use_Uind_for_force
                        )
Run time: ~7 seconds, evaluated 202 AOAs with 86% success rate.


(see the complete example under examples/liftingline_a50k27.jl to see how to postprocess the spanwise loading that is plotted below)



Wing Polar
Pic here

Wing Polar Post-Stall
Pic here
Tip

You can also automatically run this example and generate these plots with the following command:

import FLOWPanel as pnl

include(joinpath(pnl.examples_path, "liftingline_a50k27.jl"))