summaryrefslogtreecommitdiff
path: root/creator.py
diff options
context:
space:
mode:
Diffstat (limited to 'creator.py')
-rw-r--r--creator.py185
1 files changed, 73 insertions, 112 deletions
diff --git a/creator.py b/creator.py
index 3e36036..eaf4d68 100644
--- a/creator.py
+++ b/creator.py
@@ -12,19 +12,20 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
"""
-The 'creator' module contains class definitions for coordinates
-and various components we add to an airfoil (spars, stringers, and ribs.)
+The creator.py module contains class definitions for coordinates
+and various components we add to an airfoil (spars, stringers, and ribs).
Classes:
- Coordinates: always instantiated first, but never assigned to object.
- Airfoil: inherits from Coordinates & automatically aware of airfoil size.
- Spar: also inherits from Coordinates.
- Stringer: also inherits from Coordinates.
+ Airfoil: instantiated with class method to provide coordinates to heirs.
+ Spar: inherits from Airfoil.
+ Stringer: also inherits from Airfoil.
Functions:
plot_geom(airfoil): generates a 2D plot of the airfoil & any components.
"""
+
import sys
import os.path
import numpy as np
@@ -33,32 +34,25 @@ import bisect as bi
import matplotlib.pyplot as plt
-# This variable is required for main.py constant wing dimensions
-# to be passed to inheriting classes (Airfoil, Spar, Stringer, Rib).
-# This way, we don't have to redeclare our coordinates as parameters for
-# our spars, stringers and ribs. This makes for more elegant code.
-global parent
-
-
-class Coordinates:
+class Airfoil:
"""
- All airfoil components need the following:
-
- Parameters:
- Component material
- Coordinates relative to the chord & semi-span
+ This class represents a single NACA airfoil.
- Methods:
- Print component coordinates
- Save component coordinates to file specified in main.py
+ Please note: the coordinates are saved as two lists
+ for the x- and z-coordinates. The coordinates start at
+ the leading edge, travel over the airfoil's upper edge,
+ then loop back to the leading edge via the lower edge.
- So, all component classes inherit from class Coordinates.
+ This method was chosen for easier future exports
+ to 3D CAD packages like SolidWorks, which can import such
+ geometry as coordinates written in a CSV file.
"""
- def __init__(self, chord, semi_span):
- # Global dimensions
- self.chord = chord if chord > 40 else 40
- self.semi_span = semi_span
+ # Defaults
+ chord = 100
+ semi_span = 200
+
+ def __init__(self):
# mass and area
self.mass = float()
self.area = float()
@@ -68,79 +62,18 @@ class Coordinates:
self.x = []
self.z = []
- # The airfoil components know the Coordinates instance's coords
- global parent
- parent = self
+ @classmethod
+ def from_dimensions(cls, chord, semi_span):
+ cls.chord = chord
+ cls.semi_span = semi_span
+ return Airfoil()
def __str__(self):
return type(self).__name__
- def info_print(self, round):
- """
- Print all the component's coordinates to the terminal.
-
- This function's output is piped to the 'save_coord' function below.
- """
- name = ' CREATOR DATA '
- num_of_dashes = len(name)
-
- print(num_of_dashes * '-')
- print(name)
- print('Component:', str(self))
- print('Chord length:', self.chord)
- print('Semi-span:', self.semi_span)
- print('Mass:', self.mass)
- print(num_of_dashes * '-')
- print('x-coordinates:\n', np.around(self.x, round))
- print('z-coordinates:\n', np.around(self.z, round))
- return None
-
- def info_save(self, save_path, number):
- """
- Save all the object's coordinates (must be full path).
- """
- file_name = '{}_{}.txt'.format(str(self).lower(), number)
- full_path = os.path.join(save_path, file_name)
- try:
- with open(full_path, 'w') as sys.stdout:
- self.info_print(6)
- # 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
-
-
-class Airfoil(Coordinates):
- """
- This class represents a single NACA airfoil.
-
- Please note: the coordinates are saved as two lists
- for the x- and z-coordinates. The coordinates start at
- the leading edge, travel over the airfoil's upper edge,
- then loop back to the leading edge via the lower edge.
-
- This method was chosen for easier future exports
- to 3D CAD packages like SolidWorks, which can import such
- geometry as coordinates written in a CSV file.
- """
-
- def __init__(self):
- global parent
- # Run 'Coordinates' super class init method with same chord & 1/2 span.
- super().__init__(parent.chord, parent.semi_span)
- # NACA number
- self.naca_num = int()
- # Mean camber line
- self.x_c = []
- self.z_c = []
-
def add_naca(self, naca_num):
"""
- This function generates geometry for our chosen NACA airfoil shape.
+ This function generates geometry for a NACA number passed as argument.
The nested functions perform the required steps to generate geometry,
and can be called to solve the geometry y-coordinate for any 'x' input.
Equation coefficients were retrieved from Wikipedia.org.
@@ -214,6 +147,8 @@ class Airfoil(Coordinates):
x_chord_rev.extend(extend)
# Generate our airfoil geometry from previous sub-functions.
+ self.x_c = []
+ self.z_c = []
for x in x_chord:
self.x_c.append(x)
self.z_c.append(get_camber(x))
@@ -228,27 +163,56 @@ class Airfoil(Coordinates):
self.mass = mass
def info_print(self, round):
- super().info_print(round)
- print('x_c the camber x-coordinates:\n', np.around(self.x_c, round))
- print('z_c the camber z-coordinates:\n', np.around(self.z_c, round))
+ """
+ Print all the component's coordinates to the terminal.
+
+ This function's output is piped to the 'save_coord' function below.
+ """
+
+ name = ' CREATOR DATA '
+ num_of_dashes = len(name)
+
+ print(num_of_dashes * '-')
+ print(name)
+ print('Component:', str(self))
+ print('Chord length:', self.chord)
+ print('Semi-span:', self.semi_span)
+ print('Mass:', self.mass)
+ print(num_of_dashes * '-')
+ print('x-coordinates:\n', np.around(self.x, round))
+ print('z-coordinates:\n', np.around(self.z, round))
+ return None
+
+ def info_save(self, save_path, number):
+ """
+ Save all the object's coordinates (must be full path).
+ """
+
+ file_name = '{}_{}.txt'.format(str(self).lower(), number)
+ full_path = os.path.join(save_path, file_name)
+ try:
+ with open(full_path, 'w') as sys.stdout:
+ self.info_print(6)
+ # 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
-class Spar(Coordinates):
+class Spar(Airfoil):
"""Contains a single spar's location."""
- global parent
def __init__(self):
- super().__init__(parent.chord, parent.semi_span)
+ super().__init__()
self.x_start = []
self.x_end = []
self.thickness = float()
self.z_start = []
self.z_end = []
- self.dx = float()
- self.dz = float()
- self.dP_x = float()
- self.dP_z = float()
def add_coord(self, airfoil, x_loc_percent):
"""
@@ -261,6 +225,7 @@ class Spar(Coordinates):
Return:
None
"""
+
# Scaled spar location with regards to chord
loc = x_loc_percent * self.chord
# bi.bisect_left: returns index of first value in airfoil.x > loc
@@ -296,22 +261,17 @@ class Spar(Coordinates):
return None
-class Stringer(Coordinates):
+class Stringer(Airfoil):
"""Contains the coordinates of all stringers."""
- global parent
def __init__(self):
- super().__init__(parent.chord, parent.semi_span)
+ super().__init__()
self.x_start = []
self.x_end = []
self.thickness = float()
self.z_start = []
self.z_end = []
self.area = float()
- # self.dx = float()
- # self.dz = float()
- # self.dP_x = float()
- # self.dP_z = float()
def add_coord(self, airfoil,
stringer_u_1, stringer_u_2,
@@ -331,6 +291,7 @@ class Stringer(Coordinates):
Returns:
None
"""
+
# Find distance between leading edge and first upper stringer
interval = airfoil.spar.x[0][0] / (stringer_u_1 + 1)
# initialise first self.stringer_x at first interval
@@ -399,6 +360,7 @@ class Stringer(Coordinates):
def plot_geom(airfoil):
"""This function plots the airfoil's + sub-components' geometry."""
+
# Plot chord
x_chord = [0, airfoil.chord]
y_chord = [0, 0]
@@ -432,7 +394,6 @@ def plot_geom(airfoil):
# Graph formatting
plt.xlabel('X axis')
plt.ylabel('Z axis')
-
plot_bound = max(airfoil.x)
plt.xlim(- 0.10 * plot_bound, 1.10 * plot_bound)
plt.ylim(- (1.10 * plot_bound / 2), (1.10 * plot_bound / 2))
Copyright 2019--2024 Marius PETER