""" The evaluator.py module contains functions that return calculated data for an aircraft. Plotting aircraft components is also possible. """ import os.path import concurrent.futures import matplotlib.pyplot as plt from . import drag, inertia, lift, mass def analyze(aircraft): """Analyze a single aircraft.""" results = { 'Lift': lift.get_lift_total(aircraft), 'Drag': drag.get_drag_total(aircraft), 'Mass': mass.get_mass_total(aircraft), 'Centroid': inertia.get_centroid(aircraft) } aircraft.results = results return aircraft.name, results def analyze_all(population): """Analyze all aircraft in a given population.""" # for aircraft in population.aircrafts: # print(analyze(aircraft)) with concurrent.futures.ProcessPoolExecutor() as executor: results = executor.map(analyze, population.aircrafts) for result in results: print(result) return None # def analysis(self, V_x, V_z): # """Perform all analysis calculations and store in class instance.""" # self.drag = self.get_drag(10) # self.lift_rectangular = self.get_lift_rectangular(13.7) # self.lift_elliptical = self.get_lift_elliptical(15) # self.lift_total = self.get_lift_total() # self.mass_dist = self.get_mass_distribution(self.mass_total) # self.centroid = self.get_centroid() # self.I_['x'] = self.get_inertia_terms()[0] # self.I_['z'] = self.get_inertia_terms()[1] # self.I_['xz'] = self.get_inertia_terms()[2] # spar_dx = self.get_dx(self.spar) # spar_dz = self.get_dz(self.spar) # self.spar.dP_x = self.get_dP(spar_dx, spar_dz, V_x, 0, # self.spar.cap_area) # self.spar.dP_z = self.get_dP(spar_dx, spar_dz, 0, V_z, # self.spar.cap_area) # print("yayyyyy") # return None # print(f"Analysis results for {aircraft.name}:\n", results) # self.results = self.get_lift_total(aircraft) # self.drag = self.get_drag(10) # self.lift_rectangular = self.get_lift_rectangular(13.7) # self.lift_elliptical = self.get_lift_elliptical(15) # self.lift_total = self.get_lift_total() # self.mass_dist = self.get_mass_distribution(self.mass_total) # self.centroid = self.get_centroid() # self.I_['x'] = self.get_inertia_terms()[0] # self.I_['z'] = self.get_inertia_terms()[1] # self.I_['xz'] = self.get_inertia_terms()[2] # spar_dx = self.get_dx(self.spar) # spar_dz = self.get_dz(self.spar) # self.spar.dP_x = self.get_dP(spar_dx, spar_dz, V_x, 0, # self.spar.cap_area) # self.spar.dP_z = self.get_dP(spar_dx, spar_dz, 0, V_z, # self.spar.cap_area) # return None def tree_print(self, population): """Print the list of subcomponents.""" name = f" TREE FOR {[i.name for i in population.aircraft]} IN {self.name} " num_of_dashes = len(name) print(num_of_dashes * '-') print(name) for aircraft in population: print(".") print(f"`-- {aircraft}") print(f" |--{aircraft.wing}") print(f" | |-- {aircraft.wing.stringers}") for spar in aircraft.wing.spars[:-1]: print(f" | |-- {spar}") print(f" | `-- {aircraft.wing.spars[-1]}") print(f" |-- {aircraft.fuselage}") print(f" `-- {aircraft.propulsion}") print(num_of_dashes * '-') return None def tree_save(self, population, save_path='/home/blendux/Projects/Aircraft_Studio/save'): """Save the evaluator's tree to a file.""" for aircraft in population.aircraft: file_name = f"{aircraft.name}_tree.txt" full_path = os.path.join(save_path, file_name) with open(full_path, 'w') as f: try: f.write(".\n") f.write(f"`-- {aircraft}\n") f.write(f" |--{aircraft.wing}\n") for spar in aircraft.wing.spars[:-1]: f.write(f" | |-- {spar}\n") f.write(f" | `-- {aircraft.wing.spars[-1]}\n") f.write(f" |-- {aircraft.fuselage}\n") f.write(f" `-- {aircraft.propulsion}\n") logging.debug(f'Successfully wrote to file {full_path}') except IOError: print( f'Unable to write {file_name} to specified directory.', 'Was the full path passed to the function?') return None def plot_geom(evaluator): """This function plots analysis results over the airfoil's geometry.""" # Plot chord x_chord = [0, evaluator.chord] y_chord = [0, 0] plt.plot(x_chord, y_chord, linewidth='1') # Plot quarter chord plt.plot(evaluator.chord / 4, 0, '.', color='g', markersize=24, label='Quarter-chord') # Plot airfoil surfaces x = [0.98 * x for x in evaluator.airfoil.x] y = [0.98 * z for z in evaluator.airfoil.z] plt.fill(x, y, color='w', linewidth='1', fill=False) x = [1.02 * x for x in evaluator.airfoil.x] y = [1.02 * z for z in evaluator.airfoil.z] plt.fill(x, y, color='b', linewidth='1', fill=False) # Plot spars try: for _ in range(len(evaluator.spar.x)): x = (evaluator.spar.x[_]) y = (evaluator.spar.z[_]) plt.plot(x, y, '-', color='b') except AttributeError: print('No spars to plot.') # Plot stringers try: for _ in range(0, len(evaluator.stringer.x)): x = evaluator.stringer.x[_] y = evaluator.stringer.z[_] plt.plot(x, y, '.', color='y', markersize=12) except AttributeError: print('No stringers to plot.') # Plot centroid x = evaluator.centroid[0] y = evaluator.centroid[1] plt.plot(x, y, '.', color='r', markersize=24, label='centroid') # Graph formatting plt.xlabel('X axis') plt.ylabel('Z axis') plot_bound = max(evaluator.airfoil.x) plt.xlim(-0.10 * plot_bound, 1.10 * plot_bound) plt.ylim(-(1.10 * plot_bound / 2), (1.10 * plot_bound / 2)) plt.gca().set_aspect('equal', adjustable='box') plt.gca().legend() plt.grid(axis='both', linestyle=':', linewidth=1) plt.show() return None def plot_lift(evaluator): x = range(evaluator.semi_span) y_1 = evaluator.lift_rectangular y_2 = evaluator.lift_elliptical y_3 = evaluator.lift_total plt.plot(x, y_1, '.', color='b', markersize=4, label='Rectangular lift') plt.plot(x, y_2, '.', color='g', markersize=4, label='Elliptical lift') plt.plot(x, y_3, '.', color='r', markersize=4, label='Total lift') # Graph formatting plt.xlabel('Semi-span location') plt.ylabel('Lift') plt.gca().legend() plt.grid(axis='both', linestyle=':', linewidth=1) plt.show() return None