Skip to content

Commit

Permalink
minor fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
annaivagnes committed Sep 14, 2023
1 parent d4940d0 commit 4ec5dce
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 60 deletions.
6 changes: 3 additions & 3 deletions bladex/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
"""
BladeX init
"""
__all__ = ['ProfileInterface', 'NacaProfile', 'CustomProfile', 'ReversePropeller',
'Blade', 'Shaft', 'Propeller', 'Deformation', 'ParamFile',
'RBF', 'reconstruct_f', 'scipy_bspline']
__all__ = ['ProfileInterface', 'NacaProfile', 'CustomProfile',
'ReversePropeller', 'Blade', 'Shaft', 'Propeller', 'Deformation',
'ParamFile', 'RBF', 'reconstruct_f', 'scipy_bspline']

from .meta import *
from .profile import ProfileInterface
Expand Down
4 changes: 2 additions & 2 deletions bladex/blade.py
Original file line number Diff line number Diff line change
Expand Up @@ -479,7 +479,7 @@ def plot(self, elev=None, azim=None, ax=None, outfile=None):
>>> blade_2.rotate(rot_angle_deg=72)
>>> fig = plt.figure()
>>> ax = fig.gca(projection=Axes3D.name)
>>> ax = fig.add_subplot(projection='3d')
>>> blade_1.plot(ax=ax)
>>> blade_2.plot(ax=ax)
Expand All @@ -504,7 +504,7 @@ def plot(self, elev=None, azim=None, ax=None, outfile=None):
ax = ax
else:
fig = plt.figure()
ax = fig.gca(projection=Axes3D.name)
ax = fig.add_subplot(projection='3d')
ax.set_aspect('auto')

for i in range(self.n_sections):
Expand Down
52 changes: 30 additions & 22 deletions bladex/profile/customprofile.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""
Derived module from profilebase.py to provide the airfoil coordinates for a general
profile. Input data can be:
Derived module from profilebase.py to provide the airfoil coordinates for a
general profile. Input data can be:
- the coordinates arrays;
- the chord percentages, the associated nondimensional camber and thickness,
the real values of chord lengths, camber and thickness associated to the
Expand All @@ -9,14 +9,13 @@

import numpy as np
from .profileinterface import ProfileInterface
from scipy.optimize import newton


class CustomProfile(ProfileInterface):
"""
Provide custom profile, given the airfoil coordinates or the airfoil parameters,
i.e. , chord percentages and length, nondimensional and maximum camber,
nondimensional and maximum thickness.
Provide custom profile, given the airfoil coordinates or the airfoil
parameters, i.e. , chord percentages and length, nondimensional and
maximum camber, nondimensional and maximum thickness.
If coordinates are directly given as input:
Expand All @@ -31,16 +30,19 @@ class CustomProfile(ProfileInterface):
If section parameters are given as input:
:param numpy.ndarray chord_perc: 1D array that contains the chord percentages
of an airfoil section for which camber and thickness are measured
:param numpy.ndarray camber_perc: 1D array that contains the camber percentage
of an airfoil section at all considered chord percentages. The percentage is
taken with respect to the section maximum camber
:param numpy.ndarray chord_perc: 1D array that contains the chord
percentages of an airfoil section for which camber and thickness are
measured
:param numpy.ndarray camber_perc: 1D array that contains the camber
percentage of an airfoil section at all considered chord percentages.
The percentage is taken with respect to the section maximum camber
:param numpy.ndarray thickness_perc: 1D array that contains the thickness
percentage of an airfoil section at all considered chord percentages.
The percentage is with respect to the section maximum thickness
:param float camber_max: the maximum camber at a certain airfoil section
:param float thickness_max: the maximum thickness at a certain airfoil section
:param float chord_len: the chord length at a certain airfoil section
:param float thickness_max: the maximum thickness at a certain airfoil
section
"""
def __init__(self, **kwargs):
super(CustomProfile, self).__init__()
Expand Down Expand Up @@ -71,12 +73,13 @@ def __init__(self, **kwargs):
else:
raise RuntimeError(
"""Input arguments should be the section coordinates
(xup, yup, xdown, ydown) or the section parameters (camber_perc, thickness_perc,
(xup, yup, xdown, ydown) or the section parameters
(camber_perc, thickness_perc,
camber_max, thickness_max, chord_perc).""")

def generate_parameters(self, convention='british'):
return super().generate_parameters(convention)

def generate_coordinates(self, convention='british'):
if convention == 'british':
self._compute_coordinates_british_convention()
Expand All @@ -94,7 +97,7 @@ def _compute_coordinates_british_convention(self):
self.thickness_max/2*self.thickness_percentage)
self._ydown_coordinates = (self.camber_percentage*self.camber_max -
self.thickness_max/2*self.thickness_percentage)

