Start work on Evaluator

Commit
fa38b61ff2bd193fad1f320d2d59b8cb34ecd288
Author
blendoit <blendoit@gmail.com>
Author date
Committer
blendoit <blendoit@gmail.com>
Committer date
Changed files
.gitignore
index c7969028..c62ecf26 100644..100644
@@ -2,3 +2,4 @@
2 2 **/__pycache__/
3 3 **/log.txt
4 4 save/
5 Added: TAGS
evaluator.py
index 85325a95..00000000 100644..000000
@@ -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
index 00000000..6c7f9014 000000..100644
@@ -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
index 292c1e99..08282a3c 100644..100644
@@ -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)