High-performance subsonic airfoil analysis with Numba JIT acceleration.
NFoil is a fork of mfoil by Krzysztof J. Fidkowski, rewritten with Numba JIT compilation for ~18x faster subsonic airfoil analysis. It retains full numerical compatibility with the original while dramatically reducing solve times with the addition of a Graphical User Interface (GUI).


Developed and optimized by Cayetano Martínez-Muriel with assistance from Google Antigravity. Based on the original mfoil by Krzysztof J. Fidkowski, which uses mostly the same physical models as XFOIL, with some modifications.
Test: Polar computation consisting of 16 angles of attack for the viscous flow around a NACA 2412 airfoil at $Re=10^6$
| Panels | Original (s) | NFoil (s) | Speedup |
|---|---|---|---|
| 100 | 26.5 | 1.4 | 18.8x |
| 200 | 67.7 | 4.0 | 17.0x |
| 300 | 115.6 | 6.1 | 18.8x |
| 400 | 180.8 | 11.3 | 16.0x |
Both versions share the same algorithmic complexity of $\approx O(N^{1.35})$. The speedup comes entirely from eliminating Python/SciPy overhead via JIT compilation and dense array operations.
Results obtained after running both versions in the command line on a M1-Max MacBook Pro.

NFoil includes a full-featured GUI (gui.py) built with CustomTkinter:
.dat or .txt files (TE-to-TE, CCW/CW). Includes an "Unload" button to instantly revert to the parameterized NACA generator.taichi_fields.py), leveraging Metal/CUDA (and other) GPUs.python gui.py
mfoilThe #1 bottleneck in the original code was SciPy sparse matrix overhead inside the coupled Newton solver:
build_glob_sys: Replaced scipy.sparse.dok_matrix allocation for R_U and R_x with dense np.zeros arrays. This eliminated ~70% of total runtime that was spent in DOK indexing, _validate_indices, __setitem__, and COO conversion.
solve_glob: Replaced scipy.sparse.lil_matrix assembly + scipy.sparse.linalg.spsolve with dense np.zeros array + np.linalg.solve. Includes a LinAlgError fallback to np.linalg.lstsq for near-singular Jacobians at extreme operating conditions.
All core boundary-layer functions have been rewritten as @njit(cache=True, fastmath=True) kernels.
calc_ue_m (inviscid edge velocity sensitivity matrix) was rebuilt with parallelised Numba kernels:
- build_B_bulk: Vectorized source-panel influence coefficient assembly over all panels simultaneously, replacing an O($N^2$) Python loop.
- build_Csig_bulk: Vectorized wake source-influence assembly.
solve_glob catches np.linalg.LinAlgError and falls back to np.linalg.lstsq for near-singular Jacobians (common at very low Reynolds numbers or high angles of attack).taichi_fields.py computes the velocity and pressure fields on a background grid using a Taichi Lang, rendering the flow field in real-time using the available GPU.numpy
scipy
matplotlib
numba
customtkinter # for GUI only
taichi # optional, for GPU flow fields
import nfoil as nf
# Create and solve
N = nf.nfoil(naca='2412', npanel=200)
N.setoper(alpha=5, Re=1e6, Ma=0.3)
N.solve()
# Results
print(f"Cl = {N.post.cl:.4f}")
print(f"Cd = {N.post.cd:.6f}")
print(f"Cm = {N.post.cm:.4f}")
If you use or modify this tool, cite this work as:
MIT License — Copyright (C) 2026 Cayetano Martínez-Muriel.
Many thanks to Krzysztof J. Fidkowski for his work on mfoil, and to the XFOIL team for the original tool.
Thanks to the Google Antigravity team for the IDE.
$ claude mcp add NFoil \
-- python -m otcore.mcp_server <graph>