dir structure for evaluator

Commit
94ff14d3d1ab01a63aea34636c24fdcd67d4ed79
Author
blendoit <blendoit@gmail.com>
Author date
Committer
blendoit <blendoit@gmail.com>
Committer date
Changed files
creator/base.py
index 24b452c9..1e8646d8 100644..100644
@@ -13,17 +13,19 @@
13 13 class Aircraft:
14 14 """This class tracks all sub-components and is fed to the evaluator."""
15 15 def __init__(self, evaluator, name):
16 Removed: evaluator.tree.update({"aircraft": self})
16 Added: self.tree = {name: self}
17 Added: evaluator.tree[type(self).__name__] = self.tree
17 18 self.evaluator = evaluator
18 19 self.name = name
19 Removed: self.tree = [] # Nested list of subcomponents
20 20
21 21
22 22 class Component:
23 23 """Basic component providing coordinates, tools and a component tree."""
24 24 def __init__(self, parent, name):
25 Removed: self.tree = [name]
26 Removed: parent.tree.append(self.tree)
25 Added: self.tree = {name: self}
26 Added: # parent.tree.update(self.tree)
27 Added: parent.tree[type(self).__name__] = self.tree
28 Added: self.parent = parent
27 29 self.name = name
28 30 self.x = np.array([])
29 31 self.z = np.array([])
evaluator.py
index 096e9a0a..00000000 100644..000000
@@ -1,318 +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 Aircraft 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 on aircrafts.
17 Removed: Individual aircrafts must claim an Evaluator object as parent."""
18 Removed: def __init__(self):
19 Removed: self.tree = {} # Dictionary contains aircrafts and subcomponents
20 Removed: self.results = []
21 Removed: # # Evaluator knows all geometrical info from evaluated airfoil
22 Removed: # self.airfoil = self.get_airfoil(aircraft)
23 Removed: # self.spars = self.get_spars(aircraft)
24 Removed: # self.stringers = self.get_stringers(aircraft)
25 Removed: # # Lift
26 Removed: # self.lift_rectangular = []
27 Removed: # self.lift_elliptical = []
28 Removed: # self.lift_total = []
29 Removed: # # Drag
30 Removed: # self.drag = []
31 Removed: # # centroid
32 Removed: # self.centroid = []
33 Removed: # Inertia terms:
34 Removed: self.I_ = {'x': 0, 'z': 0, 'xz': 0}
35 Removed:
36 Removed: def get_lift_rectangular(aircraft, lift):
37 Removed: L_prime = [
38 Removed: lift / (aircraft.semi_span * 2) for x in range(aircraft.semi_span)
39 Removed: ]
40 Removed: return L_prime
41 Removed:
42 Removed: def get_lift_elliptical(aircraft, L_0):
43 Removed: L_prime = [
44 Removed: L_0 / (aircraft.semi_span * 2) * sqrt(1 -
45 Removed: (y / aircraft.semi_span)**2)
46 Removed: for y in range(aircraft.semi_span)
47 Removed: ]
48 Removed: return L_prime
49 Removed:
50 Removed: def get_lift_total(aircraft):
51 Removed: F_z = [(aircraft.lift_rectangular[_] + aircraft.lift_elliptical[_]) / 2
52 Removed: for _ in range(len(aircraft.lift_rectangular))]
53 Removed: return F_z
54 Removed:
55 Removed: def get_mass_distribution(self, total_mass):
56 Removed: F_z = [total_mass / self.semi_span for x in range(0, self.semi_span)]
57 Removed: return F_z
58 Removed:
59 Removed: def get_drag(self, drag):
60 Removed: # Transform semi-span integer into list
61 Removed: semi_span = [x for x in range(0, self.semi_span)]
62 Removed:
63 Removed: # Drag increases after 80% of the semi_span
64 Removed: cutoff = round(0.8 * self.semi_span)
65 Removed:
66 Removed: # Drag increases by 25% after 80% of the semi_span
67 Removed: F_x = [drag for x in semi_span[0:cutoff]]
68 Removed: F_x.extend([1.25 * drag for x in semi_span[cutoff:]])
69 Removed: return F_x
70 Removed:
71 Removed: def get_centroid(aircraft):
72 Removed: """Return the coordinates of the centroid."""
73 Removed: stringer_area = aircraft.stringer.area
74 Removed: cap_area = aircraft.spar.cap_area
75 Removed:
76 Removed: caps_x = [value for spar in aircraft.spar.x for value in spar]
77 Removed: caps_z = [value for spar in aircraft.spar.z for value in spar]
78 Removed: stringers_x = aircraft.stringer.x
79 Removed: stringers_z = aircraft.stringer.z
80 Removed:
81 Removed: denominator = float(
82 Removed: len(caps_x) * cap_area + len(stringers_x) * stringer_area)
83 Removed:
84 Removed: centroid_x = float(
85 Removed: sum([x * cap_area for x in caps_x]) +
86 Removed: sum([x * stringer_area for x in stringers_x]))
87 Removed: centroid_x = centroid_x / denominator
88 Removed:
89 Removed: centroid_z = float(
90 Removed: sum([z * cap_area for z in caps_z]) +
91 Removed: sum([z * stringer_area for z in stringers_z]))
92 Removed: centroid_z = centroid_z / denominator
93 Removed:
94 Removed: return (centroid_x, centroid_z)
95 Removed:
96 Removed: def get_inertia_terms(self):
97 Removed: """Obtain all inertia terms."""
98 Removed: stringer_area = self.stringer.area
99 Removed: cap_area = self.spar.cap_area
100 Removed:
101 Removed: # Adds upper and lower components' coordinates to list
102 Removed: x_stringers = self.stringer.x
103 Removed: z_stringers = self.stringer.z
104 Removed: x_spars = self.spar.x[:][0] + self.spar.x[:][1]
105 Removed: z_spars = self.spar.z[:][0] + self.spar.z[:][1]
106 Removed: stringer_count = range(len(x_stringers))
107 Removed: spar_count = range(len(self.spar.x))
108 Removed:
109 Removed: # I_x is the sum of the contributions of the spar caps and stringers
110 Removed: # TODO: replace list indices with dictionary value
111 Removed: I_x = sum([
112 Removed: cap_area * (z_spars[i] - self.centroid[1])**2 for i in spar_count
113 Removed: ])
114 Removed: I_x += sum([
115 Removed: stringer_area * (z_stringers[i] - self.centroid[1])**2
116 Removed: for i in stringer_count
117 Removed: ])
118 Removed:
119 Removed: I_z = sum([
120 Removed: cap_area * (x_spars[i] - self.centroid[0])**2 for i in spar_count
121 Removed: ])
122 Removed: I_z += sum([
123 Removed: stringer_area * (x_stringers[i] - self.centroid[0])**2
124 Removed: for i in stringer_count
125 Removed: ])
126 Removed:
127 Removed: I_xz = sum([
128 Removed: cap_area * (x_spars[i] - self.centroid[0]) *
129 Removed: (z_spars[i] - self.centroid[1]) for i in spar_count
130 Removed: ])
131 Removed: I_xz += sum([
132 Removed: stringer_area * (x_stringers[i] - self.centroid[0]) *
133 Removed: (z_stringers[i] - self.centroid[1]) for i in stringer_count
134 Removed: ])
135 Removed: return (I_x, I_z, I_xz)
136 Removed:
137 Removed: def get_dx(self, component):
138 Removed: return [x - self.centroid[0] for x in component.x_start]
139 Removed:
140 Removed: def get_dz(self, component):
141 Removed: return [x - self.centroid[1] for x in component.x_start]
142 Removed:
143 Removed: def get_dP(self, xDist, zDist, V_x, V_z, area):
144 Removed: I_x = self.I_['x']
145 Removed: I_z = self.I_['z']
146 Removed: I_xz = self.I_['xz']
147 Removed: denom = float(I_x * I_z - I_xz**2)
148 Removed: z = float()
149 Removed: for _ in range(len(xDist)):
150 Removed: z += float(-area * xDist[_] * (I_x * V_x - I_xz * V_z) / denom -
151 Removed: area * zDist[_] * (I_z * V_z - I_xz * V_x) / denom)
152 Removed: return z
153 Removed:
154 Removed: # def analysis(self, V_x, V_z):
155 Removed: # """Perform all analysis calculations and store in class instance."""
156 Removed:
157 Removed: # self.drag = self.get_drag(10)
158 Removed: # self.lift_rectangular = self.get_lift_rectangular(13.7)
159 Removed: # self.lift_elliptical = self.get_lift_elliptical(15)
160 Removed: # self.lift_total = self.get_lift_total()
161 Removed: # self.mass_dist = self.get_mass_distribution(self.mass_total)
162 Removed: # self.centroid = self.get_centroid()
163 Removed: # self.I_['x'] = self.get_inertia_terms()[0]
164 Removed: # self.I_['z'] = self.get_inertia_terms()[1]
165 Removed: # self.I_['xz'] = self.get_inertia_terms()[2]
166 Removed: # spar_dx = self.get_dx(self.spar)
167 Removed: # spar_dz = self.get_dz(self.spar)
168 Removed: # self.spar.dP_x = self.get_dP(spar_dx, spar_dz, V_x, 0,
169 Removed: # self.spar.cap_area)
170 Removed: # self.spar.dP_z = self.get_dP(spar_dx, spar_dz, 0, V_z,
171 Removed: # self.spar.cap_area)
172 Removed: # print("yayyyyy")
173 Removed: # return None
174 Removed:
175 Removed: def update(self):
176 Removed: """Get all aircrafts' data."""
177 Removed: for aircraft in self.tree:
178 Removed: # print(f"For {aircraft.name} tree is:")
179 Removed: # print("For", aircraft.name, " tree is:")
180 Removed: # print(self.tree)
181 Removed: self.results.append(self.analysis(aircraft))
182 Removed:
183 Removed: def analysis(self, aircraft):
184 Removed: """Perform all analysis calculations and store in class instance."""
185 Removed:
186 Removed: results = {
187 Removed: "Lift": self.get_lift_total,
188 Removed: "Drag": self.get_drag,
189 Removed: "Centroid": self.get_centroid
190 Removed: }
191 Removed:
192 Removed: # print(f"Analysis results for {aircraft.name}:\n", results)
193 Removed: return (results)
194 Removed: # self.results = self.get_lift_total(aircraft)
195 Removed:
196 Removed: # self.drag = self.get_drag(10)
197 Removed: # self.lift_rectangular = self.get_lift_rectangular(13.7)
198 Removed: # self.lift_elliptical = self.get_lift_elliptical(15)
199 Removed: # self.lift_total = self.get_lift_total()
200 Removed: # self.mass_dist = self.get_mass_distribution(self.mass_total)
201 Removed: # self.centroid = self.get_centroid()
202 Removed: # self.I_['x'] = self.get_inertia_terms()[0]
203 Removed: # self.I_['z'] = self.get_inertia_terms()[1]
204 Removed: # self.I_['xz'] = self.get_inertia_terms()[2]
205 Removed: # spar_dx = self.get_dx(self.spar)
206 Removed: # spar_dz = self.get_dz(self.spar)
207 Removed: # self.spar.dP_x = self.get_dP(spar_dx, spar_dz, V_x, 0,
208 Removed: # self.spar.cap_area)
209 Removed: # self.spar.dP_z = self.get_dP(spar_dx, spar_dz, 0, V_z,
210 Removed: # self.spar.cap_area)
211 Removed: return None
212 Removed:
213 Removed: def info_print(self, round):
214 Removed: """Print all the component's evaluated data to the terminal."""
215 Removed: name = f' {print(self)} DATA FOR {str(self).upper()} '
216 Removed: num_of_dashes = len(name)
217 Removed: print(num_of_dashes * '-')
218 Removed: print(name)
219 Removed: for k, v in self.__dict__.items():
220 Removed: if type(v) != list:
221 Removed: print('{}:\n'.format(k), v)
222 Removed: print(num_of_dashes * '-')
223 Removed: for k, v in self.__dict__.items():
224 Removed: if type(v) == list:
225 Removed: print('{}:\n'.format(k), np.around(v, round))
226 Removed: return None
227 Removed:
228 Removed: def info_save(self, save_path, number):
229 Removed: """Save all the object's coordinates (must be full path)."""
230 Removed: file_name = 'airfoil_{}_eval.txt'.format(number)
231 Removed: full_path = os.path.join(save_path, file_name)
232 Removed: try:
233 Removed: with open(full_path, 'w') as sys.stdout:
234 Removed: self.info_print(6)
235 Removed: # This line required to reset behavior of sys.stdout
236 Removed: sys.stdout = sys.__stdout__
237 Removed: print('Successfully wrote to file {}'.format(full_path))
238 Removed: except IOError:
239 Removed: print(
240 Removed: 'Unable to write {} to specified directory.\n'.format(
241 Removed: file_name), 'Was the full path passed to the function?')
242 Removed: return None
243 Removed:
244 Removed:
245 Removed: def plot_geom(evaluator):
246 Removed: """This function plots analysis results over the airfoil's geometry."""
247 Removed: # Plot chord
248 Removed: x_chord = [0, evaluator.chord]
249 Removed: y_chord = [0, 0]
250 Removed: plt.plot(x_chord, y_chord, linewidth='1')
251 Removed: # Plot quarter chord
252 Removed: plt.plot(evaluator.chord / 4,
253 Removed: 0,
254 Removed: '.',
255 Removed: color='g',
256 Removed: markersize=24,
257 Removed: label='Quarter-chord')
258 Removed: # Plot airfoil surfaces
259 Removed: x = [0.98 * x for x in evaluator.airfoil.x]
260 Removed: y = [0.98 * z for z in evaluator.airfoil.z]
261 Removed: plt.fill(x, y, color='w', linewidth='1', fill=False)
262 Removed: x = [1.02 * x for x in evaluator.airfoil.x]
263 Removed: y = [1.02 * z for z in evaluator.airfoil.z]
264 Removed: plt.fill(x, y, color='b', linewidth='1', fill=False)
265 Removed:
266 Removed: # Plot spars
267 Removed: try:
268 Removed: for _ in range(len(evaluator.spar.x)):
269 Removed: x = (evaluator.spar.x[_])
270 Removed: y = (evaluator.spar.z[_])
271 Removed: plt.plot(x, y, '-', color='b')
272 Removed: except AttributeError:
273 Removed: print('No spars to plot.')
274 Removed: # Plot stringers
275 Removed: try:
276 Removed: for _ in range(0, len(evaluator.stringer.x)):
277 Removed: x = evaluator.stringer.x[_]
278 Removed: y = evaluator.stringer.z[_]
279 Removed: plt.plot(x, y, '.', color='y', markersize=12)
280 Removed: except AttributeError:
281 Removed: print('No stringers to plot.')
282 Removed:
283 Removed: # Plot centroid
284 Removed: x = evaluator.centroid[0]
285 Removed: y = evaluator.centroid[1]
286 Removed: plt.plot(x, y, '.', color='r', markersize=24, label='centroid')
287 Removed:
288 Removed: # Graph formatting
289 Removed: plt.xlabel('X axis')
290 Removed: plt.ylabel('Z axis')
291 Removed:
292 Removed: plot_bound = max(evaluator.airfoil.x)
293 Removed: plt.xlim(-0.10 * plot_bound, 1.10 * plot_bound)
294 Removed: plt.ylim(-(1.10 * plot_bound / 2), (1.10 * plot_bound / 2))
295 Removed: plt.gca().set_aspect('equal', adjustable='box')
296 Removed: plt.gca().legend()
297 Removed: plt.grid(axis='both', linestyle=':', linewidth=1)
298 Removed: plt.show()
299 Removed: return None
300 Removed:
301 Removed:
302 Removed: def plot_lift(evaluator):
303 Removed: x = range(evaluator.semi_span)
304 Removed: y_1 = evaluator.lift_rectangular
305 Removed: y_2 = evaluator.lift_elliptical
306 Removed: y_3 = evaluator.lift_total
307 Removed: plt.plot(x, y_1, '.', color='b', markersize=4, label='Rectangular lift')
308 Removed: plt.plot(x, y_2, '.', color='g', markersize=4, label='Elliptical lift')
309 Removed: plt.plot(x, y_3, '.', color='r', markersize=4, label='Total lift')
310 Removed:
311 Removed: # Graph formatting
312 Removed: plt.xlabel('Semi-span location')
313 Removed: plt.ylabel('Lift')
314 Removed:
315 Removed: plt.gca().legend()
316 Removed: plt.grid(axis='both', linestyle=':', linewidth=1)
317 Removed: plt.show()
318 Removed: return None
evaluator/__init__.py
index 00000000..1561fb0f 000000..100644
@@ -0,0 +1,1 @@
1 Added: from . import evaluator
evaluator/evaluator.py
index 00000000..d26ee133 000000..100644
@@ -0,0 +1,316 @@
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 on aircrafts.
17 Added: Individual aircrafts must claim an Evaluator object as parent."""
18 Added: def __init__(self):
19 Added: self.tree = {} # Keys are component names, values are objects
20 Added: self.results = []
21 Added: # # Evaluator knows all geometrical info from evaluated airfoil
22 Added: # self.airfoil = self.get_airfoil(aircraft)
23 Added: # self.spars = self.get_spars(aircraft)
24 Added: # self.stringers = self.get_stringers(aircraft)
25 Added: # # Lift
26 Added: # self.lift_rectangular = []
27 Added: # self.lift_elliptical = []
28 Added: # self.lift_total = []
29 Added: # # Drag
30 Added: # self.drag = []
31 Added: # # centroid
32 Added: # self.centroid = []
33 Added: # Inertia terms:
34 Added: self.I_ = {'x': 0, 'z': 0, 'xz': 0}
35 Added:
36 Added: def get_lift_rectangular(aircraft, lift):
37 Added: L_prime = [
38 Added: lift / (aircraft.semi_span * 2) for x in range(aircraft.semi_span)
39 Added: ]
40 Added: return L_prime
41 Added:
42 Added: def get_lift_elliptical(aircraft, L_0):
43 Added: L_prime = [
44 Added: L_0 / (aircraft.semi_span * 2) * sqrt(1 -
45 Added: (y / aircraft.semi_span)**2)
46 Added: for y in range(aircraft.semi_span)
47 Added: ]
48 Added: return L_prime
49 Added:
50 Added: def get_lift_total(aircraft):
51 Added: F_z = [(aircraft.lift_rectangular[_] + aircraft.lift_elliptical[_]) / 2
52 Added: for _ in range(len(aircraft.lift_rectangular))]
53 Added: return F_z
54 Added:
55 Added: def get_mass_distribution(self, total_mass):
56 Added: F_z = [total_mass / self.semi_span for x in range(0, self.semi_span)]
57 Added: return F_z
58 Added:
59 Added: def get_drag(self, drag):
60 Added: # Transform semi-span integer into list
61 Added: semi_span = [x for x in range(0, self.semi_span)]
62 Added:
63 Added: # Drag increases after 80% of the semi_span
64 Added: cutoff = round(0.8 * self.semi_span)
65 Added:
66 Added: # Drag increases by 25% after 80% of the semi_span
67 Added: F_x = [drag for x in semi_span[0:cutoff]]
68 Added: F_x.extend([1.25 * drag for x in semi_span[cutoff:]])
69 Added: return F_x
70 Added:
71 Added: def get_centroid(aircraft):
72 Added: """Return the coordinates of the centroid."""
73 Added: stringer_area = aircraft.stringer.area
74 Added: cap_area = aircraft.spar.cap_area
75 Added:
76 Added: caps_x = [value for spar in aircraft.spar.x for value in spar]
77 Added: caps_z = [value for spar in aircraft.spar.z for value in spar]
78 Added: stringers_x = aircraft.stringer.x
79 Added: stringers_z = aircraft.stringer.z
80 Added:
81 Added: denominator = float(
82 Added: len(caps_x) * cap_area + len(stringers_x) * stringer_area)
83 Added:
84 Added: centroid_x = float(
85 Added: sum([x * cap_area for x in caps_x]) +
86 Added: sum([x * stringer_area for x in stringers_x]))
87 Added: centroid_x = centroid_x / denominator
88 Added:
89 Added: centroid_z = float(
90 Added: sum([z * cap_area for z in caps_z]) +
91 Added: sum([z * stringer_area for z in stringers_z]))
92 Added: centroid_z = centroid_z / denominator
93 Added:
94 Added: return (centroid_x, centroid_z)
95 Added:
96 Added: def get_inertia_terms(self):
97 Added: """Obtain all inertia terms."""
98 Added: stringer_area = self.stringer.area
99 Added: cap_area = self.spar.cap_area
100 Added:
101 Added: # Adds upper and lower components' coordinates to list
102 Added: x_stringers = self.stringer.x
103 Added: z_stringers = self.stringer.z
104 Added: x_spars = self.spar.x[:][0] + self.spar.x[:][1]
105 Added: z_spars = self.spar.z[:][0] + self.spar.z[:][1]
106 Added: stringer_count = range(len(x_stringers))
107 Added: spar_count = range(len(self.spar.x))
108 Added:
109 Added: # I_x is the sum of the contributions of the spar caps and stringers
110 Added: # TODO: replace list indices with dictionary value
111 Added: I_x = sum([
112 Added: cap_area * (z_spars[i] - self.centroid[1])**2 for i in spar_count
113 Added: ])
114 Added: I_x += sum([
115 Added: stringer_area * (z_stringers[i] - self.centroid[1])**2
116 Added: for i in stringer_count
117 Added: ])
118 Added:
119 Added: I_z = sum([
120 Added: cap_area * (x_spars[i] - self.centroid[0])**2 for i in spar_count
121 Added: ])
122 Added: I_z += sum([
123 Added: stringer_area * (x_stringers[i] - self.centroid[0])**2
124 Added: for i in stringer_count
125 Added: ])
126 Added:
127 Added: I_xz = sum([
128 Added: cap_area * (x_spars[i] - self.centroid[0]) *
129 Added: (z_spars[i] - self.centroid[1]) for i in spar_count
130 Added: ])
131 Added: I_xz += sum([
132 Added: stringer_area * (x_stringers[i] - self.centroid[0]) *
133 Added: (z_stringers[i] - self.centroid[1]) for i in stringer_count
134 Added: ])
135 Added: return (I_x, I_z, I_xz)
136 Added:
137 Added: def get_dx(self, component):
138 Added: return [x - self.centroid[0] for x in component.x_start]
139 Added:
140 Added: def get_dz(self, component):
141 Added: return [x - self.centroid[1] for x in component.x_start]
142 Added:
143 Added: def get_dP(self, xDist, zDist, V_x, V_z, area):
144 Added: I_x = self.I_['x']
145 Added: I_z = self.I_['z']
146 Added: I_xz = self.I_['xz']
147 Added: denom = float(I_x * I_z - I_xz**2)
148 Added: z = float()
149 Added: for _ in range(len(xDist)):
150 Added: z += float(-area * xDist[_] * (I_x * V_x - I_xz * V_z) / denom -
151 Added: area * zDist[_] * (I_z * V_z - I_xz * V_x) / denom)
152 Added: return z
153 Added:
154 Added: # def analysis(self, V_x, V_z):
155 Added: # """Perform all analysis calculations and store in class instance."""
156 Added:
157 Added: # self.drag = self.get_drag(10)
158 Added: # self.lift_rectangular = self.get_lift_rectangular(13.7)
159 Added: # self.lift_elliptical = self.get_lift_elliptical(15)
160 Added: # self.lift_total = self.get_lift_total()
161 Added: # self.mass_dist = self.get_mass_distribution(self.mass_total)
162 Added: # self.centroid = self.get_centroid()
163 Added: # self.I_['x'] = self.get_inertia_terms()[0]
164 Added: # self.I_['z'] = self.get_inertia_terms()[1]
165 Added: # self.I_['xz'] = self.get_inertia_terms()[2]
166 Added: # spar_dx = self.get_dx(self.spar)
167 Added: # spar_dz = self.get_dz(self.spar)
168 Added: # self.spar.dP_x = self.get_dP(spar_dx, spar_dz, V_x, 0,
169 Added: # self.spar.cap_area)
170 Added: # self.spar.dP_z = self.get_dP(spar_dx, spar_dz, 0, V_z,
171 Added: # self.spar.cap_area)
172 Added: # print("yayyyyy")
173 Added: # return None
174 Added:
175 Added: def update(self):
176 Added: """Refresh evaluator aircraft tree."""
177 Added: print(self.tree)
178 Added:
179 Added: # self.results.append(self.analysis(aircraft))
180 Added:
181 Added: def analysis(self, aircraft):
182 Added: """Perform all analysis calculations and store in class instance."""
183 Added:
184 Added: results = {
185 Added: "Lift": self.get_lift_total,
186 Added: "Drag": self.get_drag,
187 Added: "Centroid": self.get_centroid
188 Added: }
189 Added:
190 Added: # print(f"Analysis results for {aircraft.name}:\n", results)
191 Added: return (results)
192 Added: # self.results = self.get_lift_total(aircraft)
193 Added:
194 Added: # self.drag = self.get_drag(10)
195 Added: # self.lift_rectangular = self.get_lift_rectangular(13.7)
196 Added: # self.lift_elliptical = self.get_lift_elliptical(15)
197 Added: # self.lift_total = self.get_lift_total()
198 Added: # self.mass_dist = self.get_mass_distribution(self.mass_total)
199 Added: # self.centroid = self.get_centroid()
200 Added: # self.I_['x'] = self.get_inertia_terms()[0]
201 Added: # self.I_['z'] = self.get_inertia_terms()[1]
202 Added: # self.I_['xz'] = self.get_inertia_terms()[2]
203 Added: # spar_dx = self.get_dx(self.spar)
204 Added: # spar_dz = self.get_dz(self.spar)
205 Added: # self.spar.dP_x = self.get_dP(spar_dx, spar_dz, V_x, 0,
206 Added: # self.spar.cap_area)
207 Added: # self.spar.dP_z = self.get_dP(spar_dx, spar_dz, 0, V_z,
208 Added: # self.spar.cap_area)
209 Added: return None
210 Added:
211 Added: def info_print(self, round):
212 Added: """Print all the component's evaluated data to the terminal."""
213 Added: name = f' {print(self)} DATA FOR {str(self).upper()} '
214 Added: num_of_dashes = len(name)
215 Added: print(num_of_dashes * '-')
216 Added: print(name)
217 Added: for k, v in self.__dict__.items():
218 Added: if type(v) != list:
219 Added: print('{}:\n'.format(k), v)
220 Added: print(num_of_dashes * '-')
221 Added: for k, v in self.__dict__.items():
222 Added: if type(v) == list:
223 Added: print('{}:\n'.format(k), np.around(v, round))
224 Added: return None
225 Added:
226 Added: def info_save(self, save_path, number):
227 Added: """Save all the object's coordinates (must be full path)."""
228 Added: file_name = 'airfoil_{}_eval.txt'.format(number)
229 Added: full_path = os.path.join(save_path, file_name)
230 Added: try:
231 Added: with open(full_path, 'w') as sys.stdout:
232 Added: self.info_print(6)
233 Added: # This line required to reset behavior of sys.stdout
234 Added: sys.stdout = sys.__stdout__
235 Added: print('Successfully wrote to file {}'.format(full_path))
236 Added: except IOError:
237 Added: print(
238 Added: 'Unable to write {} to specified directory.\n'.format(
239 Added: file_name), 'Was the full path passed to the function?')
240 Added: return None
241 Added:
242 Added:
243 Added: def plot_geom(evaluator):
244 Added: """This function plots analysis results over the airfoil's geometry."""
245 Added: # Plot chord
246 Added: x_chord = [0, evaluator.chord]
247 Added: y_chord = [0, 0]
248 Added: plt.plot(x_chord, y_chord, linewidth='1')
249 Added: # Plot quarter chord
250 Added: plt.plot(evaluator.chord / 4,
251 Added: 0,
252 Added: '.',
253 Added: color='g',
254 Added: markersize=24,
255 Added: label='Quarter-chord')
256 Added: # Plot airfoil surfaces
257 Added: x = [0.98 * x for x in evaluator.airfoil.x]
258 Added: y = [0.98 * z for z in evaluator.airfoil.z]
259 Added: plt.fill(x, y, color='w', linewidth='1', fill=False)
260 Added: x = [1.02 * x for x in evaluator.airfoil.x]
261 Added: y = [1.02 * z for z in evaluator.airfoil.z]
262 Added: plt.fill(x, y, color='b', linewidth='1', fill=False)
263 Added:
264 Added: # Plot spars
265 Added: try:
266 Added: for _ in range(len(evaluator.spar.x)):
267 Added: x = (evaluator.spar.x[_])
268 Added: y = (evaluator.spar.z[_])
269 Added: plt.plot(x, y, '-', color='b')
270 Added: except AttributeError:
271 Added: print('No spars to plot.')
272 Added: # Plot stringers
273 Added: try:
274 Added: for _ in range(0, len(evaluator.stringer.x)):
275 Added: x = evaluator.stringer.x[_]
276 Added: y = evaluator.stringer.z[_]
277 Added: plt.plot(x, y, '.', color='y', markersize=12)
278 Added: except AttributeError:
279 Added: print('No stringers to plot.')
280 Added:
281 Added: # Plot centroid
282 Added: x = evaluator.centroid[0]
283 Added: y = evaluator.centroid[1]
284 Added: plt.plot(x, y, '.', color='r', markersize=24, label='centroid')
285 Added:
286 Added: # Graph formatting
287 Added: plt.xlabel('X axis')
288 Added: plt.ylabel('Z axis')
289 Added:
290 Added: plot_bound = max(evaluator.airfoil.x)
291 Added: plt.xlim(-0.10 * plot_bound, 1.10 * plot_bound)
292 Added: plt.ylim(-(1.10 * plot_bound / 2), (1.10 * plot_bound / 2))
293 Added: plt.gca().set_aspect('equal', adjustable='box')
294 Added: plt.gca().legend()
295 Added: plt.grid(axis='both', linestyle=':', linewidth=1)
296 Added: plt.show()
297 Added: return None
298 Added:
299 Added:
300 Added: def plot_lift(evaluator):
301 Added: x = range(evaluator.semi_span)
302 Added: y_1 = evaluator.lift_rectangular
303 Added: y_2 = evaluator.lift_elliptical
304 Added: y_3 = evaluator.lift_total
305 Added: plt.plot(x, y_1, '.', color='b', markersize=4, label='Rectangular lift')
306 Added: plt.plot(x, y_2, '.', color='g', markersize=4, label='Elliptical lift')
307 Added: plt.plot(x, y_3, '.', color='r', markersize=4, label='Total lift')
308 Added:
309 Added: # Graph formatting
310 Added: plt.xlabel('Semi-span location')
311 Added: plt.ylabel('Lift')
312 Added:
313 Added: plt.gca().legend()
314 Added: plt.grid(axis='both', linestyle=':', linewidth=1)
315 Added: plt.show()
316 Added: return None
example_airfoil.py
index e559bb74..aa1a5f01 100644..100644
@@ -11,7 +11,7 @@
11 11
12 12 import resources.materials as mt
13 13 import creator
14 Removed: import evaluator
14 Added: import evaluator.evaluator as evaluator
15 15 import generator
16 16 # from generator import
17 17
@@ -63,7 +63,6 @@
63 63 spar4 = creator.wing.Spar(af2, 'spar4', 0.67)
64 64
65 65 eval.update()
66 Removed: # print("spar2 parent is:", af.parent)
67 66 # eval.info_print(2)
68 67
69 68 # # Create stringer instance