Delete creator.py

Commit
a5e80fc53745e2a8696c3f0ef588979b282ef216
Author
Blendoit <51464356+Blendoit@users.noreply.github.com>
Author date
Committer
GitHub <noreply@github.com>
Committer date
creator.py
index 59c84364..00000000 100644..000000
@@ -1,382 +0,0 @@
1 Removed: # This file is part of Marius Peter's airfoil analysis package (this program).
2 Removed: #
3 Removed: # This program is free software: you can redistribute it and/or modify
4 Removed: # it under the terms of the GNU General Public License as published by
5 Removed: # the Free Software Foundation, either version 3 of the License, or
6 Removed: # (at your option) any later version.
7 Removed: #
8 Removed: # This program is distributed in the hope that it will be useful,
9 Removed: # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 Removed: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 Removed: # GNU General Public License for more details.
12 Removed: #
13 Removed: # You should have received a copy of the GNU General Public License
14 Removed: # along with this program. If not, see <https://www.gnu.org/licenses/>.
15 Removed:
16 Removed: import sys
17 Removed: import os.path
18 Removed: import numpy as np
19 Removed: from math import sin, cos, tan, atan, sqrt, ceil
20 Removed: import bisect as bi
21 Removed: import matplotlib.pyplot as plt
22 Removed: import matplotlib as mpl
23 Removed: from mpl_toolkits.mplot3d import Axes3D
24 Removed:
25 Removed:
26 Removed: # This variable is required for main.py constant wing dimensions
27 Removed: # to be passed to inheriting classes (Airfoil, Spar, Stringer, Rib).
28 Removed: # This way, we don't have to redeclare our coordinates as parameters for
29 Removed: # our spars, stringers and ribs. This makes for more elegant code.
30 Removed: global parent
31 Removed:
32 Removed:
33 Removed: class Coordinates:
34 Removed: """
35 Removed: All classes need coordinates relative to the chord & semi-span.
36 Removed: So, they all inherit from this class.
37 Removed: """
38 Removed:
39 Removed: def __init__(self, chord, semi_span):
40 Removed: # Global dimensions
41 Removed: self.chord = chord
42 Removed: self.semi_span = semi_span
43 Removed: # Upper coordinates
44 Removed: self.x_u = []
45 Removed: self.y_u = []
46 Removed: # Lower coordinates
47 Removed: self.x_l = []
48 Removed: self.y_l = []
49 Removed: # Upper coordinates
50 Removed: self.x_u = []
51 Removed: self.y_u = []
52 Removed: # Lower coordinates
53 Removed: self.x_l = []
54 Removed: self.y_l = []
55 Removed: # Coordinates x_u, y_u, x_l, y_l packed in single list
56 Removed: self.coordinates = []
57 Removed: global parent
58 Removed: parent = self
59 Removed:
60 Removed: def create(self, chord, semi_span):
61 Removed: self.chord = chord
62 Removed: self.semi_span = semi_span
63 Removed:
64 Removed: chord = self.chord
65 Removed: semi_span = self.semi_span
66 Removed:
67 Removed:
68 Removed: class Airfoil(Coordinates):
69 Removed: """This class enables the creation of a NACA airfoil."""
70 Removed:
71 Removed: def __init__(self):
72 Removed: global parent
73 Removed: # Run 'Coordinates' super class init method with same chord & 1/2 span.
74 Removed: super().__init__(parent.chord, parent.semi_span)
75 Removed: # NACA number
76 Removed: self.naca_num = int()
77 Removed: # Mean camber line
78 Removed: self.x_c = []
79 Removed: self.y_c = []
80 Removed: # Thickness
81 Removed: self.y_t = []
82 Removed: # dy_c / d_x
83 Removed: self.dy_c = []
84 Removed: # Theta
85 Removed: self.theta = []
86 Removed:
87 Removed: def naca(self, naca_num):
88 Removed: """
89 Removed: This function generates geometry for our chosen NACA airfoil shape.\
90 Removed: The nested functions perform the required steps to generate geometry,\
91 Removed: and can be called to solve the geometry y-coordinate for any 'x' input.\
92 Removed: Equation coefficients were retrieved from Wikipedia.org.
93 Removed:
94 Removed: Parameters:
95 Removed: naca_num: 4-digit NACA wing
96 Removed: chord: wing chord length, in any unit
97 Removed:
98 Removed: Return:
99 Removed: None
100 Removed: """
101 Removed:
102 Removed: # Variables extracted from 'naca_num' argument passed to the function
103 Removed: self.naca_num = naca_num
104 Removed: m = int(str(naca_num)[0]) / 100
105 Removed: p = int(str(naca_num)[1]) / 10
106 Removed: t = int(str(naca_num)[2:]) / 100
107 Removed: # Chord length. Should be higher than 10.
108 Removed: if self.chord < 10:
109 Removed: self.chord = 10
110 Removed: # x-coordinate of maximum camber
111 Removed: p_c = p * self.chord
112 Removed:
113 Removed: def get_camber(x):
114 Removed: """
115 Removed: Returns 1 camber y-coordinate from 1 'x' along the airfoil chord.
116 Removed: """
117 Removed: x_c = x
118 Removed: y_c = float()
119 Removed: if 0 <= x < p_c:
120 Removed: y_c = (m / (p ** 2)) * (2 * p
121 Removed: * (x / self.chord)
122 Removed: - (x / self.chord) ** 2)
123 Removed: elif p_c <= x <= self.chord:
124 Removed: y_c = (m / ((1 - p) ** 2)) * ((1 - 2 * p)
125 Removed: + 2 * p * (x / self.chord)
126 Removed: - (x / self.chord) ** 2)
127 Removed: else:
128 Removed: print('x-coordinate for camber is out of bounds. '
129 Removed: 'Check that 0 < x <= chord.')
130 Removed: return (x_c, y_c * self.chord)
131 Removed:
132 Removed: def get_thickness(x):
133 Removed: """
134 Removed: Returns thickness from 1 'x' along the airfoil chord.
135 Removed: """
136 Removed: y_t = float()
137 Removed: if 0 <= x <= self.chord:
138 Removed: y_t = 5 * t * self.chord * (0.2969 * sqrt(x / self.chord)
139 Removed: - 0.1260 * (x / self.chord)
140 Removed: - 0.3516 * (x / self.chord) ** 2
141 Removed: + 0.2843 * (x / self.chord) ** 3
142 Removed: - 0.1015 * (x / self.chord) ** 4)
143 Removed: else:
144 Removed: print('x-coordinate for thickness is out of bounds. '
145 Removed: 'Check that 0 < x <= chord.')
146 Removed: return y_t
147 Removed:
148 Removed: def get_dy_c(x):
149 Removed: """
150 Removed: Returns dy_c/dx from 1 'x' along the airfoil chord.
151 Removed: """
152 Removed: dy_c = float()
153 Removed: if 0 <= x < p_c:
154 Removed: dy_c = ((2 * m)/p ** 2) * (p - x / self.chord)
155 Removed: elif p_c <= x <= self.chord:
156 Removed: dy_c = (2 * m) / ((1 - p) ** 2) * (p - x / self.chord)
157 Removed: return dy_c
158 Removed:
159 Removed: def get_theta(dy_c):
160 Removed: theta = atan(dy_c)
161 Removed: return theta
162 Removed:
163 Removed: def get_upper_coordinates(x):
164 Removed: x_u = float()
165 Removed: y_u = float()
166 Removed: if 0 <= x < self.chord:
167 Removed: x_u = x - self.y_t[x] * sin(self.theta[x])
168 Removed: y_u = self.y_c[x] + self.y_t[x] * cos(self.theta[x])
169 Removed: elif x == self.chord:
170 Removed: x_u = x - self.y_t[x] * sin(self.theta[x])
171 Removed: y_u = 0 # Make upper curve finish at y = 0
172 Removed: return(x_u, y_u)
173 Removed:
174 Removed: def get_lower_coordinates(x):
175 Removed: x_l = float()
176 Removed: y_l = float()
177 Removed: if 0 <= x < self.chord:
178 Removed: x_l = (x + self.y_t[x] * sin(self.theta[x]))
179 Removed: y_l = (self.y_c[x] - self.y_t[x] * cos(self.theta[x]))
180 Removed: elif x == self.chord:
181 Removed: x_l = (x + self.y_t[x] * sin(self.theta[x]))
182 Removed: y_l = 0 # Make lower curve finish at y = 0
183 Removed: return(x_l, y_l)
184 Removed:
185 Removed: # Generate all our wing geometries from previous sub-functions
186 Removed: for x in range(0, self.chord + 1):
187 Removed: self.x_c.append(get_camber(x)[0])
188 Removed: self.y_c.append(get_camber(x)[1])
189 Removed: self.y_t.append(get_thickness(x))
190 Removed: self.dy_c.append(get_dy_c(x))
191 Removed: self.theta.append(get_theta(self.dy_c[x]))
192 Removed: self.x_u.append(get_upper_coordinates(x)[0])
193 Removed: self.y_u.append(get_upper_coordinates(x)[1])
194 Removed: self.x_l.append(get_lower_coordinates(x)[0])
195 Removed: self.y_l.append(get_lower_coordinates(x)[1])
196 Removed:
197 Removed: self.coordinates.append(self.x_u)
198 Removed: self.coordinates.append(self.y_u)
199 Removed: self.coordinates.append(self.x_l)
200 Removed: self.coordinates.append(self.x_l)
201 Removed:
202 Removed: return None
203 Removed:
204 Removed: def print_geometry(self, round):
205 Removed: """
206 Removed: Print all the declared geometry to the terminal.
207 Removed: """
208 Removed: # Print all our basic geometry, useful for debugging
209 Removed: print('Chord length')
210 Removed: print(self.chord)
211 Removed: print('x_c the x-coordinates of the mean camber line')
212 Removed: print(np.around(self.x_c, round))
213 Removed: print('y_c the y-coordinates of the mean camber line')
214 Removed: print(np.around(self.y_c, round))
215 Removed: print('y_t the y-coordinates of the airfoil thickness')
216 Removed: print(np.around(self.y_t, round))
217 Removed: print('dy_c the derivative of y_c with respect to dx')
218 Removed: print(np.around(self.dy_c, round))
219 Removed: print('theta is like an angle, idk')
220 Removed: print(np.around(self.theta, round))
221 Removed: print('x_u the x-coordinates of the upper airfoil surface')
222 Removed: print(np.around(self.x_u, round))
223 Removed: print('y_u the y-coordinates of the upper airfoil surface')
224 Removed: print(np.around(self.y_u, round))
225 Removed: print('x_l the x-coordinates of the lower airfoil surface')
226 Removed: print(np.around(self.x_l, round))
227 Removed: print('y_l the y-coordinates of lower airfoil surface')
228 Removed: print(np.around(self.y_l, round))
229 Removed: return None
230 Removed:
231 Removed: def save_values(self, airfoil_number, save_dir_path):
232 Removed: """
233 Removed: Save all the declared geometry to save_dir_path (must be full path).
234 Removed: """
235 Removed: file_name = 'airfoil_%s' % airfoil_number
236 Removed: full_path = os.path.join(save_dir_path, file_name+'.txt')
237 Removed: file = open(full_path, 'w')
238 Removed: sys.stdout = file
239 Removed: self.print_geometry(4)
240 Removed: return None
241 Removed:
242 Removed:
243 Removed: class Spar(Coordinates):
244 Removed: """Contains a single spar's location and material."""
245 Removed: global parent
246 Removed:
247 Removed: def __init__(self):
248 Removed: super().__init__(parent.chord, parent.semi_span)
249 Removed: # Spar material
250 Removed: self.spar_material = []
251 Removed:
252 Removed: def add_spar(self, coordinates, material, spar_x):
253 Removed: """
254 Removed: Add a single spar at the % chord location given to function.
255 Removed:
256 Removed: Parameters:
257 Removed: coordinates: provided by Airfoil.coordinates[x_u, y_u, x_l, y_l].
258 Removed: material: spar's material. Assumes homogeneous material.
259 Removed: spar_x: spar's location as a % of total chord length.
260 Removed:
261 Removed: Return:
262 Removed: None
263 Removed: """
264 Removed: # Airfoil surface coordinates
265 Removed: # unpacked from 'coordinates' (list of lists in 'Airfoil').
266 Removed: x_u = coordinates[0]
267 Removed: y_u = coordinates[1]
268 Removed: x_l = coordinates[2]
269 Removed: y_l = coordinates[3]
270 Removed: # Scaled spar location with regards to chord
271 Removed: loc = spar_x * self.chord
272 Removed: # bisect_left: returns index of first value in x_u > loc.
273 Removed: # This ensures that the spar coordinates intersect with airfoil surface.
274 Removed: spar_x_u = bi.bisect_left(x_u, loc) # index of spar's x_u
275 Removed: spar_x_l = bi.bisect_left(x_l, loc) # index of spar's x_l
276 Removed: # These x and y coordinates are assigned to the spar, NOT airfoil.
277 Removed: self.x_u.append(x_u[spar_x_u])
278 Removed: self.y_u.append(y_u[spar_x_u])
279 Removed: self.x_l.append(x_l[spar_x_l])
280 Removed: self.y_l.append(y_l[spar_x_l])
281 Removed: self.spar_material = material
282 Removed: return None
283 Removed:
284 Removed:
285 Removed: class Stringer():
286 Removed: """Contains the coordinates of stringer(s) location and material."""
287 Removed:
288 Removed: def __init__(self):
289 Removed: # Stringer attributes
290 Removed: self.stringer_x_u = []
291 Removed: self.stringer_y_u = []
292 Removed: self.stringer_x_l = []
293 Removed: self.stringer_y_l = []
294 Removed: self.stringer_mat = []
295 Removed:
296 Removed: def add_stringers(self, material, *density):
297 Removed: """
298 Removed: Add stringers to the wing from their distribution density between spars.
299 Removed: First half of density[] concerns stringer distribution on
300 Removed:
301 Removed: Parameters:
302 Removed: material: stringer material
303 Removed: *density:
304 Removed:
305 Removed: """
306 Removed:
307 Removed: # Find interval between leading edge and first upper stringer,
308 Removed: # from density parameter den_u_1.
309 Removed: interval = self.spar_x_u[0] / (den_u_1 * self.spar_x_u[0])
310 Removed: # initialise first self.stringer_x_u at first interval.
311 Removed: x = interval
312 Removed: # Add upper stringers until first spar.
313 Removed: while x < self.spar_x_u[0]:
314 Removed: # Index of the first value of self.x_u > x
315 Removed: x_u = bi.bisect_left(self.x_u, x)
316 Removed: self.stringer_x_u.append(self.x_u[x_u])
317 Removed: self.stringer_y_u.append(self.y_u[x_u])
318 Removed: x += interval
319 Removed:
320 Removed: # Find interval between leading edge and first lower stringer,
321 Removed: # from density parameter den_l_1.
322 Removed: interval = self.spar_x_u[0] / (den_l_1 * self.spar_x_u[0])
323 Removed: # initialise first self.stringer_x_l at first interval.
324 Removed: x = interval
325 Removed: # Add lower stringers until first spar.
326 Removed: while x < self.spar_x_l[0]:
327 Removed: # Index of the first value of self.x_l > x
328 Removed: x_u = bi.bisect_left(self.x_l, x)
329 Removed: self.stringer_x_l.append(self.x_l[x_u])
330 Removed: self.stringer_y_l.append(self.y_l[x_u])
331 Removed: x += interval
332 Removed: return None
333 Removed:
334 Removed:
335 Removed: def plot(airfoil, spar):
336 Removed: """This function plots the elements passed as arguments."""
337 Removed:
338 Removed: print('Plotting airfoil.')
339 Removed: # Plot chord
340 Removed: x_chord = [0, airfoil.chord]
341 Removed: y_chord = [0, 0]
342 Removed: plt.plot(x_chord, y_chord, linewidth='1')
343 Removed: # Plot mean camber line
344 Removed: plt.plot(airfoil.x_c, airfoil.y_c, '-.', color='r', linewidth='2',
345 Removed: label='mean camber line')
346 Removed: # Plot upper surface
347 Removed: plt.plot(airfoil.x_u, airfoil.y_u, '', color='b', linewidth='1')
348 Removed: # Plot lower surface
349 Removed: plt.plot(airfoil.x_l, airfoil.y_l, '', color='b', linewidth='1')
350 Removed: # Plot spars
351 Removed: try:
352 Removed: for _ in range(0, len(spar.x_u)):
353 Removed: x = (spar.spar_x_u[_], spar.spar_x_l[_])
354 Removed: y = (spar.spar_y_u[_], spar.spar_y_l[_])
355 Removed: plt.plot(x, y, '.-', color='b', label='spar')
356 Removed: plt.legend()
357 Removed: except:
358 Removed: print('Did plot spars. Were they added?')
359 Removed: # Plot stringers
360 Removed: # if len(self.spar_x) != 0:
361 Removed: # for _ in range(0, len(self.stringer_x)):
362 Removed: # x = (self.stringer_x[_], self.stringer_x[_])
363 Removed: # y = (self.stringer_y_u[_], self.stringer_y_l[_])
364 Removed: # plt.scatter(x, y, color='y', linewidth='1',
365 Removed: # else:
366 Removed: # print('Unable to plot stringers. Were they created?')
367 Removed: # Graph formatting
368 Removed: plt.gcf().set_size_inches(9, 2.2)
369 Removed: plt.xlabel('X axis')
370 Removed: plt.ylabel('Y axis')
371 Removed: # plt.gcf().set_size_inches(self.chord, max(self.y_u) - min(self.y_l))
372 Removed: plt.grid(axis='both', linestyle=':', linewidth=1)
373 Removed: plt.show()
374 Removed: return None
375 Removed:
376 Removed:
377 Removed: def main():
378 Removed: return None
379 Removed:
380 Removed:
381 Removed: if __name__ == '__main__':
382 Removed: main()