# Source code for sharpy.aero.utils.airfoilpolars

```import numpy as np
# import sharpy.utils.algebra as algebra
from scipy.interpolate import interp1d

[docs]class Polar:
"""
Airfoil polar object
"""

def __init__(self):

self.table = None
self.aoa_cl0_deg = None

[docs]    def initialise(self, table):
"""
Initialise polar

Args:
table (np.ndarray): 4-column array containing ``aoa`` (rad), ``cl``, ``cd`` and ``cm``

"""
# Store the table
if (np.diff(table[:, 0]) > 0.).all():
self.table = table[~np.isnan(table).any(axis=1), :]
else:
raise RuntimeError("ERROR: angles of attack not ordered")

# Look for aoa where CL=0
npoints = self.table.shape[0]
matches = []
for ipoint in range(npoints - 1):
if self.table[ipoint, 1] == 0.:
matches.append(self.table[ipoint, 0])
elif (self.table[ipoint, 1] < 0. and self.table[ipoint + 1, 1] > 0):
# elif ((self.table[ipoint, 1] < 0. and self.table[ipoint + 1, 1] > 0) or
#       (self.table[ipoint, 1] > 0. and self.table[ipoint + 1, 1] < 0)):
if (self.table[ipoint, 0] <= 0.):
matches.append(np.interp(0,
self.table[ipoint:ipoint+2, 1],
self.table[ipoint:ipoint+2, 0]))
# else:
#     print("WARNING: Be careful negative camber airfoil not supported")

iaoacl0 = 0
aux = np.abs(matches[0])
for imin in range(len(matches)):
if np.abs(matches[imin]) < aux:
aux = np.abs(matches[imin])
iaoacl0 = imin
self.aoa_cl0_deg = matches[iaoacl0]

self.cl_interp = interp1d(self.table[:, 0], self.table[:, 1])
self.cd_interp = interp1d(self.table[:, 0], self.table[:, 2])
self.cm_interp = interp1d(self.table[:, 0], self.table[:, 3])

def get_coefs(self, aoa_deg):

cl = self.cl_interp(aoa_deg)
cd = self.cd_interp(aoa_deg)
cm = self.cm_interp(aoa_deg)

return cl, cd, cm

def get_aoa_deg_from_cl_2pi(self, cl):

def redefine_aoa(self, new_aoa):

naoa = len(new_aoa)
# Generate the same polar interpolated at different angles of attack
# by linear interpolation
table = np.zeros((naoa, 4))
table[:, 0] = new_aoa
for icol in range(1, 4):
table[:, icol] = np.interp(table[:, 0],
self.table[:, 0],
self.table[:, icol])

new_polar = Polar()
new_polar.initialise(table)
return new_polar

def get_cdcm_from_cl(self, cl):
# Computes the cd and cm from cl
# It provides the first match after (or before) the AOA of CL=0

cl_max = np.max(self.table[:,1])
cl_min = np.min(self.table[:,1])

if cl_max < cl or cl_min > cl:
print(("cl = %.2f out of range, forces at this point will not be corrected" % cl))
cd = 0.
cm = 0.
else:
if cl == 0.:
cl_new, cd, cm = self.get_coefs(self.aoa_cl0_deg)
elif cl > 0.:
dist = np.abs(self.table[:,0] - self.aoa_cl0_deg)
min_dist = np.min(dist)
i = np.where(dist == min_dist)[0][0]
while self.table[i, 1] < cl:
i += 1
cd = np.interp(cl, self.table[i-1:i+1, 1], self.table[i-1:i+1, 2])
cm = np.interp(cl, self.table[i-1:i+1, 1], self.table[i-1:i+1, 3])
else:
dist = np.abs(self.table[:,0] - self.aoa_cl0_deg)
min_dist = np.min(dist)
i = np.where(dist == min_dist)[0][0]
while self.table[i, 1] > cl:
i -= 1
cd = np.interp(cl, self.table[i:i+2, 1], self.table[i:i+2, 2])
cm = np.interp(cl, self.table[i:i+2, 1], self.table[i:i+2, 3])

return cd, cm

def interpolate(polar1, polar2, coef=0.5):

all_aoa = np.sort(np.concatenate((polar1.table[:, 0], polar2.table[:, 0]),))

different_aoa = []
different_aoa.append(all_aoa[0])
for iaoa in range(1, len(all_aoa)):
if not all_aoa[iaoa] == different_aoa[-1]:
different_aoa.append(all_aoa[iaoa])

new_polar1 = polar1.redefine_aoa(different_aoa)
new_polar2 = polar2.redefine_aoa(different_aoa)

table = (1. - coef)*new_polar1.table + coef*new_polar2.table

new_polar = Polar()
new_polar.initialise(table)
return new_polar
```