The ground (in case one speaks about the ground effect) is not a free surface, so we can safely use mirror assumptions.
To use a ground, set setup(Mirror=1) and be wary of your definition of aoa and airfoil position.
The ground is a ray through the origin in the direction of the free flow, and you can put the airfoil above or below it, either way the flow is mirrored.
Regarding validation: I chose the data in [1] for an airfoil intended for race cars and set Ncrit to a larger value to make it coincide with the measured data better.
import viiflow as vf
import viiflowtools.vf_tools as vft
import viiflowtools.vf_plots as vfp
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
%matplotlib inline
%config InlineBackend.figure_format = 'svg'
# Read Airfoil Data
N = 180
AF = vft.repanel(vft.read_selig("Tyrell026m.csv")[:,::-1],N)
ExpData = np.genfromtxt("TyrellPressure1deg.csv",delimiter=";")
colors = ["tab:blue","tab:orange","tab:green","tab:red","tab:purple","tab:pink","tab:olive"]
results = {} # Dictionary of results
heights = np.asarray([np.inf,.671, .313, .179, .134,.090, .067])-np.min(AF[1,:])
AOARange = [0.0]
for h in heights:
# Settings
ncrit = 12
Mach = .087
s = vf.setup(Re=4.6e5,Ma=Mach,Ncrit=ncrit,Alpha=AOARange[0],IterateWakes=False,Silent=True,Mirror=1 if np.isfinite(h) else 0)
results[h] = {} # Sub-Dictionary of results
results[h]["AOA"] = []
results[h]["CL"] = []
results[h]["CD"] = []
results[h]["CP"] = []
# Go over AOA range
faults = 0
init = True
for alpha in AOARange:
# Set current alpha and set res/grad to None to tell viiflow that they are not valid
s.Alpha = alpha
res = None
grad = None
# Set-up and initialize based on inviscid panel solution
# This calculates panel operator
AFC = AF.copy()
if np.isfinite(h):
AFC[1,:] += np.cos(alpha*np.pi/180)*h # Move TE wrt free flow
AFC[0,:] += -np.sin(alpha*np.pi/180)*h # Move TE wrt free flow
[p,bl,x] = vf.init([AFC],s)
# Run viiflow
[x,flag,res,grad,_] = vf.iter(x,bl,p,s,res,grad)
# If converged add to cl/cd vectors (could check flag as well, but this allows custom tolerance
# to use the results anyways)
if flag:
results[h]["AOA"].append(alpha)
results[h]["CL"].append(p.CL)
results[h]["CD"].append(bl[0].CD)
results[h]["CP"].append(1.0-np.power(p.gamma_viscid,2.0))
faults = 0
else:
faults+=1
init = True
# Skip current polar if 4 unconverged results in a row
if faults>3:
print("Exiting RE %u polar calculation at AOA %f°"%(RE,alpha))
break
matplotlib.rcParams['figure.figsize'] = [12, 6]
fig,ax = plt.subplots(1,1)
for cnt in range(len(heights)):
h = heights[cnt]
ax.plot(AFC[0,:],-results[h]["CP"][0][0:N],color = colors[cnt],label="h=%3.3g"%(heights[cnt]+np.min(AF[1,:])))
ax.plot((ExpData[:,2*cnt]-.05)/.95,-ExpData[:,2*cnt+1],'.',color = colors[cnt])
ax.grid(1)
ax.set_ylim([-1,5])
cnt+=1
ax.legend()
[6] Zerihan, Jonathan. An investigation into the aerodynamics of wings in ground effect. Diss. University of Southampton, 2001.