Airfoil Configuration Optimization with Genetic Algorithms

This article describes the first iteration of a project I did as part of Penn Electric Racing, the University of Pennsylvania’s Formula SAE Electric team. It uses JavaFoil, a panel method solver that we wanted to investigate. Ultimately we switched out JavaFoil for OpenFOAM, a true CFD solver, and had much better results that gave REV5 the rear wing it has today. Since we’re still hoping to get a boost from using this tool for other parts of our aero package I won’t be releasing the source code publically, but feel free to message me if you’re curious. In any case, I hope this post prevents other teams from wasting time trying panel method solvers.

When designing a multi-element airfoil, the number of possible configurations is enormous. For REV5, we’re moving to a five-element rear wing, where each element has a location, rotation, and possibly size to optimize. This ends up producing a sample space which is far too large to search exhaustively. To make matters worse, the aerodynamic performance of a wing is estimated using some kind of numerical solver, which is usually slow and makes evaluating configurations a drag. To help optimize element configuration, I’ve written a tool that uses a genetic algorithm and JavaFoil to find the best wing.

The Genetic Algorithm

I won’t get into the basics of genetic algorithms as they’ve been written about pretty extensively; you can read the wiki for a quick overview. The core idea is to represent a particular multi-element airfoil as a genome, seed an initial population with random airfoils, and then iteratively improve the airfoils from generation to generation through mutation and natural selection. We use genetic algorithms because of the high dimensionality and nonconvexity of the search space–other global optimization algorithms (e.g. simulated annealing) would probably have worked similarly but in order to make the tool accessible to future generations of Penn Electric Students I’ve opted for simplest option. The setup I’ve used is based on genetic.js and involves:

  • 200 generations of size 10
  • 0.5 mutation and 0.5 crossover probabilities
  • Single-point crossover function
  • Fittest 1 selection and then a 2-Tournament for 2 selection (always bring fittest individual into next generation)
  • Either coefficient of lift or downforce as fitness function (unitless)
  • Varied relative position and angle of attack (not scale since our molds were already fixed); these values were constrained to reasonable values

Evaluating Airfoil Configurations

In order to calculate the fitness of a particular configuration, we need to use an aerodynamics software package. Broadly speaking, aerodynamic simulation software can be grouped into panel-method solvers (such as JavaFoil) and computational fluid dynamics packages (such as StarCCM). Panel solvers are a lot faster, CFD mesh solvers are usually much more accurate and can simulate more complicated turbulence / element interaction effects. JavaFoil has the following disclaimer in their user manual:

As JavaFoil does not model laminar separation bubbles and flow separation, its results will become inaccurate if such effects occur. The boundary layer method does not include any feedback to the potential flow solution, which means that it is limited to mostly attached flows. Flow separation, as it occurs at stall, is modeled to some extent by empirical corrections, so that maximum lift can be estimated for conventional airfoils. If you analyze an airfoil beyond stall, the results will be quite inaccurate. On the other hand, it is somewhat questionable, whether any two-dimensional analysis method can be used at all in this regime, as the flow field beyond stall becomes fully three dimensional with spanwise flow and strong vortices developing.

In the case of multi element airfoils, one must be aware, that in the real world very complex flows can develop due to interaction of trailing wakes and the boundary layers of the individual elements or if the boundary layers separate locally. An accurate analysis would require a more sophisticated solver for the Navier-Stokes equations, which would also imply an increase in computer time in the order of 1000. Nevertheless a simple tool like JavaFoil can be helpful to estimate the main effects and to improve a design to avoid suction peaks and flow separation.

Even though JavaFoil didn’t advertise itself as accurate for multi-element airfoils, we decided to try it anyways since it’s significantly faster than CFD (1 second / configuration vs 10-20 seconds / 2D configuration). Ultimately, by comparing JavaFoil output to StarCCM, we concluded that it wasn’t really accurate enough for what we’re trying to do–more on this later.


We optimized for lift coefficient and downforce for both 4 and 5 element airfoils. Downforce is proportional to the coefficient of lift times the cross section size, which means that we expect the downforce optimization to generate “taller” airfoils. Simulations usually hit an asymptote after around 80-100 generations. Importantly, we didn’t expect coefficient of lift and downforce to be correct in absolute terms (especially since it was very sensitive to scaling); we were just hoping that relative results between two airfoils to be similar in JavaFoil and a CFD package like StarCCM. Below you can see some representative results for 4/5 element airfoils optimizing for cl and cd. The faded out traces in the back represent the best airfoils from previous generations; the final configuration after 200 generations is outlined. Axes are unitless.

Fitness = Lift CoefficientFitness = Downforce
4 elem
5 elem


  • Sometimes airfoils that performed similarly in JavaFoil performed very differently in StarCCM (up to 20%)
  • For Cl optimizations, the optimal main element angle of attack was basically flat, which didn’t make much sense (for downforce it was sensibly angled)
  • For Cl optimizations, the angle of attack of the leading element and position of the second element relative to the first didn’t really converge to one value across many runs, area of attack especially varied wildly
  • The fourth and fifth element didn’t usually have any x overlap with the trailing edge of the previous element; would expect the elements to be “staggered,” which did occur for the element after the main element
  • Sometimes a mutation overlapped two elements and the Cl went bonkers
  • Configurations generated by the genetic algorithm might not fit in the bounds of the endplates (would have to add a constraint for this somehow)
  • Simulations in JavaFoil were not scale-invariant; changing the size of a single standalone element with 0 area of attack would change the Cl (also part of reason why scale was constrained, JavaFoil would just blow up the elements as large as possible otherwise)


  • Genetic algorithms by and large work, random configurations would eventually converge to a sensible-looking final configuration
    • Usually take 50-80 generations to converge
    • Increasing population size didn’t help convergence
  • Interestingly, convergence was a lot nicer and more reproducible when optimizing for downforce rather than coefficient of lift
    • End fitness values were more similar
    • Consistently placed main element to have overlap with leading element
  • The solver regularly figured out staggering for the element after the main element (but not for later elements)
  • Panel method solvers don’t capture the full range of aerodynamic effects that are needed
  • Switching from panel method solvers to true CFD solvers mostly addressed the issues with panel method solvers






Leave a Reply

Your email address will not be published. Required fields are marked *