def _compute_orth_camber_coordinates(self):
"""
Compute the coordinates of points on upper and lower profile on the
Expand All @@ -108,8 +111,9 @@ def _compute_orth_camber_coordinates(self):
m = np.zeros(n_pos)
for i in range(1, n_pos, 1):
m[i] = (self.camber_percentage[i]-
self.camber_percentage[i-1])/(self.chord_percentage[i]-
self.chord_percentage[i-1])*self.camber_max/self.chord_length
self.camber_percentage[i-1])*self.camber_max/(
self.chord_percentage[i]-
self.chord_percentage[i-1])/self.chord_length

m_angle = np.arctan(m)

Expand All @@ -127,7 +131,7 @@ def _compute_orth_camber_coordinates(self):
yup_tmp[1], ydown_tmp[1] = yup_tmp[2]-1e-16, ydown_tmp[2]-1e-16

return [xup_tmp, xdown_tmp, yup_tmp, ydown_tmp]

def _compute_coordinates_american_convention(self):
"""
Compute the coordinates of points on upper and lower profile according
Expand All @@ -137,8 +141,8 @@ def _compute_coordinates_american_convention(self):
self._ydown_coordinates] = self._compute_orth_camber_coordinates()

self._ydown_coordinates = self.ydown_curve(
(self.chord_percentage*self.chord_length).reshape(-1,1)).reshape(
self.chord_percentage.shape)
(self.chord_percentage*self.chord_length).reshape(-1,1)
).reshape(self.chord_percentage.shape)
self._yup_coordinates = (2*self.camber_max*self.camber_percentage -
self.ydown_coordinates)

Expand All @@ -161,6 +165,8 @@ def _check_parameters(self):
raise ValueError('object "camber_max" refers to an empty array.')
if self._thickness_max is None:
raise ValueError('object "thickness_max" refers to an empty array.')
if self._chord_length is None:
raise ValueError('object "chord_length" refers to an empty array.')

if not isinstance(self._chord_percentage, np.ndarray):
self._chord_percentage = np.asarray(self._chord_percentage,
Expand Down Expand Up @@ -241,7 +247,8 @@ def _check_coordinates(self):
# The condition yup_coordinates >= ydown_coordinates must be satisfied
# element-wise to the whole elements in the mentioned arrays.
if not all(
np.greater_equal(self.yup_coordinates[1:-1], self.ydown_coordinates[1:-1])):
np.greater_equal(self.yup_coordinates[1:-1],
self.ydown_coordinates[1:-1])):
raise ValueError('yup is not >= ydown elementwise.')

if not np.isclose(self.xdown_coordinates[0], self.xup_coordinates[0],
Expand All @@ -258,4 +265,5 @@ def _check_coordinates(self):

if not np.isclose(self.ydown_coordinates[-1], self.yup_coordinates[-1],
atol=1e-6):
raise ValueError('(ydown[0]=yup[0]) not satisfied.')
raise ValueError('(ydown[-1]=yup[-1]) not satisfied.')

19 changes: 10 additions & 9 deletions bladex/profile/nacaprofile.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""
Derived module from profilebase.py to provide the airfoil coordinates for standard
Naca profiles.
Derived module from profilebase.py to provide the airfoil coordinates for
standard Naca profiles.
"""
from scipy.interpolate import splev, splrep
import numpy as np
Expand All @@ -24,29 +24,29 @@ class NacaProfile(ProfileInterface):
- P/10: indicates the location of the maximum camber measured from the
leading edge. The location is normalized by the chord length.
- TT/100: the maximum thickness as fraction of the chord length.
The profile 00TT refers to a symmetrical NACA airfoil.
The NACA five-digit series describes more complex airfoil shapes.
Its format is: LPSTT, where:
- L: the theoretical optimum lift coefficient at ideal
angle-of-attack = 0.15*L
- P: the x-coordinate of the point of maximum camber
(max camber at x = 0.05*P)
- S: indicates whether the camber is simple (S=0) or reflex (S=1)
TT/100: the maximum thickness in percent of chord, as in a four-digit
NACA airfoil code
References:
- Moran, Jack (2003). An introduction to theoretical and computational
aerodynamics. Dover. p. 7. ISBN 0-486-42879-6.
- Abbott, Ira (1959). Theory of Wing Sections: Including a Summary of
Airfoil Data. New York: Dover Publications. p. 115. ISBN 978-0486605869.
Expand Down Expand Up @@ -218,4 +218,5 @@ def generate_coordinates(self):
self.ydown_coordinates = yc - yt

else:
raise Exception
raise Exception

Loading

0 comments on commit 4ec5dce

Please sign in to comment.