View raw

1 """ 2 The evaluator.py module contains functions 3 that return calculated data for an aircraft. 4 Plotting aircraft components is also possible. 5 """ 6 7 import os.path 8 import concurrent.futures 9 import matplotlib.pyplot as plt 10 11 from . import drag, inertia, lift, mass 12 13 14 def analyze(aircraft): 15 """Analyze a single aircraft.""" 16 results = { 17 'Lift': lift.get_lift_total(aircraft), 18 'Drag': drag.get_drag_total(aircraft), 19 'Mass': mass.get_mass_total(aircraft), 20 'Centroid': inertia.get_centroid(aircraft) 21 } 22 aircraft.results = results 23 return aircraft.name, results 24 25 26 def analyze_all(population): 27 """Analyze all aircraft in a given population.""" 28 # for aircraft in population.aircrafts: 29 # print(analyze(aircraft)) 30 with concurrent.futures.ProcessPoolExecutor() as executor: 31 results = executor.map(analyze, population.aircrafts) 32 for result in results: 33 print(result) 34 return None 35 36 # def analysis(self, V_x, V_z): 37 # """Perform all analysis calculations and store in class instance.""" 38 39 # self.drag = self.get_drag(10) 40 # self.lift_rectangular = self.get_lift_rectangular(13.7) 41 # self.lift_elliptical = self.get_lift_elliptical(15) 42 # self.lift_total = self.get_lift_total() 43 # self.mass_dist = self.get_mass_distribution(self.mass_total) 44 # self.centroid = self.get_centroid() 45 # self.I_['x'] = self.get_inertia_terms()[0] 46 # self.I_['z'] = self.get_inertia_terms()[1] 47 # self.I_['xz'] = self.get_inertia_terms()[2] 48 # spar_dx = self.get_dx(self.spar) 49 # spar_dz = self.get_dz(self.spar) 50 # self.spar.dP_x = self.get_dP(spar_dx, spar_dz, V_x, 0, 51 # self.spar.cap_area) 52 # self.spar.dP_z = self.get_dP(spar_dx, spar_dz, 0, V_z, 53 # self.spar.cap_area) 54 # print("yayyyyy") 55 # return None 56 57 # print(f"Analysis results for {aircraft.name}:\n", results) 58 # self.results = self.get_lift_total(aircraft) 59 60 # self.drag = self.get_drag(10) 61 # self.lift_rectangular = self.get_lift_rectangular(13.7) 62 # self.lift_elliptical = self.get_lift_elliptical(15) 63 # self.lift_total = self.get_lift_total() 64 # self.mass_dist = self.get_mass_distribution(self.mass_total) 65 # self.centroid = self.get_centroid() 66 # self.I_['x'] = self.get_inertia_terms()[0] 67 # self.I_['z'] = self.get_inertia_terms()[1] 68 # self.I_['xz'] = self.get_inertia_terms()[2] 69 # spar_dx = self.get_dx(self.spar) 70 # spar_dz = self.get_dz(self.spar) 71 # self.spar.dP_x = self.get_dP(spar_dx, spar_dz, V_x, 0, 72 # self.spar.cap_area) 73 # self.spar.dP_z = self.get_dP(spar_dx, spar_dz, 0, V_z, 74 # self.spar.cap_area) 75 # return None 76 77 def tree_print(self, population): 78 """Print the list of subcomponents.""" 79 name = f" TREE FOR {[i.name for i in population.aircraft]} IN {self.name} " 80 num_of_dashes = len(name) 81 print(num_of_dashes * '-') 82 print(name) 83 for aircraft in population: 84 print(".") 85 print(f"`-- {aircraft}") 86 print(f" |--{aircraft.wing}") 87 print(f" | |-- {aircraft.wing.stringers}") 88 for spar in aircraft.wing.spars[:-1]: 89 print(f" | |-- {spar}") 90 print(f" | `-- {aircraft.wing.spars[-1]}") 91 print(f" |-- {aircraft.fuselage}") 92 print(f" `-- {aircraft.propulsion}") 93 print(num_of_dashes * '-') 94 return None 95 96 def tree_save(self, 97 population, 98 save_path='/home/blendux/Projects/Aircraft_Studio/save'): 99 """Save the evaluator's tree to a file.""" 100 for aircraft in population.aircraft: 101 file_name = f"{aircraft.name}_tree.txt" 102 full_path = os.path.join(save_path, file_name) 103 with open(full_path, 'w') as f: 104 try: 105 f.write(".\n") 106 f.write(f"`-- {aircraft}\n") 107 f.write(f" |--{aircraft.wing}\n") 108 for spar in aircraft.wing.spars[:-1]: 109 f.write(f" | |-- {spar}\n") 110 f.write(f" | `-- {aircraft.wing.spars[-1]}\n") 111 f.write(f" |-- {aircraft.fuselage}\n") 112 f.write(f" `-- {aircraft.propulsion}\n") 113 logging.debug(f'Successfully wrote to file {full_path}') 114 115 except IOError: 116 print( 117 f'Unable to write {file_name} to specified directory.', 118 'Was the full path passed to the function?') 119 return None 120 121 122 def plot_geom(evaluator): 123 """This function plots analysis results over the airfoil's geometry.""" 124 # Plot chord 125 x_chord = [0, evaluator.chord] 126 y_chord = [0, 0] 127 plt.plot(x_chord, y_chord, linewidth='1') 128 # Plot quarter chord 129 plt.plot(evaluator.chord / 4, 130 0, 131 '.', 132 color='g', 133 markersize=24, 134 label='Quarter-chord') 135 # Plot airfoil surfaces 136 x = [0.98 * x for x in evaluator.airfoil.x] 137 y = [0.98 * z for z in evaluator.airfoil.z] 138 plt.fill(x, y, color='w', linewidth='1', fill=False) 139 x = [1.02 * x for x in evaluator.airfoil.x] 140 y = [1.02 * z for z in evaluator.airfoil.z] 141 plt.fill(x, y, color='b', linewidth='1', fill=False) 142 143 # Plot spars 144 try: 145 for _ in range(len(evaluator.spar.x)): 146 x = (evaluator.spar.x[_]) 147 y = (evaluator.spar.z[_]) 148 plt.plot(x, y, '-', color='b') 149 except AttributeError: 150 print('No spars to plot.') 151 # Plot stringers 152 try: 153 for _ in range(0, len(evaluator.stringer.x)): 154 x = evaluator.stringer.x[_] 155 y = evaluator.stringer.z[_] 156 plt.plot(x, y, '.', color='y', markersize=12) 157 except AttributeError: 158 print('No stringers to plot.') 159 160 # Plot centroid 161 x = evaluator.centroid[0] 162 y = evaluator.centroid[1] 163 plt.plot(x, y, '.', color='r', markersize=24, label='centroid') 164 165 # Graph formatting 166 plt.xlabel('X axis') 167 plt.ylabel('Z axis') 168 169 plot_bound = max(evaluator.airfoil.x) 170 plt.xlim(-0.10 * plot_bound, 1.10 * plot_bound) 171 plt.ylim(-(1.10 * plot_bound / 2), (1.10 * plot_bound / 2)) 172 plt.gca().set_aspect('equal', adjustable='box') 173 plt.gca().legend() 174 plt.grid(axis='both', linestyle=':', linewidth=1) 175 plt.show() 176 return None 177 178 179 def plot_lift(evaluator): 180 x = range(evaluator.semi_span) 181 y_1 = evaluator.lift_rectangular 182 y_2 = evaluator.lift_elliptical 183 y_3 = evaluator.lift_total 184 plt.plot(x, y_1, '.', color='b', markersize=4, label='Rectangular lift') 185 plt.plot(x, y_2, '.', color='g', markersize=4, label='Elliptical lift') 186 plt.plot(x, y_3, '.', color='r', markersize=4, label='Total lift') 187 188 # Graph formatting 189 plt.xlabel('Semi-span location') 190 plt.ylabel('Lift') 191 192 plt.gca().legend() 193 plt.grid(axis='both', linestyle=':', linewidth=1) 194 plt.show() 195 return None 196