[Python] Design & build airplanes from your specifications.
Start work on Evaluator
Changed files
.gitignore
@@ -2,3 +2,4 @@
2
2
**/__pycache__/
3
3
**/log.txt
4
4
save/
5
Added:
TAGS
evaluator.py
@@ -1,284 +0,0 @@
1
Removed:
"""
2
Removed:
The evaluator.py module contains a single Evaluator class,
3
Removed:
which knows all the attributes of a specified Airfoil instance,
4
Removed:
and contains functions to analyse the airfoil's geometrical
5
Removed:
& structural properties.
6
Removed:
"""
7
Removed:
8
Removed:
import sys
9
Removed:
import os.path
10
Removed:
import numpy as np
11
Removed:
from math import sqrt
12
Removed:
import matplotlib.pyplot as plt
13
Removed:
14
Removed:
15
Removed:
class Evaluator:
16
Removed:
"""Performs structural evaluations for the airfoil passed as argument."""
17
Removed:
def __init__(self, airfoil):
18
Removed:
# Evaluator knows all geometrical info from evaluated airfoil
19
Removed:
self.airfoil = airfoil
20
Removed:
self.spar = airfoil.spar
21
Removed:
self.stringer = airfoil.stringer
22
Removed:
# Global dimensions
23
Removed:
self.chord = airfoil.chord
24
Removed:
self.semi_span = airfoil.semi_span
25
Removed:
# Mass & spanwise distribution
26
Removed:
self.mass_total = float(airfoil.mass + airfoil.spar.mass +
27
Removed:
airfoil.stringer.mass)
28
Removed:
self.mass_dist = []
29
Removed:
# Lift
30
Removed:
self.lift_rectangular = []
31
Removed:
self.lift_elliptical = []
32
Removed:
self.lift_total = []
33
Removed:
# Drag
34
Removed:
self.drag = []
35
Removed:
# centroid
36
Removed:
self.centroid = []
37
Removed:
# Inertia terms:
38
Removed:
self.I_ = {'x': 0, 'z': 0, 'xz': 0}
39
Removed:
40
Removed:
def __str__(self):
41
Removed:
return type(self).__name__
42
Removed:
43
Removed:
def info_print(self, round):
44
Removed:
"""Print all the component's evaluated data to the terminal."""
45
Removed:
name = ' EVALUATOR DATA FOR {} '.format(str(self).upper())
46
Removed:
num_of_dashes = len(name)
47
Removed:
print(num_of_dashes * '-')
48
Removed:
print(name)
49
Removed:
for k, v in self.__dict__.items():
50
Removed:
if type(v) != list:
51
Removed:
print('{}:\n'.format(k), v)
52
Removed:
print(num_of_dashes * '-')
53
Removed:
for k, v in self.__dict__.items():
54
Removed:
if type(v) == list:
55
Removed:
print('{}:\n'.format(k), np.around(v, round))
56
Removed:
return None
57
Removed:
58
Removed:
def info_save(self, save_path, number):
59
Removed:
"""Save all the object's coordinates (must be full path)."""
60
Removed:
file_name = 'airfoil_{}_eval.txt'.format(number)
61
Removed:
full_path = os.path.join(save_path, file_name)
62
Removed:
try:
63
Removed:
with open(full_path, 'w') as sys.stdout:
64
Removed:
self.info_print(6)
65
Removed:
# This line required to reset behavior of sys.stdout
66
Removed:
sys.stdout = sys.__stdout__
67
Removed:
print('Successfully wrote to file {}'.format(full_path))
68
Removed:
except IOError:
69
Removed:
print(
70
Removed:
'Unable to write {} to specified directory.\n'.format(
71
Removed:
file_name), 'Was the full path passed to the function?')
72
Removed:
return None
73
Removed:
74
Removed:
# All these functions take integer arguments and return lists.
75
Removed:
76
Removed:
def get_lift_rectangular(self, lift):
77
Removed:
L_prime = [lift / (self.semi_span * 2) for x in range(self.semi_span)]
78
Removed:
return L_prime
79
Removed:
80
Removed:
def get_lift_elliptical(self, L_0):
81
Removed:
L_prime = [
82
Removed:
L_0 / (self.semi_span * 2) * sqrt(1 - (y / self.semi_span)**2)
83
Removed:
for y in range(self.semi_span)
84
Removed:
]
85
Removed:
return L_prime
86
Removed:
87
Removed:
def get_lift_total(self):
88
Removed:
F_z = [(self.lift_rectangular[_] + self.lift_elliptical[_]) / 2
89
Removed:
for _ in range(len(self.lift_rectangular))]
90
Removed:
return F_z
91
Removed:
92
Removed:
def get_mass_distribution(self, total_mass):
93
Removed:
F_z = [total_mass / self.semi_span for x in range(0, self.semi_span)]
94
Removed:
return F_z
95
Removed:
96
Removed:
def get_drag(self, drag):
97
Removed:
# Transform semi-span integer into list
98
Removed:
semi_span = [x for x in range(0, self.semi_span)]
99
Removed:
100
Removed:
# Drag increases after 80% of the semi_span
101
Removed:
cutoff = round(0.8 * self.semi_span)
102
Removed:
103
Removed:
# Drag increases by 25% after 80% of the semi_span
104
Removed:
F_x = [drag for x in semi_span[0:cutoff]]
105
Removed:
F_x.extend([1.25 * drag for x in semi_span[cutoff:]])
106
Removed:
return F_x
107
Removed:
108
Removed:
def get_centroid(self):
109
Removed:
"""Return the coordinates of the centroid."""
110
Removed:
stringer_area = self.stringer.area
111
Removed:
cap_area = self.spar.cap_area
112
Removed:
113
Removed:
caps_x = [value for spar in self.spar.x for value in spar]
114
Removed:
caps_z = [value for spar in self.spar.z for value in spar]
115
Removed:
stringers_x = self.stringer.x
116
Removed:
stringers_z = self.stringer.z
117
Removed:
118
Removed:
denominator = float(
119
Removed:
len(caps_x) * cap_area + len(stringers_x) * stringer_area)
120
Removed:
121
Removed:
centroid_x = float(
122
Removed:
sum([x * cap_area for x in caps_x]) +
123
Removed:
sum([x * stringer_area for x in stringers_x]))
124
Removed:
centroid_x = centroid_x / denominator
125
Removed:
126
Removed:
centroid_z = float(
127
Removed:
sum([z * cap_area for z in caps_z]) +
128
Removed:
sum([z * stringer_area for z in stringers_z]))
129
Removed:
centroid_z = centroid_z / denominator
130
Removed:
131
Removed:
return (centroid_x, centroid_z)
132
Removed:
133
Removed:
def get_inertia_terms(self):
134
Removed:
"""Obtain all inertia terms."""
135
Removed:
stringer_area = self.stringer.area
136
Removed:
cap_area = self.spar.cap_area
137
Removed:
138
Removed:
# Adds upper and lower components' coordinates to list
139
Removed:
x_stringers = self.stringer.x
140
Removed:
z_stringers = self.stringer.z
141
Removed:
x_spars = self.spar.x[:][0] + self.spar.x[:][1]
142
Removed:
z_spars = self.spar.z[:][0] + self.spar.z[:][1]
143
Removed:
stringer_count = range(len(x_stringers))
144
Removed:
spar_count = range(len(self.spar.x))
145
Removed:
146
Removed:
# I_x is the sum of the contributions of the spar caps and stringers
147
Removed:
# TODO: replace list indices with dictionary value
148
Removed:
I_x = sum([
149
Removed:
cap_area * (z_spars[i] - self.centroid[1])**2 for i in spar_count
150
Removed:
])
151
Removed:
I_x += sum([
152
Removed:
stringer_area * (z_stringers[i] - self.centroid[1])**2
153
Removed:
for i in stringer_count
154
Removed:
])
155
Removed:
156
Removed:
I_z = sum([
157
Removed:
cap_area * (x_spars[i] - self.centroid[0])**2 for i in spar_count
158
Removed:
])
159
Removed:
I_z += sum([
160
Removed:
stringer_area * (x_stringers[i] - self.centroid[0])**2
161
Removed:
for i in stringer_count
162
Removed:
])
163
Removed:
164
Removed:
I_xz = sum([
165
Removed:
cap_area * (x_spars[i] - self.centroid[0]) *
166
Removed:
(z_spars[i] - self.centroid[1]) for i in spar_count
167
Removed:
])
168
Removed:
I_xz += sum([
169
Removed:
stringer_area * (x_stringers[i] - self.centroid[0]) *
170
Removed:
(z_stringers[i] - self.centroid[1]) for i in stringer_count
171
Removed:
])
172
Removed:
return (I_x, I_z, I_xz)
173
Removed:
174
Removed:
def get_dx(self, component):
175
Removed:
return [x - self.centroid[0] for x in component.x_start]
176
Removed:
177
Removed:
def get_dz(self, component):
178
Removed:
return [x - self.centroid[1] for x in component.x_start]
179
Removed:
180
Removed:
def get_dP(self, xDist, zDist, V_x, V_z, area):
181
Removed:
I_x = self.I_['x']
182
Removed:
I_z = self.I_['z']
183
Removed:
I_xz = self.I_['xz']
184
Removed:
denom = float(I_x * I_z - I_xz**2)
185
Removed:
z = float()
186
Removed:
for _ in range(len(xDist)):
187
Removed:
z += float(-area * xDist[_] * (I_x * V_x - I_xz * V_z) / denom -
188
Removed:
area * zDist[_] * (I_z * V_z - I_xz * V_x) / denom)
189
Removed:
return z
190
Removed:
191
Removed:
def analysis(self, V_x, V_z):
192
Removed:
"""Perform all analysis calculations and store in class instance."""
193
Removed:
self.drag = self.get_drag(10)
194
Removed:
self.lift_rectangular = self.get_lift_rectangular(13.7)
195
Removed:
self.lift_elliptical = self.get_lift_elliptical(15)
196
Removed:
self.lift_total = self.get_lift_total()
197
Removed:
self.mass_dist = self.get_mass_distribution(self.mass_total)
198
Removed:
self.centroid = self.get_centroid()
199
Removed:
self.I_['x'] = self.get_inertia_terms()[0]
200
Removed:
self.I_['z'] = self.get_inertia_terms()[1]
201
Removed:
self.I_['xz'] = self.get_inertia_terms()[2]
202
Removed:
spar_dx = self.get_dx(self.spar)
203
Removed:
spar_dz = self.get_dz(self.spar)
204
Removed:
self.spar.dP_x = self.get_dP(spar_dx, spar_dz, V_x, 0,
205
Removed:
self.spar.cap_area)
206
Removed:
self.spar.dP_z = self.get_dP(spar_dx, spar_dz, 0, V_z,
207
Removed:
self.spar.cap_area)
208
Removed:
return None
209
Removed:
210
Removed:
211
Removed:
def plot_geom(evaluator):
212
Removed:
"""This function plots analysis results over the airfoil's geometry."""
213
Removed:
# Plot chord
214
Removed:
x_chord = [0, evaluator.chord]
215
Removed:
y_chord = [0, 0]
216
Removed:
plt.plot(x_chord, y_chord, linewidth='1')
217
Removed:
# Plot quarter chord
218
Removed:
plt.plot(evaluator.chord / 4,
219
Removed:
0,
220
Removed:
'.',
221
Removed:
color='g',
222
Removed:
markersize=24,
223
Removed:
label='Quarter-chord')
224
Removed:
# Plot airfoil surfaces
225
Removed:
x = [0.98 * x for x in evaluator.airfoil.x]
226
Removed:
y = [0.98 * z for z in evaluator.airfoil.z]
227
Removed:
plt.fill(x, y, color='w', linewidth='1', fill=False)
228
Removed:
x = [1.02 * x for x in evaluator.airfoil.x]
229
Removed:
y = [1.02 * z for z in evaluator.airfoil.z]
230
Removed:
plt.fill(x, y, color='b', linewidth='1', fill=False)
231
Removed:
232
Removed:
# Plot spars
233
Removed:
try:
234
Removed:
for _ in range(len(evaluator.spar.x)):
235
Removed:
x = (evaluator.spar.x[_])
236
Removed:
y = (evaluator.spar.z[_])
237
Removed:
plt.plot(x, y, '-', color='b')
238
Removed:
except AttributeError:
239
Removed:
print('No spars to plot.')
240
Removed:
# Plot stringers
241
Removed:
try:
242
Removed:
for _ in range(0, len(evaluator.stringer.x)):
243
Removed:
x = evaluator.stringer.x[_]
244
Removed:
y = evaluator.stringer.z[_]
245
Removed:
plt.plot(x, y, '.', color='y', markersize=12)
246
Removed:
except AttributeError:
247
Removed:
print('No stringers to plot.')
248
Removed:
249
Removed:
# Plot centroid
250
Removed:
x = evaluator.centroid[0]
251
Removed:
y = evaluator.centroid[1]
252
Removed:
plt.plot(x, y, '.', color='r', markersize=24, label='centroid')
253
Removed:
254
Removed:
# Graph formatting
255
Removed:
plt.xlabel('X axis')
256
Removed:
plt.ylabel('Z axis')
257
Removed:
258
Removed:
plot_bound = max(evaluator.airfoil.x)
259
Removed:
plt.xlim(-0.10 * plot_bound, 1.10 * plot_bound)
260
Removed:
plt.ylim(-(1.10 * plot_bound / 2), (1.10 * plot_bound / 2))
261
Removed:
plt.gca().set_aspect('equal', adjustable='box')
262
Removed:
plt.gca().legend()
263
Removed:
plt.grid(axis='both', linestyle=':', linewidth=1)
264
Removed:
plt.show()
265
Removed:
return None
266
Removed:
267
Removed:
268
Removed:
def plot_lift(evaluator):
269
Removed:
x = range(evaluator.semi_span)
270
Removed:
y_1 = evaluator.lift_rectangular
271
Removed:
y_2 = evaluator.lift_elliptical
272
Removed:
y_3 = evaluator.lift_total
273
Removed:
plt.plot(x, y_1, '.', color='b', markersize=4, label='Rectangular lift')
274
Removed:
plt.plot(x, y_2, '.', color='g', markersize=4, label='Elliptical lift')
275
Removed:
plt.plot(x, y_3, '.', color='r', markersize=4, label='Total lift')
276
Removed:
277
Removed:
# Graph formatting
278
Removed:
plt.xlabel('Semi-span location')
279
Removed:
plt.ylabel('Lift')
280
Removed:
281
Removed:
plt.gca().legend()
282
Removed:
plt.grid(axis='both', linestyle=':', linewidth=1)
283
Removed:
plt.show()
284
Removed:
return None
evaluator/evaluator.py
@@ -0,0 +1,284 @@
1
Added:
"""
2
Added:
The evaluator.py module contains a single Evaluator class,
3
Added:
which knows all the attributes of a specified Aircraft instance,
4
Added:
and contains functions to analyse the airfoil's geometrical
5
Added:
& structural properties.
6
Added:
"""
7
Added:
8
Added:
import sys
9
Added:
import os.path
10
Added:
import numpy as np
11
Added:
from math import sqrt
12
Added:
import matplotlib.pyplot as plt
13
Added:
14
Added:
15
Added:
class Evaluator:
16
Added:
"""Performs structural evaluations for the airfoil passed as argument."""
17
Added:
def __init__(self, airfoil):
18
Added:
# Evaluator knows all geometrical info from evaluated airfoil
19
Added:
self.airfoil = airfoil
20
Added:
self.spar = airfoil.spar
21
Added:
self.stringer = airfoil.stringer
22
Added:
# Global dimensions
23
Added:
self.chord = airfoil.chord
24
Added:
self.semi_span = airfoil.semi_span
25
Added:
# Mass & spanwise distribution
26
Added:
self.mass_total = float(airfoil.mass + airfoil.spar.mass +
27
Added:
airfoil.stringer.mass)
28
Added:
self.mass_dist = []
29
Added:
# Lift
30
Added:
self.lift_rectangular = []
31
Added:
self.lift_elliptical = []
32
Added:
self.lift_total = []
33
Added:
# Drag
34
Added:
self.drag = []
35
Added:
# centroid
36
Added:
self.centroid = []
37
Added:
# Inertia terms:
38
Added:
self.I_ = {'x': 0, 'z': 0, 'xz': 0}
39
Added:
40
Added:
def __str__(self):
41
Added:
return type(self).__name__
42
Added:
43
Added:
def info_print(self, round):
44
Added:
"""Print all the component's evaluated data to the terminal."""
45
Added:
name = ' EVALUATOR DATA FOR {} '.format(str(self).upper())
46
Added:
num_of_dashes = len(name)
47
Added:
print(num_of_dashes * '-')
48
Added:
print(name)
49
Added:
for k, v in self.__dict__.items():
50
Added:
if type(v) != list:
51
Added:
print('{}:\n'.format(k), v)
52
Added:
print(num_of_dashes * '-')
53
Added:
for k, v in self.__dict__.items():
54
Added:
if type(v) == list:
55
Added:
print('{}:\n'.format(k), np.around(v, round))
56
Added:
return None
57
Added:
58
Added:
def info_save(self, save_path, number):
59
Added:
"""Save all the object's coordinates (must be full path)."""
60
Added:
file_name = 'airfoil_{}_eval.txt'.format(number)
61
Added:
full_path = os.path.join(save_path, file_name)
62
Added:
try:
63
Added:
with open(full_path, 'w') as sys.stdout:
64
Added:
self.info_print(6)
65
Added:
# This line required to reset behavior of sys.stdout
66
Added:
sys.stdout = sys.__stdout__
67
Added:
print('Successfully wrote to file {}'.format(full_path))
68
Added:
except IOError:
69
Added:
print(
70
Added:
'Unable to write {} to specified directory.\n'.format(
71
Added:
file_name), 'Was the full path passed to the function?')
72
Added:
return None
73
Added:
74
Added:
# All these functions take integer arguments and return lists.
75
Added:
76
Added:
def get_lift_rectangular(self, lift):
77
Added:
L_prime = [lift / (self.semi_span * 2) for x in range(self.semi_span)]
78
Added:
return L_prime
79
Added:
80
Added:
def get_lift_elliptical(self, L_0):
81
Added:
L_prime = [
82
Added:
L_0 / (self.semi_span * 2) * sqrt(1 - (y / self.semi_span)**2)
83
Added:
for y in range(self.semi_span)
84
Added:
]
85
Added:
return L_prime
86
Added:
87
Added:
def get_lift_total(self):
88
Added:
F_z = [(self.lift_rectangular[_] + self.lift_elliptical[_]) / 2
89
Added:
for _ in range(len(self.lift_rectangular))]
90
Added:
return F_z
91
Added:
92
Added:
def get_mass_distribution(self, total_mass):
93
Added:
F_z = [total_mass / self.semi_span for x in range(0, self.semi_span)]
94
Added:
return F_z
95
Added:
96
Added:
def get_drag(self, drag):
97
Added:
# Transform semi-span integer into list
98
Added:
semi_span = [x for x in range(0, self.semi_span)]
99
Added:
100
Added:
# Drag increases after 80% of the semi_span
101
Added:
cutoff = round(0.8 * self.semi_span)
102
Added:
103
Added:
# Drag increases by 25% after 80% of the semi_span
104
Added:
F_x = [drag for x in semi_span[0:cutoff]]
105
Added:
F_x.extend([1.25 * drag for x in semi_span[cutoff:]])
106
Added:
return F_x
107
Added:
108
Added:
def get_centroid(self):
109
Added:
"""Return the coordinates of the centroid."""
110
Added:
stringer_area = self.stringer.area
111
Added:
cap_area = self.spar.cap_area
112
Added:
113
Added:
caps_x = [value for spar in self.spar.x for value in spar]
114
Added:
caps_z = [value for spar in self.spar.z for value in spar]
115
Added:
stringers_x = self.stringer.x
116
Added:
stringers_z = self.stringer.z
117
Added:
118
Added:
denominator = float(
119
Added:
len(caps_x) * cap_area + len(stringers_x) * stringer_area)
120
Added:
121
Added:
centroid_x = float(
122
Added:
sum([x * cap_area for x in caps_x]) +
123
Added:
sum([x * stringer_area for x in stringers_x]))
124
Added:
centroid_x = centroid_x / denominator
125
Added:
126
Added:
centroid_z = float(
127
Added:
sum([z * cap_area for z in caps_z]) +
128
Added:
sum([z * stringer_area for z in stringers_z]))
129
Added:
centroid_z = centroid_z / denominator
130
Added:
131
Added:
return (centroid_x, centroid_z)
132
Added:
133
Added:
def get_inertia_terms(self):
134
Added:
"""Obtain all inertia terms."""
135
Added:
stringer_area = self.stringer.area
136
Added:
cap_area = self.spar.cap_area
137
Added:
138
Added:
# Adds upper and lower components' coordinates to list
139
Added:
x_stringers = self.stringer.x
140
Added:
z_stringers = self.stringer.z
141
Added:
x_spars = self.spar.x[:][0] + self.spar.x[:][1]
142
Added:
z_spars = self.spar.z[:][0] + self.spar.z[:][1]
143
Added:
stringer_count = range(len(x_stringers))
144
Added:
spar_count = range(len(self.spar.x))
145
Added:
146
Added:
# I_x is the sum of the contributions of the spar caps and stringers
147
Added:
# TODO: replace list indices with dictionary value
148
Added:
I_x = sum([
149
Added:
cap_area * (z_spars[i] - self.centroid[1])**2 for i in spar_count
150
Added:
])
151
Added:
I_x += sum([
152
Added:
stringer_area * (z_stringers[i] - self.centroid[1])**2
153
Added:
for i in stringer_count
154
Added:
])
155
Added:
156
Added:
I_z = sum([
157
Added:
cap_area * (x_spars[i] - self.centroid[0])**2 for i in spar_count
158
Added:
])
159
Added:
I_z += sum([
160
Added:
stringer_area * (x_stringers[i] - self.centroid[0])**2
161
Added:
for i in stringer_count
162
Added:
])
163
Added:
164
Added:
I_xz = sum([
165
Added:
cap_area * (x_spars[i] - self.centroid[0]) *
166
Added:
(z_spars[i] - self.centroid[1]) for i in spar_count
167
Added:
])
168
Added:
I_xz += sum([
169
Added:
stringer_area * (x_stringers[i] - self.centroid[0]) *
170
Added:
(z_stringers[i] - self.centroid[1]) for i in stringer_count
171
Added:
])
172
Added:
return (I_x, I_z, I_xz)
173
Added:
174
Added:
def get_dx(self, component):
175
Added:
return [x - self.centroid[0] for x in component.x_start]
176
Added:
177
Added:
def get_dz(self, component):
178
Added:
return [x - self.centroid[1] for x in component.x_start]
179
Added:
180
Added:
def get_dP(self, xDist, zDist, V_x, V_z, area):
181
Added:
I_x = self.I_['x']
182
Added:
I_z = self.I_['z']
183
Added:
I_xz = self.I_['xz']
184
Added:
denom = float(I_x * I_z - I_xz**2)
185
Added:
z = float()
186
Added:
for _ in range(len(xDist)):
187
Added:
z += float(-area * xDist[_] * (I_x * V_x - I_xz * V_z) / denom -
188
Added:
area * zDist[_] * (I_z * V_z - I_xz * V_x) / denom)
189
Added:
return z
190
Added:
191
Added:
def analysis(self, V_x, V_z):
192
Added:
"""Perform all analysis calculations and store in class instance."""
193
Added:
self.drag = self.get_drag(10)
194
Added:
self.lift_rectangular = self.get_lift_rectangular(13.7)
195
Added:
self.lift_elliptical = self.get_lift_elliptical(15)
196
Added:
self.lift_total = self.get_lift_total()
197
Added:
self.mass_dist = self.get_mass_distribution(self.mass_total)
198
Added:
self.centroid = self.get_centroid()
199
Added:
self.I_['x'] = self.get_inertia_terms()[0]
200
Added:
self.I_['z'] = self.get_inertia_terms()[1]
201
Added:
self.I_['xz'] = self.get_inertia_terms()[2]
202
Added:
spar_dx = self.get_dx(self.spar)
203
Added:
spar_dz = self.get_dz(self.spar)
204
Added:
self.spar.dP_x = self.get_dP(spar_dx, spar_dz, V_x, 0,
205
Added:
self.spar.cap_area)
206
Added:
self.spar.dP_z = self.get_dP(spar_dx, spar_dz, 0, V_z,
207
Added:
self.spar.cap_area)
208
Added:
return None
209
Added:
210
Added:
211
Added:
def plot_geom(evaluator):
212
Added:
"""This function plots analysis results over the airfoil's geometry."""
213
Added:
# Plot chord
214
Added:
x_chord = [0, evaluator.chord]
215
Added:
y_chord = [0, 0]
216
Added:
plt.plot(x_chord, y_chord, linewidth='1')
217
Added:
# Plot quarter chord
218
Added:
plt.plot(evaluator.chord / 4,
219
Added:
0,
220
Added:
'.',
221
Added:
color='g',
222
Added:
markersize=24,
223
Added:
label='Quarter-chord')
224
Added:
# Plot airfoil surfaces
225
Added:
x = [0.98 * x for x in evaluator.airfoil.x]
226
Added:
y = [0.98 * z for z in evaluator.airfoil.z]
227
Added:
plt.fill(x, y, color='w', linewidth='1', fill=False)
228
Added:
x = [1.02 * x for x in evaluator.airfoil.x]
229
Added:
y = [1.02 * z for z in evaluator.airfoil.z]
230
Added:
plt.fill(x, y, color='b', linewidth='1', fill=False)
231
Added:
232
Added:
# Plot spars
233
Added:
try:
234
Added:
for _ in range(len(evaluator.spar.x)):
235
Added:
x = (evaluator.spar.x[_])
236
Added:
y = (evaluator.spar.z[_])
237
Added:
plt.plot(x, y, '-', color='b')
238
Added:
except AttributeError:
239
Added:
print('No spars to plot.')
240
Added:
# Plot stringers
241
Added:
try:
242
Added:
for _ in range(0, len(evaluator.stringer.x)):
243
Added:
x = evaluator.stringer.x[_]
244
Added:
y = evaluator.stringer.z[_]
245
Added:
plt.plot(x, y, '.', color='y', markersize=12)
246
Added:
except AttributeError:
247
Added:
print('No stringers to plot.')
248
Added:
249
Added:
# Plot centroid
250
Added:
x = evaluator.centroid[0]
251
Added:
y = evaluator.centroid[1]
252
Added:
plt.plot(x, y, '.', color='r', markersize=24, label='centroid')
253
Added:
254
Added:
# Graph formatting
255
Added:
plt.xlabel('X axis')
256
Added:
plt.ylabel('Z axis')
257
Added:
258
Added:
plot_bound = max(evaluator.airfoil.x)
259
Added:
plt.xlim(-0.10 * plot_bound, 1.10 * plot_bound)
260
Added:
plt.ylim(-(1.10 * plot_bound / 2), (1.10 * plot_bound / 2))
261
Added:
plt.gca().set_aspect('equal', adjustable='box')
262
Added:
plt.gca().legend()
263
Added:
plt.grid(axis='both', linestyle=':', linewidth=1)
264
Added:
plt.show()
265
Added:
return None
266
Added:
267
Added:
268
Added:
def plot_lift(evaluator):
269
Added:
x = range(evaluator.semi_span)
270
Added:
y_1 = evaluator.lift_rectangular
271
Added:
y_2 = evaluator.lift_elliptical
272
Added:
y_3 = evaluator.lift_total
273
Added:
plt.plot(x, y_1, '.', color='b', markersize=4, label='Rectangular lift')
274
Added:
plt.plot(x, y_2, '.', color='g', markersize=4, label='Elliptical lift')
275
Added:
plt.plot(x, y_3, '.', color='r', markersize=4, label='Total lift')
276
Added:
277
Added:
# Graph formatting
278
Added:
plt.xlabel('Semi-span location')
279
Added:
plt.ylabel('Lift')
280
Added:
281
Added:
plt.gca().legend()
282
Added:
plt.grid(axis='both', linestyle=':', linewidth=1)
283
Added:
plt.show()
284
Added:
return None
example_airfoil.py
@@ -42,18 +42,18 @@
42
42
SAVE_PATH = '/home/blendux/Projects/Aircraft_Studio/save'
43
43
44
44
# Create airfoil instance
45
Removed:
af = wing.Airfoil(68, 150, mt.aluminium)
45
Added:
af = wing.Airfoil(20, 150, mt.aluminium)
46
46
af.add_naca(NACA_NUM)
47
Removed:
# af.info_print(2)
48
Removed:
af.info_save(SAVE_PATH, 'foo_name')
47
Added:
af.info_print(2)
48
Added:
# af.info_save(SAVE_PATH, 'foo_name')
49
49
50
50
# Create spar instances
51
51
af.spar1 = wing.Spar(af, 0.23, mt.aluminium)
52
52
af.spar2 = wing.Spar(af, 0.57, mt.aluminium)
53
53
# af.spar1.info_print(2)
54
54
# af.spar2.info_print(2)
55
Removed:
af.spar1.info_save(SAVE_PATH, 'spar1')
56
Removed:
af.spar2.info_save(SAVE_PATH, 'spar2')
55
Added:
# af.spar1.info_save(SAVE_PATH, 'spar1')
56
Added:
# af.spar2.info_save(SAVE_PATH, 'spar2')
57
57
58
58
# # Create stringer instance
59
59
# af.stringer = wing.Stringer()
@@ -66,7 +66,7 @@
66
66
# af.stringer.info_save(SAVE_PATH, 'foo_name')
67
67
68
68
# Plot components with matplotlib
69
Removed:
wing.plot_geom(af, [af.spar1, af.spar2], None)
69
Added:
# wing.plot_geom(af, [af.spar1, af.spar2], None)
70
70
71
71
# Evaluator object contains airfoil analysis results.
72
72
# eval = evaluator.Evaluator(af)