forked from jte0419/Panel_Methods
-
Notifications
You must be signed in to change notification settings - Fork 0
/
XFOIL.py
158 lines (120 loc) · 10.3 KB
/
XFOIL.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# FUNCTION - CALL XFOIL AND GET AIRFOIL DATA
# Written by: JoshTheEngineer
# YouTube : www.youtube.com/joshtheengineer
# Website : www.joshtheengineer.com
# Started : 02/17/20 - Transferred from MATLAB to Python
# - Works as expected
#
# PUROSE
# - Create or load airfoil based on flagAirfoil
# - Save and read airfoil coordinates
# - Save and read airfoil pressure coefficient
# - Save and read airfoil lift, drag, and moment coefficients
#
# INPUTS
# - NACA : Four-digit NACA airfoil designation
# - PPAR : Paneling variables used in XFOIL PPAR menu
# - AoA : Angle of attack [deg]
# - flagAirfoil : Flag for loading/creating airfoil
#
# OUTPUTS
# - xFoilResults : Array containing all results
import os # For calling the XFoil executable
import numpy as np # For number/math stuff
from tkinter import Tk # For input file dialog box
from tkinter.filedialog import askopenfilename # For input file dialog box
import ntpath # For file path splitting
def XFOIL(NACA,PPAR,AoA,flagAirfoil):
# %% CALL XFOIL FROM MATLAB
xFoilResults = list(range(9)) # Initialize results array
if (flagAirfoil[0] == 1): # If the user wants XFOIL to create a NACA airfoil
airfoilName = NACA # Set the airfoilName to the input NACA airfoil
xFoilResults[0] = airfoilName # Send the airfoil name back from this function
elif (flagAirfoil[1] == 1): # If the user wants to load a DAT file airfoil
root = Tk() # Create GUI for open file dialog box
ftypes = [('dat file',"*.dat")] # File types allowed to be loaded
ttl = "Select Airfoil File" # Title of the dialog box GUI
dir1 = '/Airfoil_DAT_Selig/' # Initial directory of the dialog box GUI
root.withdraw() # Needed for closing the Tk window later
root.update() # Needed for closing the Tk window later
root.fileName = askopenfilename(filetypes = ftypes, # User input of airfoil file to load
initialdir = dir1,
title = ttl)
root.destroy() # Destroy the Tk window
head, tail = ntpath.split(root.fileName) # https://stackoverflow.com/questions/8384737/extract-file-name-from-path-no-matter-what-the-os-path-format
airfoilName = tail[0:len(tail)-4] # Retain only airfoil name, not extension
xFoilResults[0] = airfoilName # Send the airfoil name back from this function
# Save-to file names
saveFlnm = 'Save_' + airfoilName + '.txt' # Airfoil coordinates save-to file
saveFlnmCp = 'Save_' + airfoilName + '_Cp.txt' # Airfoil Cp save-to file
saveFlnmPol = 'Save_' + airfoilName + '_Pol.txt' # Airfoil polar save-to file
# Delete files if they exist
if os.path.exists(saveFlnm): # If the airofil coordinates file exists
os.remove(saveFlnm) # Delete the file
if os.path.exists(saveFlnmCp): # If the airfoil Cp file exists
os.remove(saveFlnmCp) # Delete the file
if os.path.exists(saveFlnmPol): # If the airfoil polar file exists
os.remove(saveFlnmPol) # Delete the file
# Create the airfoil
fid = open('xfoil_input.inp',"w") # Open a file for writing the XFoil commands to
if (flagAirfoil[0] == 1): # If the user wants to let XFoil create a NACA airfoil
fid.write("NACA " + NACA + "\n") # Create the NACA airfoil
elif (flagAirfoil[1] == 1): # If the user wants to load an external airfoil file
fid.write("LOAD " + "./Airfoil_DAT_Selig/" + tail + "\n") # Load the airfoil file
fid.write("PPAR\n") # Enter the PPAR (paneling) menu
fid.write("N " + PPAR[0] + "\n") # Define "Number of panel nodes"
fid.write("P " + PPAR[1] + "\n") # Define "Panel bunching paramter"
fid.write("T " + PPAR[2] + "\n") # Define "TE/LE panel density ratios"
fid.write("R " + PPAR[3] + "\n") # Define "Refined area/LE panel density ratio"
fid.write("XT " + PPAR[4] + "\n") # Define "Top side refined area x/c limits"
fid.write("XB " + PPAR[5] + "\n") # Define "Bottom side refined area x/c limits"
fid.write("\n") # Apply all changes
fid.write("\n") # Back out to XFOIL menu
# Save the airfoil data points
fid.write("PSAV " + saveFlnm + "\n") # Save the airfoil coordinate file
# Get Cp and polar data
fid.write("OPER\n") # Enter OPER menu
fid.write("Pacc 1 \n") # Begin polar accumulation
fid.write("\n\n") # Don't enter save or dump file names
fid.write("Alfa " + str(AoA) + "\n") # Set angle of attack
fid.write("CPWR " + saveFlnmCp + "\n") # Write the Cp file
fid.write("PWRT\n") # Save the polar data
fid.write(saveFlnmPol + "\n") # Save polar data to this file
if os.path.exists(saveFlnmPol): # If saveFlnmPol already exists
fid.write("y \n") # Overwrite existing file
fid.close() # Close the input file
# Run the XFoil calling command
os.system("xfoil.exe < xfoil_input.inp") # Run XFoil with the input file just created
# Delete file after running
if os.path.exists('xfoil_input.inp'): # If the input file exists
os.remove('xfoil_input.inp') # Delete the file since we don't need it anymore
# %% READ CP DATA
# Load the data from the text file
dataBufferCp = np.loadtxt(saveFlnmCp, skiprows=3) # Read the X, Y, and Cp data from data file
# Extract data from the loaded dataBuffer array
xFoilResults[1] = dataBufferCp[:,0] # X-data points
xFoilResults[2] = dataBufferCp[:,1] # Y-data points
xFoilResults[3] = dataBufferCp[:,2] # Cp data
# Delete file after loading
if os.path.exists(saveFlnmCp): # If filename exists
os.remove(saveFlnmCp) # Delete the file
# %% READ AIRFOIL COORDINATES
# Load the data from the text file
dataBuffer = np.loadtxt(saveFlnm, skiprows=0) # Read the XB and YB data from the data file
# Extract data from the loaded dataBuffer array
xFoilResults[4] = dataBuffer[:,0] # Boundary point X-coordinate
xFoilResults[5] = dataBuffer[:,1] # Boundary point Y-coordinate
# Delete file after loading
if os.path.exists(saveFlnm): # If filename exists
os.remove(saveFlnm) # Delete the file
# %% READ POLAR DATA
# Load the data from the text file
dataBufferPol = np.loadtxt(saveFlnmPol, skiprows=12) # Read the CL, CD, and CM data from the data file
# Extract data from the loaded dataBuffer array
xFoilResults[6] = dataBufferPol[1] # Lift coefficient
xFoilResults[7] = dataBufferPol[2] # Drag coefficient
xFoilResults[8] = dataBufferPol[4] # Moment coefficient
# Delete file after loading
if os.path.exists(saveFlnmPol): # If filename exists
os.remove(saveFlnmPol) # Delete the file
return xFoilResults # Return the important information from this function