This little notebook compares viiflow and XFOIL runtimes for different panel densities of the S805 airfoil. It is not 100% fair, because
Note: These results were generated with a PC with a AMD Ryzen 3700 processor on a windows 10 64bit OS with numpy built with Intel MKL and the xfoil 6.99 binary version.
import os # For calling xfoil
'''
Numpy (with MKL in this case) might want to use multiple threads to do linalg.solve.
Solving 150x150->500x500 matrices with multiple cores it not super efficient,
especially if your processor uses a higher clock if only one core is used.
And even if it would be faster with multiple cores, it would not be fair to compare
these results with single-core using XFOIL.
'''
#os.environ["OMP_NUM_THREADS"] = "1"
os.environ["MKL_NUM_THREADS"] = "1"
# viiflow imports
import viiflow as vf
import viiflowtools.vf_tools as vft
import numpy as np
import time # For timing
# For plotting at the end
import matplotlib.pyplot as plt
%matplotlib inline
%config InlineBackend.figure_format = 'svg'
import matplotlib
NVEC = np.arange(100,500,10) # Panel densities to compare
run_xfoil = True
# AOA Sweep
AOA0 = -5
AOAE = 16
DAOA = .5
RE = 1e6 # Reynolds Number
maxiter = 50 # maximum iterations for both methods
FOIL = "S805b.dat"
# Container for results
elapsedXF=[]
elapsedVF=[]
for N in NVEC:
if run_xfoil:
## Build correct file with N panels by XFOIL, compare both solvers with this file
# Make XFOIL command
com = "load %s\nPPAR\nN %u\n\n\nsave tmpfoil.dat\ny\n"%(FOIL,N)
# Save Xfoil Command
with open('xfcom.inp', 'w') as f:
print(com,file=f)
f.close()
# Run XFOIL
os.system("xfoil < xfcom.inp > xf.out")
## XFOIL
# Make XFOIL command
com = "load %s\nPLOP\nG F\n\nOPER\nv %u\nITER %u\nASEQ %f %f %f\n\nquit\n"%('tmpfoil.dat',RE,maxiter,AOA0,AOAE,DAOA)
#com = "load %s\nOPER\nv %u\nITER %u\nASEQ %f %f %f\n\nquit\n"%('tmpfoil.dat',RE,maxiter,AOA0,AOA0,DAOA)
# Save Xfoil Command
with open('xfcom.inp', 'w') as f:
print(com,file=f)
f.close()
time.sleep(.1)
# Run XFOIL
t = time.time()
os.system("xfoil < xfcom.inp > xf.out")
elapsedXF.append(time.time() - t)
# Check for convergence
f = open("xf.out", "r")
lines = f.readlines()
f.close()
time.sleep(.1)
xf_unconverged=0
for line in lines:
if line.startswith(" VISCAL: Convergence failed"):
xf_unconverged+=1
else:
elapsedXF.append(0.0)
xf_unconverged = 0
## viiflow
s = vf.setup(Re=RE,Ma=0.0,Ncrit=9.0,Alpha=AOA0)
s.Silent = True # Do not output residual/iterations internally
s.Itermax = maxiter
#s.IntermittencyGrowthRate = 1000
#s.Curvature = True
t = time.time()
# Set-up and initialize based on inviscid panel solution
# This calculates panel operator
if run_xfoil:
airfoil = vft.read_selig('tmpfoil.dat')
else:
airfoil = vft.repanel(vft.read_selig('S805b.dat'),N)
[p,bl,x] = vf.init(airfoil,s)
#vf.set_forced_transition(bl,p,[0.5],[0.5])
vf_unconverged = 0
for alpha in np.arange(AOA0,AOAE+DAOA,DAOA):
# Set current alpha and set res/grad to None to tell viiflow that they are not valid
s.Alpha = alpha
res = None
grad = None
# Run viiflow
[x,flag,res,_,_] = vf.iter(x,bl,p,s,res,grad)
# Print if not converged
if flag<=0:
#print('Not converged at AL: %f' % alpha)
vf_unconverged+=1
elapsedVF.append(time.time() - t)
time.sleep(.1)
# Print comparison
print("N: %u XF: %5.5ss (%u failed) VF:%5.5ss (%u failed)"%(N,elapsedXF[-1],xf_unconverged,elapsedVF[-1],vf_unconverged))
N: 100 XF: 0.580s (1 failed) VF:0.749s (1 failed) N: 110 XF: 0.709s (1 failed) VF:0.780s (0 failed) N: 120 XF: 0.890s (2 failed) VF:0.893s (0 failed) N: 130 XF: 1.244s (3 failed) VF:0.980s (0 failed) N: 140 XF: 0.971s (0 failed) VF:1.146s (1 failed) N: 150 XF: 1.413s (2 failed) VF:1.269s (1 failed) N: 160 XF: 1.376s (0 failed) VF:1.439s (0 failed) N: 170 XF: 1.800s (1 failed) VF:1.494s (0 failed) N: 180 XF: 1.792s (0 failed) VF:1.813s (1 failed) N: 190 XF: 2.267s (1 failed) VF:1.821s (0 failed) N: 200 XF: 3.170s (2 failed) VF:2.035s (0 failed) N: 210 XF: 3.081s (1 failed) VF:2.207s (0 failed) N: 220 XF: 3.459s (1 failed) VF:2.436s (0 failed) N: 230 XF: 4.624s (2 failed) VF:2.572s (0 failed) N: 240 XF: 3.813s (0 failed) VF:2.823s (0 failed) N: 250 XF: 4.753s (1 failed) VF:2.986s (0 failed) N: 260 XF: 6.187s (2 failed) VF:3.204s (0 failed) N: 270 XF: 5.070s (0 failed) VF:3.574s (0 failed) N: 280 XF: 5.945s (0 failed) VF:3.720s (0 failed) N: 290 XF: 8.080s (2 failed) VF:4.176s (1 failed) N: 300 XF: 9.002s (2 failed) VF:4.280s (0 failed) N: 310 XF: 7.980s (0 failed) VF:4.759s (0 failed) N: 320 XF: 8.617s (0 failed) VF:5.002s (0 failed) N: 330 XF: 10.19s (1 failed) VF:5.452s (0 failed) N: 340 XF: 11.86s (1 failed) VF:6.020s (0 failed) N: 350 XF: 17.25s (2 failed) VF:6.231s (0 failed) N: 360 XF: 16.20s (1 failed) VF:6.331s (0 failed) N: 370 XF: 15.59s (2 failed) VF:6.776s (0 failed) N: 380 XF: 15.55s (1 failed) VF:7.256s (0 failed) N: 390 XF: 15.89s (0 failed) VF:7.542s (0 failed) N: 400 XF: 18.86s (1 failed) VF:8.018s (0 failed) N: 410 XF: 18.86s (1 failed) VF:8.378s (0 failed) N: 420 XF: 17.89s (0 failed) VF:9.022s (0 failed) N: 430 XF: 17.36s (0 failed) VF:9.173s (0 failed) N: 440 XF: 19.21s (0 failed) VF:9.671s (0 failed) N: 450 XF: 21.50s (1 failed) VF:10.19s (0 failed) N: 460 XF: 20.68s (0 failed) VF:10.93s (0 failed) N: 470 XF: 21.58s (0 failed) VF:11.21s (0 failed) N: 480 XF: 42.87s (5 failed) VF:12.28s (0 failed) N: 490 XF: 36.84s (3 failed) VF:12.26s (0 failed)
matplotlib.rcParams['figure.figsize'] = [11, 6] # Make plots bigger than default
plt.plot(NVEC[0:len(elapsedVF)],elapsedVF,'-o')
plt.plot(NVEC[0:len(elapsedXF)],elapsedXF,'-o')
plt.legend(["viiflow","xfoil"])
plt.xlabel("Panels")
plt.ylabel("Runtime [s]")
plt.grid(1)
plt.ylim([0,30])
plt.xlim([90,500]);
The runtime difference increases with increasing panel density. This is to be expected. XFOIL needs to solve a system of 3xNP linear equations at every Newton step, while viiflow only needs to solve a 1xNP system.