*ARCHIVED* development moved to aircraft-studio.
module & class & function docstrings
Changed files
creator.py
@@ -12,8 +12,19 @@
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program. If not, see <https://www.gnu.org/licenses/>.
15
Added:
"""
16
Added:
The 'creator' module contains class definitions for coordinates
17
Added:
and various components we add to an airfoil (spars, stringers, and ribs.)
15
18
19
Added:
Classes:
20
Added:
Coordinates: always instantiated first, but never assigned to object.
21
Added:
Airfoil: inherits from Coordinates & automatically aware of airfoil size.
22
Added:
Spar: also inherits from Coordinates.
23
Added:
Stringer: also inherits from Coordinates.
16
24
25
Added:
Functions:
26
Added:
plot_geom(airfoil): generates a 2D plot of the airfoil & any components.
27
Added:
"""
17
28
import sys
18
29
import os.path
19
30
import numpy as np
@@ -30,19 +41,19 @@
30
41
31
42
32
43
class Coordinates:
33
Removed:
'''
44
Added:
"""
34
45
All airfoil components need the following:
35
46
36
47
Parameters:
37
Removed:
* Component material
38
Removed:
* Coordinates relative to the chord & semi-span
48
Added:
Component material
49
Added:
Coordinates relative to the chord & semi-span
39
50
40
51
Methods:
41
Removed:
* Print component coordinates
42
Removed:
* Save component coordinates to file specified in main.py
52
Added:
Print component coordinates
53
Added:
Save component coordinates to file specified in main.py
43
54
44
55
So, all component classes inherit from class Coordinates.
45
Removed:
'''
56
Added:
"""
46
57
47
58
def __init__(self, chord, semi_span):
48
59
# Global dimensions
@@ -65,11 +76,11 @@
65
76
return type(self).__name__
66
77
67
78
def info_print(self, round):
68
Removed:
'''
79
Added:
"""
69
80
Print all the component's coordinates to the terminal.
70
81
71
82
This function's output is piped to the 'save_coord' function below.
72
Removed:
'''
83
Added:
"""
73
84
name = ' CREATOR DATA '
74
85
num_of_dashes = len(name)
75
86
@@ -85,10 +96,9 @@
85
96
return None
86
97
87
98
def info_save(self, save_path, number):
88
Removed:
'''
99
Added:
"""
89
100
Save all the object's coordinates (must be full path).
90
Removed:
'''
91
Removed:
101
Added:
"""
92
102
file_name = '{}_{}.txt'.format(str(self).lower(), number)
93
103
full_path = os.path.join(save_path, file_name)
94
104
try:
@@ -105,8 +115,8 @@
105
115
106
116
107
117
class Airfoil(Coordinates):
108
Removed:
'''
109
Removed:
This class enables the creation of a single NACA airfoil.
118
Added:
"""
119
Added:
This class represents a single NACA airfoil.
110
120
111
121
Please note: the coordinates are saved as two lists
112
122
for the x- and z-coordinates. The coordinates start at
@@ -116,7 +126,7 @@
116
126
This method was chosen for easier future exports
117
127
to 3D CAD packages like SolidWorks, which can import such
118
128
geometry as coordinates written in a CSV file.
119
Removed:
'''
129
Added:
"""
120
130
121
131
def __init__(self):
122
132
global parent
@@ -129,7 +139,7 @@
129
139
self.z_c = []
130
140
131
141
def add_naca(self, naca_num):
132
Removed:
'''
142
Added:
"""
133
143
This function generates geometry for our chosen NACA airfoil shape.
134
144
The nested functions perform the required steps to generate geometry,
135
145
and can be called to solve the geometry y-coordinate for any 'x' input.
@@ -140,8 +150,7 @@
140
150
141
151
Return:
142
152
None
143
Removed:
'''
144
Removed:
153
Added:
"""
145
154
# Variables extracted from 'naca_num' argument passed to the function
146
155
self.naca_num = naca_num
147
156
m = int(str(naca_num)[0]) / 100
@@ -151,9 +160,9 @@
151
160
p_c = p * self.chord
152
161
153
162
def get_camber(x):
154
Removed:
'''
163
Added:
"""
155
164
Returns camber z-coordinate from 1 'x' along the airfoil chord.
156
Removed:
'''
165
Added:
"""
157
166
z_c = float()
158
167
if 0 <= x < p_c:
159
168
z_c = (m / (p ** 2)) * (2 * p * (x / self.chord)
@@ -165,8 +174,7 @@
165
174
return (z_c * self.chord)
166
175
167
176
def get_thickness(x):
168
Removed:
'''Returns thickness from 1 'x' along the airfoil chord.'''
169
Removed:
177
Added:
"""Returns thickness from 1 'x' along the airfoil chord."""
170
178
x = 0 if x < 0 else x
171
179
z_t = 5 * t * self.chord * (
172
180
+ 0.2969 * sqrt(x / self.chord)
@@ -227,7 +235,7 @@
227
235
228
236
229
237
class Spar(Coordinates):
230
Removed:
'''Contains a single spar's location.'''
238
Added:
"""Contains a single spar's location."""
231
239
global parent
232
240
233
241
def __init__(self):
@@ -243,7 +251,7 @@
243
251
self.dP_z = float()
244
252
245
253
def add_coord(self, airfoil, x_loc_percent):
246
Removed:
'''
254
Added:
"""
247
255
Add a single spar at the % chord location given to function.
248
256
249
257
Parameters:
@@ -252,8 +260,7 @@
252
260
253
261
Return:
254
262
None
255
Removed:
'''
256
Removed:
263
Added:
"""
257
264
# Scaled spar location with regards to chord
258
265
loc = x_loc_percent * self.chord
259
266
# bi.bisect_left: returns index of first value in airfoil.x > loc
@@ -279,8 +286,7 @@
279
286
return None
280
287
281
288
def add_webs(self, thickness):
282
Removed:
'''Add webs to spars.'''
283
Removed:
289
Added:
"""Add webs to spars."""
284
290
for _ in range(len(self.x)):
285
291
self.x_start.append(self.x[_][0])
286
292
self.x_end.append(self.x[_][1])
@@ -291,7 +297,7 @@
291
297
292
298
293
299
class Stringer(Coordinates):
294
Removed:
'''Contains the coordinates of all stringers.'''
300
Added:
"""Contains the coordinates of all stringers."""
295
301
global parent
296
302
297
303
def __init__(self):
@@ -310,7 +316,7 @@
310
316
def add_coord(self, airfoil,
311
317
stringer_u_1, stringer_u_2,
312
318
stringer_l_1, stringer_l_2):
313
Removed:
'''
319
Added:
"""
314
320
Add equally distributed stringers to four airfoil locations
315
321
(upper nose, lower nose, upper surface, lower surface).
316
322
@@ -324,8 +330,7 @@
324
330
325
331
Returns:
326
332
None
327
Removed:
'''
328
Removed:
333
Added:
"""
329
334
# Find distance between leading edge and first upper stringer
330
335
interval = airfoil.spar.x[0][0] / (stringer_u_1 + 1)
331
336
# initialise first self.stringer_x at first interval
@@ -377,8 +382,7 @@
377
382
return None
378
383
379
384
def add_webs(self, thickness):
380
Removed:
'''Add webs to stringers.'''
381
Removed:
385
Added:
"""Add webs to stringers."""
382
386
for _ in range(len(self.x) // 2):
383
387
self.x_start.append(self.x[_])
384
388
self.x_end.append(self.x[_ + 1])
@@ -394,8 +398,7 @@
394
398
395
399
396
400
def plot_geom(airfoil):
397
Removed:
'''This function plots the airfoil's + sub-components' geometry.'''
398
Removed:
401
Added:
"""This function plots the airfoil's + sub-components' geometry."""
399
402
# Plot chord
400
403
x_chord = [0, airfoil.chord]
401
404
y_chord = [0, 0]
evaluator.py
@@ -12,8 +12,13 @@
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program. If not, see <https://www.gnu.org/licenses/>.
15
Added:
"""
16
Added:
The 'evaluator' module contains a single Evaluator class,
17
Added:
which knows all the attributes of a specified Airfoil instance,
18
Added:
and contains functions to analyse the airfoil's geometrical
19
Added:
& structural properties.
20
Added:
"""
15
21
16
Removed:
17
22
import sys
18
23
import os.path
19
24
import numpy as np
@@ -22,7 +27,7 @@
22
27
23
28
24
29
class Evaluator:
25
Removed:
'''Performs structural evaluations for the airfoil passed as argument.'''
30
Added:
"""Performs structural evaluations for the airfoil passed as argument."""
26
31
27
32
def __init__(self, airfoil):
28
33
# Evaluator knows all geometrical info from evaluated airfoil
@@ -32,8 +37,7 @@
32
37
# Global dimensions
33
38
self.chord = airfoil.chord
34
39
self.semi_span = airfoil.semi_span
35
Removed:
36
Removed:
# mass and area
40
Added:
# Mass & spanwise distribution
37
41
self.mass_total = float(airfoil.mass
38
42
+ airfoil.spar.mass
39
43
+ airfoil.stringer.mass)
@@ -50,18 +54,14 @@
50
54
# centroid
51
55
self.centroid = []
52
56
# Inertia terms:
53
Removed:
# I_x = self.I_[0]
54
Removed:
# I_z = self.I_[1]
55
Removed:
# I_xz = self.I_[2]
56
Removed:
self.I_ = []
57
Added:
self.I_ = {'x': 0, 'z': 0, 'xz': 0}
57
58
58
59
def info_print(self, round):
59
Removed:
'''
60
Added:
"""
60
61
Print all the component's evaluated data to the terminal.
61
62
62
63
This function's output is piped to the 'save_data' function below.
63
Removed:
'''
64
Removed:
64
Added:
"""
65
65
name = ' EVALUATOR DATA '
66
66
num_of_dashes = len(name)
67
67
@@ -73,9 +73,9 @@
73
73
print('Total airfoil mass:', self.mass_total)
74
74
print('Centroid location:\n', np.around(self.centroid, 3))
75
75
print('Inertia terms:')
76
Removed:
print('I_x:\n', np.around(self.I_[0], 3))
77
Removed:
print('I_z:\n', np.around(self.I_[1], 3))
78
Removed:
print('I_xz:\n', np.around(self.I_[2], 3))
76
Added:
print('I_x:\n', np.around(self.I_['x'], 3))
77
Added:
print('I_z:\n', np.around(self.I_['z'], 3))
78
Added:
print('I_xz:\n', np.around(self.I_['xz'], 3))
79
79
print('Spar dP_x:\n', self.spar.dP_x)
80
80
print('Spar dP_z:\n', self.spar.dP_z)
81
81
print(num_of_dashes * '-')
@@ -91,8 +91,7 @@
91
91
return None
92
92
93
93
def info_save(self, save_path, number):
94
Removed:
'''Save all the object's coordinates (must be full path).'''
95
Removed:
94
Added:
"""Save all the object's coordinates (must be full path)."""
96
95
file_name = 'airfoil_{}_eval.txt'.format(number)
97
96
full_path = os.path.join(save_path, file_name)
98
97
try:
@@ -102,22 +101,22 @@
102
101
sys.stdout = sys.__stdout__
103
102
print('Successfully wrote to file {}'.format(full_path))
104
103
except IOError:
105
Removed:
print('Unable to write {} to specified directory.\n'
106
Removed:
.format(file_name),
107
Removed:
'Was the full path passed to the function?')
104
Added:
print(
105
Added:
'Unable to write {} to specified directory.\n'.format(
106
Added:
file_name), 'Was the full path passed to the function?')
108
107
return None
109
108
110
109
# All these functions take integer arguments and return lists.
111
110
112
111
def get_lift_rectangular(self, lift):
113
Removed:
L_prime = [lift / (self.semi_span * 2)
114
Removed:
for x in range(self.semi_span)]
112
Added:
L_prime = [lift / (self.semi_span * 2) for x in range(self.semi_span)]
115
113
return L_prime
116
114
117
115
def get_lift_elliptical(self, L_0):
118
Removed:
L_prime = [L_0 / (self.semi_span * 2)
119
Removed:
* sqrt(1 - (y / self.semi_span) ** 2)
120
Removed:
for y in range(self.semi_span)]
116
Added:
L_prime = [
117
Added:
L_0 / (self.semi_span * 2) * sqrt(1 - (y / self.semi_span)**2)
118
Added:
for y in range(self.semi_span)
119
Added:
]
121
120
return L_prime
122
121
123
122
def get_lift_total(self):
@@ -126,8 +125,7 @@
126
125
return F_z
127
126
128
127
def get_mass_distribution(self, total_mass):
129
Removed:
F_z = [total_mass / self.semi_span
130
Removed:
for x in range(0, self.semi_span)]
128
Added:
F_z = [total_mass / self.semi_span for x in range(0, self.semi_span)]
131
129
return F_z
132
130
133
131
def get_drag(self, drag):
@@ -143,8 +141,7 @@
143
141
return F_x
144
142
145
143
def get_centroid(self):
146
Removed:
'''Return the coordinates of the centroid.'''
147
Removed:
144
Added:
"""Return the coordinates of the centroid."""
148
145
stringer_area = self.stringer.area
149
146
cap_area = self.spar.cap_area
150
147
@@ -163,11 +160,11 @@
163
160
centroid_z = float(sum([z * cap_area for z in caps_z])
164
161
+ sum([z * stringer_area for z in stringers_z]))
165
162
centroid_z = centroid_z / denominator
166
Removed:
return(centroid_x, centroid_z)
167
163
168
Removed:
def get_inertia_terms(self):
169
Removed:
'''Obtain all inertia terms.'''
164
Added:
return (centroid_x, centroid_z)
170
165
166
Added:
def get_inertia_terms(self):
167
Added:
"""Obtain all inertia terms."""
171
168
stringer_area = self.stringer.area
172
169
cap_area = self.spar.cap_area
173
170
@@ -180,72 +177,75 @@
180
177
spar_count = range(len(self.spar.x))
181
178
182
179
# I_x is the sum of the contributions of the spar caps and stringers
183
Removed:
I_x = (sum([cap_area * (z_spars[i] - self.centroid[1]) ** 2
184
Removed:
for i in spar_count])
185
Removed:
+ sum([stringer_area * (z_stringers[i] - self.centroid[1]) ** 2
186
Removed:
for i in stringer_count]))
180
Added:
# TODO: replace list indices with dictionary value
181
Added:
I_x = sum([cap_area * (z_spars[i] - self.centroid[1])**2
182
Added:
for i in spar_count])
183
Added:
I_x += sum([stringer_area * (z_stringers[i] - self.centroid[1])**2
184
Added:
for i in stringer_count])
187
185
188
Removed:
I_z = (sum([cap_area * (x_spars[i] - self.centroid[0]) ** 2
186
Added:
I_z = sum([cap_area * (x_spars[i] - self.centroid[0])**2
187
Added:
for i in spar_count])
188
Added:
I_z += sum([stringer_area * (x_stringers[i] - self.centroid[0])**2
189
Added:
for i in stringer_count])
190
Added:
191
Added:
I_xz = sum([cap_area * (x_spars[i] - self.centroid[0])
192
Added:
* (z_spars[i] - self.centroid[1])
189
193
for i in spar_count])
190
Removed:
+ sum([stringer_area * (x_stringers[i] - self.centroid[0]) ** 2
191
Removed:
for i in stringer_count]))
194
Added:
I_xz += sum([stringer_area * (x_stringers[i] - self.centroid[0])
195
Added:
* (z_stringers[i] - self.centroid[1])
196
Added:
for i in stringer_count])
197
Added:
return (I_x, I_z, I_xz)
192
198
193
Removed:
I_xz = (sum([cap_area * (x_spars[i] - self.centroid[0])
194
Removed:
* (z_spars[i] - self.centroid[1])
195
Removed:
for i in spar_count])
196
Removed:
+ sum([stringer_area * (x_stringers[i] - self.centroid[0])
197
Removed:
* (z_stringers[i] - self.centroid[1])
198
Removed:
for i in stringer_count]))
199
Added:
def get_dx(self, component):
200
Added:
return [x - self.centroid[0] for x in component.x_start]
199
201
200
Removed:
return(I_x, I_z, I_xz)
202
Added:
def get_dz(self, component):
203
Added:
return [x - self.centroid[1] for x in component.x_start]
201
204
202
205
def analysis(self, V_x, V_z):
203
Removed:
'''Perform all analysis calculations and store in class instance.'''
206
Added:
"""Perform all analysis calculations and store in class instance."""
204
207
205
Removed:
def get_dp(xDist, zDist, V_x, V_z, I_x, I_z, I_xz, area):
208
Added:
def get_dP(xDist, zDist, V_x, V_z, I_x, I_z, I_xz, area):
206
209
denom = float(I_x * I_z - I_xz ** 2)
207
210
z = float()
208
211
for _ in range(len(xDist)):
209
Removed:
z += float(- area * xDist[_] * (I_x * V_x - I_xz * V_z)
212
Added:
z += float(-area * xDist[_] * (I_x * V_x - I_xz * V_z)
210
213
/ denom
211
214
- area * zDist[_] * (I_z * V_z - I_xz * V_x)
212
215
/ denom)
213
216
return z
214
217
215
Removed:
def get_dx(component):
216
Removed:
return [x - self.centroid[0] for x in component.x_start]
217
Removed:
218
Removed:
def get_dz(component):
219
Removed:
return [x - self.centroid[1] for x in component.x_start]
220
Removed:
221
218
self.drag = self.get_drag(10)
222
Removed:
223
219
self.lift_rectangular = self.get_lift_rectangular(13.7)
224
220
self.lift_elliptical = self.get_lift_elliptical(15)
225
221
self.lift_total = self.get_lift_total()
226
Removed:
227
222
self.mass_dist = self.get_mass_distribution(self.mass_total)
228
223
self.centroid = self.get_centroid()
229
Removed:
self.I_ = self.get_inertia_terms()
230
Removed:
self.spar.dP_x = get_dp(get_dx(self.spar), get_dz(self.spar), V_x, 0,
231
Removed:
self.I_[0], self.I_[1], self.I_[2],
224
Added:
self.I_['x'] = self.get_inertia_terms()[0]
225
Added:
self.I_['z'] = self.get_inertia_terms()[1]
226
Added:
self.I_['xz'] = self.get_inertia_terms()[2]
227
Added:
spar_dx = self.get_dx(self.spar)
228
Added:
spar_dz = self.get_dz(self.spar)
229
Added:
self.spar.dP_x = get_dP(spar_dx, spar_dz,
230
Added:
V_x, 0,
231
Added:
self.I_['x'], self.I_['z'], self.I_['xz'],
232
232
self.spar.cap_area)
233
Removed:
self.spar.dP_z = get_dp(get_dx(self.spar), get_dz(self.spar), 0, V_z,
234
Removed:
self.I_[0], self.I_[1], self.I_[2],
233
Added:
self.spar.dP_z = get_dP(spar_dx, spar_dz,
234
Added:
0, V_z,
235
Added:
self.I_['x'], self.I_['z'], self.I_['xz'],
235
236
self.spar.cap_area)
236
237
return None
237
238
238
239
239
240
def plot_geom(evaluator):
240
Removed:
'''This function plots analysis results over the airfoil's geometry.'''
241
Removed:
241
Added:
"""This function plots analysis results over the airfoil's geometry."""
242
242
# Plot chord
243
243
x_chord = [0, evaluator.chord]
244
244
y_chord = [0, 0]
245
245
plt.plot(x_chord, y_chord, linewidth='1')
246
246
# Plot quarter chord
247
Removed:
plt.plot(evaluator.chord / 4, 0, '.', color='g',
248
Removed:
markersize=24, label='Quarter-chord')
247
Added:
plt.plot(evaluator.chord / 4, 0,
248
Added:
'.', color='g', markersize=24, label='Quarter-chord')
249
249
# Plot airfoil surfaces
250
250
x = [0.98 * x for x in evaluator.x]
251
251
y = [0.98 * z for z in evaluator.z]
@@ -281,8 +281,8 @@
281
281
plt.ylabel('Z axis')
282
282
283
283
plot_bound = max(evaluator.x)
284
Removed:
plt.xlim(- 0.10 * plot_bound, 1.10 * plot_bound)
285
Removed:
plt.ylim(- (1.10 * plot_bound / 2), (1.10 * plot_bound / 2))
284
Added:
plt.xlim(-0.10 * plot_bound, 1.10 * plot_bound)
285
Added:
plt.ylim(-(1.10 * plot_bound / 2), (1.10 * plot_bound / 2))
286
286
plt.gca().set_aspect('equal', adjustable='box')
287
287
plt.gca().legend()
288
288
plt.grid(axis='both', linestyle=':', linewidth=1)
@@ -295,10 +295,8 @@
295
295
y_1 = evaluator.lift_rectangular
296
296
y_2 = evaluator.lift_elliptical
297
297
y_3 = evaluator.lift_total
298
Removed:
plt.plot(x, y_1, '.', color='b', markersize=4,
299
Removed:
label='Rectangular lift')
300
Removed:
plt.plot(x, y_2, '.', color='g', markersize=4,
301
Removed:
label='Elliptical lift')
298
Added:
plt.plot(x, y_1, '.', color='b', markersize=4, label='Rectangular lift')
299
Added:
plt.plot(x, y_2, '.', color='g', markersize=4, label='Elliptical lift')
302
300
plt.plot(x, y_3, '.', color='r', markersize=4, label='Total lift')
303
301
304
302
# Graph formatting
generator.py
@@ -12,25 +12,31 @@
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program. If not, see <https://www.gnu.org/licenses/>.
15
Added:
"""
16
Added:
The 'generator' module contains a single Population class,
17
Added:
which represents a collection of randomized airfoils.
18
Added:
"""
15
19
16
Removed:
import creator
20
Added:
import creator as cr
17
21
18
22
19
Removed:
class Population:
20
Removed:
'''Collection of random airfoils.'''
23
Added:
class Population(cr.Airfoil, cr.Spar, cr.Stringer):
24
Added:
"""Collection of random airfoils."""
21
25
22
26
def __init__(self, size):
27
Added:
af = cr.Airfoil
28
Added:
# print(af)
23
29
self.size = size
24
30
self.gen_number = 0 # incremented for every generation
25
31
26
32
def mutate(self, prob_mt):
27
Removed:
'''Randomly mutate the genes of prob_mt % of the population.'''
33
Added:
"""Randomly mutate the genes of prob_mt % of the population."""
28
34
29
35
def crossover(self, prob_cx):
30
Removed:
'''Combine the genes of prob_cx % of the population.'''
36
Added:
"""Combine the genes of prob_cx % of the population."""
31
37
32
38
def reproduce(self, prob_rp):
33
Removed:
'''Pass on the genes of the fittest prob_rp % of the population.'''
39
Added:
"""Pass on the genes of the fittest prob_rp % of the population."""
34
40
35
41
def fitness():
36
Removed:
'''Rate the fitness of an individual on a relative scale (0-100)'''
42
Added:
"""Rate the fitness of an individual on a relative scale (0-100)"""
main.py
@@ -52,12 +52,11 @@
52
52
53
53
54
54
def main():
55
Removed:
'''
55
Added:
"""
56
56
Create an airfoil;
57
57
Evaluate an airfoil;
58
58
Generate a population of airfoils & optimize.
59
Removed:
'''
60
Removed:
59
Added:
"""
61
60
# Create coordinate system specific to our airfoil dimensions.
62
61
# TODO: imperial + metric unit setting
63
62
creator.Coordinates(CHORD_LENGTH, SEMI_SPAN)
@@ -70,8 +69,8 @@
70
69
# Define NACA airfoil coordinates and mass
71
70
af.add_naca(NACA_NUM)
72
71
af.add_mass(AIRFOIL_MASS)
73
Removed:
af.info_print(2)
74
Removed:
af.info_save(SAVE_PATH, _)
72
Added:
# af.info_print(2)
73
Added:
# af.info_save(SAVE_PATH, _)
75
74
76
75
# Create spar instance
77
76
af.spar = creator.Spar()
@@ -82,8 +81,8 @@
82
81
af.spar.add_spar_caps(SPAR_CAP_AREA)
83
82
af.spar.add_mass(SPAR_MASS)
84
83
af.spar.add_webs(SPAR_THICKNESS)
85
Removed:
af.spar.info_print(2)
86
Removed:
af.spar.info_save(SAVE_PATH, _)
84
Added:
# af.spar.info_print(2)
85
Added:
# af.spar.info_save(SAVE_PATH, _)
87
86
88
87
# Create stringer instance
89
88
af.stringer = creator.Stringer()
@@ -96,20 +95,26 @@
96
95
af.stringer.add_area(STRINGER_AREA)
97
96
af.stringer.add_mass(STRINGER_MASS)
98
97
af.stringer.add_webs(SKIN_THICKNESS)
99
Removed:
af.stringer.info_print(2)
100
Removed:
af.stringer.info_save(SAVE_PATH, _)
101
Removed:
98
Added:
# af.stringer.info_print(2)
99
Added:
# af.stringer.info_save(SAVE_PATH, _)
100
Added:
#
102
101
# Plot components with matplotlib
103
Removed:
creator.plot_geom(af)
102
Added:
# creator.plot_geom(af)
104
103
105
104
# Evaluator object contains airfoil analysis results.
106
105
eval = evaluator.Evaluator(af)
107
106
# The analysis is performed in the evaluator.py module.
108
107
eval.analysis(1, 1)
109
Removed:
eval.info_print(2)
110
Removed:
eval.info_save(SAVE_PATH, _)
108
Added:
# eval.info_print(2)
109
Added:
# eval.info_save(SAVE_PATH, _)
111
110
evaluator.plot_geom(eval)
112
Removed:
evaluator.plot_lift(eval)
111
Added:
# evaluator.plot_lift(eval)
112
Added:
113
Added:
pop = generator.Population(10)
114
Added:
115
Added:
# print(help(creator))
116
Added:
# print(help(evaluator))
117
Added:
# print(help(generator))
113
118
114
119
# Print final execution time
115
120
print("--- %s seconds ---" % (time.time() - start_time))