def __init__( self, xyz_le: np.ndarray = np.array([0, 0, 0]), chord: float = 1., twist_angle: float = 0, twist_axis: np.ndarray = np.array([0, 1, 0]), airfoil: Airfoil = Airfoil("naca0012"), control_surface_is_symmetric: bool = True, control_surface_hinge_point: float = 0.75, control_surface_deflection: float = 0., ): """ Initialize a new wing cross section. Args: xyz_le: xyz-coordinates of the leading edge of the cross section, relative to the wing's datum. chord: Chord of the wing at this cross section twist_angle: Twist angle, in degrees, as defined about the leading edge. twist_axis: The twist axis vector, used if twist_angle != 0. airfoil: Airfoil associated with this cross section. [aerosandbox.Airfoil] control_surface_is_symmetric: Is the control surface symmetric? (e.g. True for flaps, False for ailerons.) control_surface_hinge_point: The location of the control surface hinge, as a fraction of chord. control_surface_deflection: Control deflection, in degrees. Downwards-positive. """ self.xyz_le = xyz_le self.chord = chord self.twist = twist_angle self.twist_axis = twist_axis self.airfoil = airfoil self.control_surface_is_symmetric = control_surface_is_symmetric self.control_surface_hinge_point = control_surface_hinge_point self.control_surface_deflection = control_surface_deflection
def __init__(self, xyz_le: np.ndarray = np.array([0, 0, 0]), chord: float = 1., twist: float = 0, twist_angle=None, # TODO Deprecate airfoil: Airfoil = Airfoil("naca0012"), control_surface_is_symmetric: bool = True, control_surface_hinge_point: float = 0.75, control_surface_deflection: float = 0., ): """ Initialize a new wing cross section. Args: xyz_le: xyz-coordinates of the leading edge of the cross section, relative to the wing's datum. chord: Chord of the wing at this cross section twist: Twist angle, in degrees, as defined about the leading edge. The twist axis is computed with the following procedure: * The quarter-chord point of this WingXSec and the following one are identified. * A line is drawn connecting them, and it is converted into a direction vector. * That direction vector is projected onto the Y-Z plane. * That direction vector is now the twist axis. airfoil: Airfoil associated with this cross section. [aerosandbox.Airfoil] control_surface_is_symmetric: Is the control surface symmetric? (e.g. True for flaps, False for ailerons.) control_surface_hinge_point: The location of the control surface hinge, as a fraction of chord. control_surface_deflection: Control deflection, in degrees. Downwards-positive. """ if twist_angle is not None: import warnings warnings.warn("DEPRECATED: 'twist_angle' has been renamed 'twist', and will break in future versions.") twist = twist_angle self.xyz_le = np.array(xyz_le) self.chord = chord self.twist = twist self.airfoil = airfoil self.control_surface_is_symmetric = control_surface_is_symmetric self.control_surface_hinge_point = control_surface_hinge_point self.control_surface_deflection = control_surface_deflection
def diamond_airfoil( t_over_c: float, n_points_per_panel=2, ) -> Airfoil: x_nondim = [1, 0.5, 0, 0.5, 1] y_nondim = [0, 1, 0, -1, 0] x = np.concatenate([ list(np.cosspace(a, b, n_points_per_panel))[:-1] for a, b in zip(x_nondim[:-1], x_nondim[1:]) ] + [[x_nondim[-1]]]) y = np.concatenate([ list(np.cosspace(a, b, n_points_per_panel))[:-1] for a, b in zip(y_nondim[:-1], y_nondim[1:]) ] + [[y_nondim[-1]]]) y = y * t_over_c coordinates = np.array([x, y]).T return Airfoil( name="Diamond", coordinates=coordinates, )
def __init__( self, xyz_le: Union[np.ndarray, List] = np.array([0, 0, 0]), chord: float = 1., twist: float = 0, airfoil: Airfoil = None, control_surfaces: Optional[List['ControlSurface']] = None, analysis_specific_options: Optional[Dict[type, Dict[str, Any]]] = None, **deprecated_kwargs, ): """ Defines a new wing cross section. Args: xyz_le: An array-like that represents the xyz-coordinates of the leading edge of the cross section, in geometry axes. chord: Chord of the wing at this cross section. twist: Twist angle, in degrees, as defined about the leading edge. The twist axis is computed with the following procedure: * The quarter-chord point of this WingXSec and the following one are identified. * A line is drawn connecting them, and it is normalized to a unit direction vector. * That direction vector is projected onto the geometry Y-Z plane. * That direction vector is now the twist axis. airfoil: Airfoil associated with this cross section. [aerosandbox.Airfoil] control_surfaces: A list of control surfaces in the form of ControlSurface objects. analysis_specific_options: Analysis-specific options are additional constants or modeling assumptions that should be passed on to specific analyses and associated with this specific geometry object. This should be a dictionary where: * Keys are specific analysis types (typically a subclass of asb.ExplicitAnalysis or asb.ImplicitAnalysis), but if you decide to write your own analysis and want to make this key something else (like a string), that's totally fine - it's just a unique identifier for the specific analysis you're running. * Values are a dictionary of key:value pairs, where: * Keys are strings. * Values are some value you want to assign. This is more easily demonstrated / understood with an example: >>> analysis_specific_options = { >>> asb.AeroBuildup: dict( >>> include_wave_drag=True, >>> ) >>> } Note: Control surface definition through WingXSec properties (control_surface_is_symmetric, control_surface_hinge_point, control_surface_deflection) is deprecated. Control surfaces should be handled according to the following protocol: 1. If control_surfaces is an empty list (default, user does not specify any control surfaces), use deprecated WingXSec control surface definition properties. This will result in 1 control surface at this xsec. Usage example: >>> xsecs = asb.WingXSec( >>> chord = 2 >>> ) 2. If control_surfaces is a list of ControlSurface instances, use ControlSurface properties to define control surfaces. This will result in as many control surfaces at this xsec as there are entries in the control_surfaces list (an arbitrary number >= 1). Usage example: >>>xsecs = asb.WingXSec( >>> chord = 2, >>> control_surfaces = [ >>> ControlSurface( >>> trailing_edge = False >>> ) >>> ] >>>) 3. If control_surfaces is None, override deprecated control surface definition properties and do not define a control surface at this xsec. This will result in 0 control surfaces at this xsec. Usage example: >>>xsecs = asb.WingXSec( >>> chord = 2, >>> control_surfaces = None >>>) See avl.py for example of control_surface handling using this protocol. """ ### Set defaults if airfoil is None: airfoil = Airfoil("naca0012") if control_surfaces is None: control_surfaces = [] if analysis_specific_options is None: analysis_specific_options = {} self.xyz_le = np.array(xyz_le) self.chord = chord self.twist = twist self.airfoil = airfoil self.control_surfaces = control_surfaces self.analysis_specific_options = analysis_specific_options ### Handle deprecated arguments if 'twist_angle' in locals(): import warnings warnings.warn( "DEPRECATED: 'twist_angle' has been renamed 'twist', and will break in future versions.", stacklevel=2) self.twist = twist_angle if ('control_surface_is_symmetric' in locals() or 'control_surface_hinge_point' in locals() or 'control_surface_deflection' in locals()): import warnings warnings.warn( "DEPRECATED: Define control surfaces using the `control_surfaces` parameter, which takes in a list of asb.ControlSurface objects.", stacklevel=2) if 'control_surface_is_symmetric' not in locals(): control_surface_is_symmetric = True if 'control_surface_hinge_point' not in locals(): control_surface_hinge_point = 0.75 if 'control_surface_deflection' not in locals(): control_surface_deflection = 0 self.control_surfaces.append( ControlSurface( hinge_point=control_surface_hinge_point, symmetric=control_surface_is_symmetric, deflection=control_surface_deflection, ))
analysis_specific_options = {} self.name = name self.trailing_edge = trailing_edge self.hinge_point = hinge_point self.symmetric = symmetric self.deflection = deflection self.analysis_specific_options = analysis_specific_options if __name__ == '__main__': wing = Wing(xsecs=[ WingXSec( xyz_le=[0, 0, 0], chord=1, airfoil=Airfoil("naca0012"), twist=0, ), WingXSec( xyz_le=[0.5, 1, 0], chord=0.5, airfoil=Airfoil("naca0012"), twist=0, ), WingXSec( xyz_le=[0.7, 1, 0.3], chord=0.3, airfoil=Airfoil("naca0012"), twist=0, ) ]).translate([1, 0, 0])
y = y * t_over_c coordinates = np.array([x, y]).T return Airfoil( name="Diamond", coordinates=coordinates, ) generic_cambered_airfoil = Airfoil( name="Generic Cambered Airfoil", CL_function=lambda alpha, Re, mach, deflection, : ( # Lift coefficient function (alpha * np.pi / 180) * (2 * np.pi) + 0.4550), CD_function=lambda alpha, Re, mach, deflection: ( # Profile drag coefficient function (1 + (alpha / 5)**2) * 2 * Cf_flat_plate(Re_L=Re)), CM_function=lambda alpha, Re, mach, deflection: ( # Moment coefficient function about quarter-chord -0.1), coordinates=get_UIUC_coordinates(name="clarky")) generic_airfoil = Airfoil( name="Generic Airfoil", CL_function=lambda alpha, Re, mach, deflection, : ( # Lift coefficient function (alpha * np.pi / 180) * (2 * np.pi)), CD_function=lambda alpha, Re, mach, deflection: ( # Profile drag coefficient function (1 + (alpha / 5)**2) * 2 * Cf_flat_plate(Re_L=Re)), CM_function=lambda alpha, Re, mach, deflection: ( # Moment coefficient function about quarter-chord