diff options
| -rw-r--r-- | creator.py | 1 | ||||
| -rw-r--r-- | evaluator.py | 171 | ||||
| -rw-r--r-- | main.py | 21 | 
3 files changed, 125 insertions, 68 deletions
| @@ -75,6 +75,7 @@ class Coordinates:          This function's output is piped to the 'save_coord' function below.          """          print('============================') +        print('        CREATOR DATA        ')          print('Component:', str(self))          print('Chord length:', self.chord)          print('Semi-span:', self.semi_span) diff --git a/evaluator.py b/evaluator.py index 2b61348..6965895 100644 --- a/evaluator.py +++ b/evaluator.py @@ -13,60 +13,129 @@  # You should have received a copy of the GNU General Public License  # along with this program.  If not, see <https://www.gnu.org/licenses/>. +import sys +import os.path +import numpy as np  from math import sin, cos, atan, sqrt -def get_total_mass(*component): -    total_mass = float() -    for _ in component: -        total_mass += _.mass -    return total_mass +class Airfoil: +    '''Performs structural evaluations for the airfoil passed as argument.''' + +    def __init__(self, airfoil): +        self.airfoil = airfoil +        # Global dimensions +        self.chord = airfoil.chord +        self.semi_span = airfoil.semi_span +        # mass and area +        self.mass_total = float() +        self.mass_dist = [] + +        self.lift_rectangular = [] +        self.lift_elliptical = [] +        self.lift = [] + +        self.drag = [] + +    def __str__(self): +        return type(self).__name__ + +    def print_info(self, round): +        """ +        Print all the component's evaluated data to the terminal. + +        This function's output is piped to the 'save_data' function below. +        """ +        print('============================') +        print('       EVALUATOR DATA       ') +        print('Evaluating:', str(self.airfoil)) +        print('Chord length:', self.chord) +        print('Semi-span:', self.semi_span) +        print('Total airfoil mass:', self.mass_total) +        print('============================') +        print('Rectangular lift:\n', np.around(self.lift_rectangular, round)) +        print('Elliptical lift:\n', np.around(self.lift_elliptical, round)) +        print('Combined lift:\n', np.around(self.lift, round)) +        print('Distribution of mass:\n', np.around(self.mass_dist, round)) +        print('Drag:\n', np.around(self.drag, round)) +        return None + +    def save_info(self, save_dir_path, number): +        """ +        Save all the object's coordinates (must be full path). +        """ + +        file_name = '{}_{}.txt'.format(self, number) +        full_path = os.path.join(save_dir_path, file_name) +        try: +            with open(full_path, 'w') as sys.stdout: +                self.print_info(2) +                # This line required to reset behavior of sys.stdout +                sys.stdout = sys.__stdout__ +                print('Successfully wrote to file {}'.format(full_path)) +        except IOError: +            print('Unable to write {} to specified directory.\n' +                  .format(file_name), +                  'Was the full path passed to the function?') +        return None + +    def get_mass_total(airfoil): +        total_mass = airfoil.mass + airfoil.spar.mass + airfoil.stringer.mass +        return total_mass + +    # All these functions take integer arguments and return lists. + +    def get_lift_rectangular(airfoil, lift): +        L_prime = [lift / (airfoil.semi_span * 2) +                   for x in range(airfoil.semi_span)] +        return L_prime + +    def get_lift_elliptical(airfoil, L_0): +        L_prime = [L_0 * sqrt(1 - (y / airfoil.semi_span) ** 2) +                   for y in range(airfoil.semi_span)] +        return L_prime + +    def get_lift(rectangular, elliptical): +        F_z = [(rectangular[_] + elliptical[_]) / 2 +               for _ in range(len(rectangular))] +        return F_z + +    def get_mass_distribution(airfoil, total_mass): +        F_z = [total_mass / airfoil.semi_span +               for x in range(0, airfoil.semi_span)] +        return F_z + +    def get_drag(airfoil, drag): +        # Transform semi-span integer into list +        semi_span = [x for x in range(0, airfoil.semi_span)] + +        # Drag increases after 80% of the semi_span +        cutoff = round(0.8 * airfoil.semi_span) + +        # Drag increases by 25% after 80% of the semi_span +        F_x = [drag for x in semi_span[0:cutoff]] +        F_x.extend([1.25 * drag for x in semi_span[cutoff:]]) +        return F_x + +    def evaluate(self): +        self.drag = self.get_drag(self.airfoil, 10) + +        self.lift_rectangular = self.get_lift_rectangular(10) +        self.lift_elliptical = self.get_lift_elliptical(15) +        self.lift = self.get_lift(self.lift_rectangular, self.lift_elliptical) + +        self.mass_total = self.get_mass_total() +        self.mass_dist = self.get_mass_distribution(self.total_mass) +        return None + +# def get_centroid(airfoil): +#     area = airfoil.stringer.area +#     top_stringers = airfoil.stringer +#     bottom_stringers = +#     nose_top_stringers = +#     nose_bottom_stringers = +#     for _ in airfoil.stringer[1]: +#         centroid.x += - -# All these functions take integer arguments and return lists. - -def get_lift_rectangular(airfoil, lift): -    L_prime = [lift / (airfoil.semi_span * 2) -               for x in range(airfoil.semi_span)] -    return L_prime - - -def get_lift_elliptical(airfoil, L_0): -    L_prime = [L_0 * sqrt(1 - (y / airfoil.semi_span) ** 2) -               for y in range(airfoil.semi_span)] -    return L_prime - - -def get_lift(rectangular, elliptical): -    F_z = [(rectangular[_] + elliptical[_]) / 2 -           for _ in range(len(rectangular))] -    return F_z - - -def get_mass_distribution(airfoil, total_mass): -    F_z = [total_mass / airfoil.semi_span -           for x in range(0, airfoil.semi_span)] -    return F_z - - -def get_drag(airfoil, drag): -    # Transform semi-span integer into list -    semi_span = [x for x in range(0, airfoil.semi_span)] -    cutoff = round(0.8 * airfoil.semi_span) - -    F_x = [drag for x in semi_span[0:cutoff]] -    F_x.extend([1.25 * drag for x in semi_span[cutoff:]]) -    # for x in semi_span[cutoff:]: -    #     drag_distribution.append(1.25 * drag) -    return F_x - - -def get_centroid(airfoil): -    area = airfoil.stringer.area -    numerator = float() -    for _ in airfoil.stringer.x_u: -        numerator += _ * area -    for _ in airfoil.stringer.x_l: -        numerator += _ * area      # denominator      # z_c = @@ -76,21 +76,6 @@ def main():          af.stringer.add_mass(STRINGER_MASS)          # af.stringer.print_info(2) -        # print(evaluator.get_total_mass(af, af.spar, af.stringer)) -        drag = evaluator.get_drag(af, 10) - -        lift_rectangular = evaluator.get_lift_rectangular(af, 10) -        lift_elliptical = evaluator.get_lift_elliptical(af, 15) -        lift = evaluator.get_lift(lift_rectangular, lift_elliptical) - -        total_mass = evaluator.get_total_mass(af, af.spar, af.stringer) -        dist_mass = evaluator.get_mass_distribution(af, total_mass) -        print('rect', len(lift_rectangular)) -        print('ellipse', len(lift_elliptical)) -        print('lift', len(lift)) -        print(len(drag)) -        print(len(dist_mass)) -          # Plot components with matplotlib          # creator.plot(af, af.spar, af.stringer) @@ -99,8 +84,10 @@ def main():          # af.spar.save_info(SAVE_PATH, _)          # af.stringer.save_info(SAVE_PATH, _) -    # Evaluate previously created airfoil(s). -    # total_mass = evaluator.get_total_mass(af, af.spar, af.stringer) +    # evaluator.Airfoil instance contains the results of the airfoil analysis. +    # The analysis itself takes place in the evaluator.py module. +    eval = evaluator.Airfoil(af) +    eval.print_info(2)      # Print final execution time      print("--- %s seconds ---" % (time.time() - start_time)) | 
