def test_airfoil_multielement():
    a = asb.AirfoilInviscid(airfoil=[
        asb.Airfoil("e423").repanel(n_points_per_side=50),
        asb.Airfoil("naca6408").repanel(n_points_per_side=25).scale(
            0.4, 0.4).rotate(np.radians(-20)).translate(0.9, -0.05),
    ],
                            op_point=asb.OperatingPoint(velocity=1, alpha=5))
def test_fuselage_aerodynamics_optimization():
    opti = asb.Opti()

    alpha = opti.variable(init_guess=0, lower_bound=0, upper_bound=30)
    beta = opti.variable(init_guess=0)

    fuselage = asb.Fuselage(xsecs=[
        asb.FuselageXSec(xyz_c=[xi, 0, 0],
                         radius=asb.Airfoil("naca0010").local_thickness(
                             0.8 * xi)) for xi in np.cosspace(0, 1, 20)
    ], )

    aero = asb.AeroBuildup(airplane=asb.Airplane(fuselages=[fuselage]),
                           op_point=asb.OperatingPoint(velocity=10,
                                                       alpha=alpha,
                                                       beta=beta)).run()

    opti.minimize(-aero["L"] / aero["D"])
    sol = opti.solve(verbose=False)
    print(sol.value(alpha))
    assert sol.value(alpha) > 10 and sol.value(alpha) < 20
    assert sol.value(beta) == pytest.approx(0, abs=1e-3)

    opti.minimize(aero["D"])
    sol = opti.solve(verbose=False)
    assert sol.value(alpha) == pytest.approx(0, abs=1e-2)
    assert sol.value(beta) == pytest.approx(0, abs=1e-2)
Beispiel #3
0
    def _create_winglet(self):
        """Create winglet.

        Returns
        -------
        aerosandbox.Wing
        """

        # Extract winglet configuration
        parameters = self.winglet_parameters
        dimensions = self.winglet_dimensions

        location_tip = self.__get_winglet_vector__(
            length=dimensions["length"],
            sweep=parameters[W_ANGLE_SWEEP],
            cant=parameters[W_ANGLE_CANT],
        )

        # Slightly separete from the wing
        _epsilon_winglet_wing = Point([0, 0, 0.01])

        # Get wing tip section
        _section = self.__wingtip_section__
        _coordinates = list(_section[LE_LOCATION])
        coordinates_weld = _coordinates + _epsilon_winglet_wing

        # Match TE of wing tip and winglet root chord
        chord_root = dimensions["chord_root"]
        chord_tip = dimensions["chord_tip"]

        coordinates_weld.x += _section[CHORD] - chord_root

        winglet_airfoil = sbx.Airfoil(name=parameters[W_AIRFOIL])

        twist_root = parameters[W_ANGLE_TWIST_ROOT]
        twist_tip = parameters[W_ANGLE_TWIST_TIP]

        winglet = sbx.Wing(
            name="Winglet",
            xyz_le=list(coordinates_weld),
            symmetric=True,
            xsecs=[
                sbx.WingXSec(
                    xyz_le=[0, 0, 0],
                    chord=chord_root,
                    twist=twist_root,
                    airfoil=winglet_airfoil,
                ),
                sbx.WingXSec(
                    xyz_le=list(location_tip),
                    chord=chord_tip,
                    twist=twist_tip,
                    airfoil=winglet_airfoil,
                ),
            ],
        )

        self.winglet = [winglet]

        return winglet
def test_airfoil_symmetric_NACA():
    a = asb.AirfoilInviscid(airfoil=[asb.Airfoil("naca0012").repanel(50)],
                            op_point=asb.OperatingPoint(
                                velocity=1,
                                alpha=0,
                            ))
    assert a.Cl == pytest.approx(0, abs=1e-8)
Beispiel #5
0
    def create_wing_planform(self):
        """Create planform object.

        Returns
        -------
        aerosanbox.Wing
        """

        # Create sections
        sections = []

        for _section in self.sections:

            _coordinates = list(_section[LE_LOCATION])
            _airfoil = sbx.Airfoil(name=_section[AIRFOIL])

            _sbx_section = sbx.WingXSec(
                xyz_le=
                _coordinates,  # Coordinates of the XSec's leading edge, **relative** to the wing's leading edge.
                chord=_section[CHORD],
                twist=_section[TWIST],  # degrees
                airfoil=_airfoil,
            )

            sections.append(_sbx_section)

        # Create wing
        planform = sbx.Wing(
            name=self.NAME,
            xyz_le=[0.0, 0.0, 0.0],  # Coordinates of the wing's leading edge
            symmetric=True,
            xsecs=sections,
        )

        self.planform = planform

        return planform
    with open(filename) as f:
        data = f.readlines()

    data = [json.loads(line) for line in data]

    data = {k: np.array([d[k] for d in data]) for k in data[0].keys()}

    order = np.argsort(data['mach'])

    data = {k: v[order] for k, v in data.items()}

    return data


machs = np.linspace(0, 1.3, 500)
airfoil = asb.Airfoil("rae2822")
airfoil.generate_polars(cache_filename="./cache/rae2822.json")
aerobuildup_data = {
    "mach": machs,
    "CL": airfoil.CL_function(1, 6.5e6, machs, 0) * np.ones_like(machs),
    "CD": airfoil.CD_function(1, 6.5e6, machs, 0) * np.ones_like(machs),
    "CM": airfoil.CM_function(1, 6.5e6, machs, 0) * np.ones_like(machs),
}

datas = {
    "XFoil v6 (P-G)": get_data(data_folder / "xfoil6.csv"),
    "MSES (Euler + IBL)": get_data(data_folder / "mses.csv"),
    "SU2 (RANS)": get_data(data_folder / "su2.csv"),
    "ASB AeroBuildup": aerobuildup_data,
}
Beispiel #7
0
import aerosandbox as asb
import aerosandbox.numpy as np
from aerosandbox.library import airfoils

wing_airfoil = asb.Airfoil("sd7037")
tail_airfoil = asb.Airfoil("naca0010")

### Define the 3D geometry you want to analyze/optimize.
# Here, all distances are in meters and all angles are in degrees.
airplane = asb.Airplane(
    name="Peter's Glider",
    xyz_ref=[0.04, 0, 0],  # CG location
    wings=[
        asb.Wing(
            name="Main Wing",
            symmetric=True,  # Should this wing be mirrored across the XZ plane?
            xsecs=[  # The wing's cross ("X") sections
                asb.WingXSec(  # Root
                    xyz_le=[0, 0, 0],  # Coordinates of the XSec's leading edge, relative to the wing's leading edge.
                    chord=0.18,
                    twist=0,  # degrees
                    airfoil=wing_airfoil,  # Airfoils are blended between a given XSec and the next one.
                    control_surface_is_symmetric=True,
                    # Flap (ctrl. surfs. applied between this XSec and the next one.)
                    control_surface_deflection=0,  # degrees
                ),
                asb.WingXSec(  # Mid
                    xyz_le=[0.01, 0.5, 0],
                    chord=0.16,
                    twist=0,
                    airfoil=wing_airfoil,
import aerosandbox as asb
import aerosandbox.numpy as np
import pytest

airplane = asb.Airplane(wings=[
    asb.Wing(xsecs=[
        asb.WingXSec(
            xyz_le=[0, 0, 0], chord=1, airfoil=asb.Airfoil("naca0001")),
        asb.WingXSec(
            xyz_le=[0, 1, 0], chord=1, airfoil=asb.Airfoil("naca0001"))
    ])
])


def LD_from_alpha(alpha):
    op_point = asb.OperatingPoint(
        velocity=1,
        alpha=alpha,
    )

    vlm = asb.VortexLatticeMethod(airplane,
                                  op_point,
                                  align_trailing_vortices_with_wind=True)
    aero = vlm.run()

    CD0 = 0.01

    LD = aero["CL"] / (aero["CD"] + CD0)
    return LD

Beispiel #9
0
def display_graph(n_clicks, alpha, height, streamline_density,
                  operating_checklist, *kulfan_inputs):
    ### Figure out if a button was pressed
    global n_clicks_last
    if n_clicks is None:
        n_clicks = 0

    analyze_button_pressed = n_clicks > n_clicks_last
    n_clicks_last = n_clicks

    ### Parse the checklist
    ground_effect = "ground_effect" in operating_checklist

    ### Start constructing the figure
    airfoil = asb.Airfoil(coordinates=asb.get_kulfan_coordinates(
        lower_weights=np.array(kulfan_inputs[n_kulfan_inputs_per_side:]),
        upper_weights=np.array(kulfan_inputs[:n_kulfan_inputs_per_side]),
        TE_thickness=0,
        enforce_continuous_LE_radius=False,
        n_points_per_side=200,
    ))

    ### Do coordinates output
    coordinates_output = "\n".join(
        ["```"] + ["AeroSandbox Airfoil"] +
        ["\t%f\t%f" % tuple(coordinate)
         for coordinate in airfoil.coordinates] + ["```"])

    ### Continue doing the airfoil things
    airfoil = airfoil.rotate(angle=-np.radians(alpha))
    airfoil = airfoil.translate(0, height + 0.5 * np.sind(alpha))
    fig = go.Figure()
    fig.add_trace(
        go.Scatter(
            x=airfoil.x(),
            y=airfoil.y(),
            mode="lines",
            name="Airfoil",
            fill="toself",
            line=dict(color="blue"),
        ))

    ### Default text output
    text_output = 'Click "Analyze" to compute aerodynamics!'

    xrng = (-0.5, 1.5)
    yrng = (-0.6, 0.6) if not ground_effect else (0, 1.2)

    if analyze_button_pressed:

        analysis = asb.AirfoilInviscid(
            airfoil=airfoil.repanel(50),
            op_point=asb.OperatingPoint(
                velocity=1,
                alpha=0,
            ),
            ground_effect=ground_effect,
        )

        x = np.linspace(*xrng, 100)
        y = np.linspace(*yrng, 100)
        X, Y = np.meshgrid(x, y)
        u, v = analysis.calculate_velocity(x_field=X.flatten(),
                                           y_field=Y.flatten())
        U = u.reshape(X.shape)
        V = v.reshape(Y.shape)

        streamline_fig = ff.create_streamline(
            x,
            y,
            U,
            V,
            arrow_scale=1e-16,
            density=streamline_density,
            line=dict(color="#ff82a3"),
            name="Streamlines",
        )

        fig = go.Figure(data=streamline_fig.data + fig.data)

        text_output = make_table(
            pd.DataFrame({
                "Engineering Quantity": ["C_L"],
                "Value": [f"{analysis.Cl:.3f}"]
            }))

    fig.update_layout(
        xaxis_title="x/c",
        yaxis_title="y/c",
        showlegend=False,
        yaxis=dict(scaleanchor="x", scaleratio=1),
        margin={"t": 0},
        title=None,
    )

    fig.update_xaxes(range=xrng)
    fig.update_yaxes(range=yrng)

    return fig, text_output, [coordinates_output]
import aerosandbox as asb
import aerosandbox.numpy as np

if __name__ == '__main__':
    af = asb.Airfoil("dae11")
    af.generate_polars()

    alpha = np.linspace(-40, 40, 300)
    re = np.geomspace(1e4, 1e12, 100)
    Alpha, Re = np.meshgrid(alpha, re)
    af.CL_function(alpha=0, Re=1e6)

    CL = af.CL_function(Alpha.flatten(), Re.flatten()).reshape(Alpha.shape)
    CD = af.CD_function(Alpha.flatten(), Re.flatten()).reshape(Alpha.shape)
    CM = af.CM_function(Alpha.flatten(), Re.flatten()).reshape(Alpha.shape)

    ##### Plot alpha-Re contours
    from aerosandbox.tools.pretty_plots import plt, show_plot, contour

    fig, ax = plt.subplots()
    contour(Alpha, Re, CL, levels=30, colorbar_label=r"$C_L$")
    plt.scatter(af.xfoil_data["alpha"],
                af.xfoil_data["Re"],
                color="k",
                alpha=0.2)
    plt.yscale('log')
    show_plot(
        f"Auto-generated Polar for {af.name} Airfoil",
        "Angle of Attack [deg]",
        "Reynolds Number [-]",
    )
Beispiel #11
0
testPlane = ae.Airplane(
    name='ju87',
    xyz_ref=[0, 0, 0],  # CG location
    wings=[
        ae.Wing(
            name="Main Wing",
            xyz_le=[0, 0, 0],  # Coordinates of the wing's leading edge
            symmetric=True,
            xsecs=[  # The wing's cross ("X") sections
                ae.WingXSec(  # Root
                    xyz_le=[
                        0, 0, x_trans[0]
                    ],  # Coordinates of the XSec's leading edge, relative to the wing's leading edge.
                    chord=CHORD,
                    twist=0,  # degrees
                    airfoil=ae.Airfoil(name="naca4412"),
                    control_surface_type='symmetric',
                    # Flap # Control surfaces are applied between a given XSec and the next one.
                    control_surface_deflection=0,  # degrees
                    control_surface_hinge_point=0.75  # as chord fraction
                ),
                ae.WingXSec(  # Mid
                    xyz_le=[0, x_trans[1], 0],
                    chord=CHORD,
                    twist=0,
                    airfoil=ae.Airfoil(name="naca4412"),
                    control_surface_type='asymmetric',  # Aileron
                    control_surface_deflection=0,
                    control_surface_hinge_point=0.75),
                ae.WingXSec(  # Tip
                    xyz_le=[0, 1, x_trans[2]],
def test_airfoil_with_TE_gap():
    a = asb.AirfoilInviscid(airfoil=asb.Airfoil("naca4408").repanel(100),
                            op_point=asb.OperatingPoint(velocity=1, alpha=5))
    assert a.Cl == pytest.approx(1.0754, abs=0.01)  # From XFoil
def test_airfoil_ground_effect():
    a = asb.AirfoilInviscid(
        airfoil=asb.Airfoil("naca4408").repanel(100).translate(0, 0.2),
        op_point=asb.OperatingPoint(velocity=1, alpha=0),
        ground_effect=True)
    assert a.calculate_velocity(0, 0)[1] == pytest.approx(0)
def CL_function(alpha, Re, mach, deflection):
    return 2 * np.pi * np.radians(alpha)


def CD_function(alpha, Re, mach, deflection):
    return 0 * Re**0


def CM_function(alpha, Re, mach, deflection):
    return 0 * alpha


ideal_airfoil = asb.Airfoil(name="Ideal Airfoil",
                            coordinates=get_NACA_coordinates('naca0012'),
                            CL_function=CL_function,
                            CD_function=CD_function,
                            CM_function=CM_function)

wing = asb.Wing(xsecs=[
    asb.WingXSec(xyz_le=[0, y_i, 0], chord=1, airfoil=ideal_airfoil)
    for y_i in [0, 10]
],
                symmetric=True)

airplane = asb.Airplane(wings=[wing])

op_point = asb.OperatingPoint(velocity=340, alpha=0)

aero = asb.AeroBuildup(airplane=airplane, op_point=op_point).run()
Beispiel #15
0
import aerosandbox as asb
import aerosandbox.numpy as np

af = asb.Airfoil("naca0012")
cache = asb._asb_root / "geometry/airfoil/test_airfoil/naca0012.json"


def make_cache():
    af.generate_polars(cache_filename=cache)


def test_load_cache():
    af.generate_polars(cache_filename=cache)


if __name__ == '__main__':
    make_cache()
    test_load_cache()
Beispiel #16
0
import aerosandbox as asb
import aerosandbox.numpy as np

import matplotlib.pyplot as plt
import aerosandbox.tools.pretty_plots as p

fuselage = asb.Fuselage(xsecs=[
    asb.FuselageXSec(xyz_c=[xi, 0, 0],
                     radius=asb.Airfoil("naca0020").local_thickness(xi) / 2)
    for xi in np.cosspace(0, 1, 20)
], )

fig, ax = plt.subplots(figsize=(7, 6))
V = np.linspace(10, 1000, 1001)
op_point = asb.OperatingPoint(velocity=V, )

aero = asb.AeroBuildup(
    airplane=asb.Airplane(fuselages=[fuselage]),
    op_point=op_point,
).run()

plt.plot(op_point.mach(), aero["CD"], label="Full Model")

aero = asb.AeroBuildup(airplane=asb.Airplane(fuselages=[fuselage]),
                       op_point=op_point,
                       include_wave_drag=False).run()

plt.plot(op_point.mach(),
         aero["CD"],
         zorder=1.9,
         label="Model without Wave Drag")
Beispiel #17
0
import aerosandbox as asb
import aerosandbox.numpy as np

sd7037 = asb.Airfoil("sd7037")

airplane = asb.Airplane(
    name="Vanilla",
    xyz_ref=[0.5, 0, 0],
    s_ref=9,
    c_ref=0.9,
    b_ref=10,
    wings=[
        asb.Wing(name="Wing",
                 symmetric=True,
                 xsecs=[
                     asb.WingXSec(
                         xyz_le=[0, 0, 0],
                         chord=1,
                         twist=2,
                         airfoil=sd7037,
                     ),
                     asb.WingXSec(
                         xyz_le=[0.2, 5, 1],
                         chord=0.6,
                         twist=2,
                         airfoil=sd7037,
                     )
                 ]),
        asb.Wing(name="H-stab",
                 symmetric=True,
                 xyz_le=[4, 0, 0],
    def __init__(self,
                 filePrefix="",
                 fileDirectory="",
                 CLfitOrder=3,
                 CDpfitOrder=2,
                 CmfitOrder=3,
                 weightedFit=False,
                 plotFit=False):
        """
        Class containing airfoil read from file, as well as CL, CDp and Cm interpolation functions

        Point pairs (Re, AOA) as well as CL, CDp and Cm at each point is .points and .values(CL/CDp/Cm)

        :param filePrefix: an identifier for the airfoil file names, such as "NACA 0012_"
        :param fileDirectory: location of files
        :param fitOrder: degree of polynomial fit for CL, CDp and Cm, default is 3 for performance
        :param weightedFit: if True, the reader will add weight to polars near 2.5deg AOA
                            using a cos function with period T = 40deg
        :param plotFit: if True, the data will be scatter-plotted with poly fits
        """

        # Airfoil instance with characteristics read from files
        self.airfoil = None

        # Polars read from file
        self.polars = []

        # Point pairs (Re, AOA) as well as CL CDp and Cm at each point
        self.points = []

        self.valuesCL = []
        self.valuesCDp = []
        self.valuesCm = []

        # A list of Reynolds numbers
        self.Res = []

        # AOA, CL, CDp, Cm at each Re
        self.AOAs_Re = []
        self.CLs_Re = []
        self.CDps_Re = []
        self.Cms_Re = []

        # Fit characteristics
        self.CLfitOrder = CLfitOrder
        self.CDpfitOrder = CDpfitOrder
        self.CmfitOrder = CmfitOrder
        self.weightedFit = weightedFit
        self.plotFit = plotFit

        # Polyfit coeffs at each Re w.r.t. angle
        self.CLfit_Re = []
        self.CDpfit_Re = []
        self.Cmfit_Re = []

        # Keep some handy flags
        self.importedPolars = False
        self.createdCPolyfitTables = False

        if filePrefix is not "" and fileDirectory is not "":
            print("\nReading from xflr5 files...")
            try:
                # Try getting polars from file
                self.xflr5AirfoilPolarReader(filePrefix, fileDirectory)
                self.importedPolars = True

            except:
                self.importedPolars = False
                print("Read unsuccessful!")

            if self.importedPolars:
                print("Read successful!")
                print("\nCreating polynomial fits for coefficients...")
                try:
                    # Create lookup tables for CL, CDp and Cm
                    self.CreateCoefficientPolyfitTables()
                    self.createdCPolyfitTables = True

                except:
                    print("Fit unsuccessful!")
                    self.createdCPolyfitTables = False

            if self.createdCPolyfitTables:
                print("Fit successful!")

                # Create Airfoil instance
                self.airfoil = asb.Airfoil(
                    CL_function=lambda alpha, Re, mach, deflection:
                    (  # Lift coefficient function
                        self.CL_function(Re * 10e-6, alpha)),
                    CDp_function=lambda alpha, Re, mach, deflection:
                    (  # Profile drag coefficient function
                        self.CDp_function(Re * 10e-6, alpha)),
                    Cm_function=lambda alpha, Re, mach, deflection:
                    (  # Moment coefficient function
                        self.Cm_function(Re * 10e-6, alpha)))

                try:
                    self.PlotPolyFit()

                except:
                    print("Plot unsuccessful")
Beispiel #19
0
import aerosandbox as asb
import aerosandbox.numpy as np

airfoil = asb.Airfoil("naca0008")

airplane = asb.Airplane(name="Flat Plate",
                        xyz_ref=[0, 0, 0],
                        wings=[
                            asb.Wing(name="Wing",
                                     symmetric=True,
                                     xsecs=[
                                         asb.WingXSec(
                                             xyz_le=[0, 0, 0],
                                             chord=1,
                                             twist=0,
                                             airfoil=airfoil,
                                         ),
                                         asb.WingXSec(
                                             xyz_le=[0, 5, 0],
                                             chord=1,
                                             twist=0,
                                             airfoil=airfoil,
                                         ),
                                     ])
                        ])

if __name__ == '__main__':
    airplane.draw()
Beispiel #20
0
import aerosandbox as asb
import aerosandbox.numpy as np
from aerosandbox.tools import units as u


def ft_to_m(feet, inches=0):  # Converts feet (and inches) to meters
    return feet * u.foot + inches * u.inch


naca2412 = asb.Airfoil("naca2412")
naca0012 = asb.Airfoil("naca0012")
naca2412.generate_polars(cache_filename="assets/naca2412.json")
naca0012.generate_polars(cache_filename="assets/naca0012.json")

airplane = asb.Airplane(
    name="Cessna 152",
    wings=[
        asb.Wing(name="Wing",
                 xsecs=[
                     asb.WingXSec(xyz_le=[0, 0, 0],
                                  chord=ft_to_m(5, 4),
                                  airfoil=naca2412),
                     asb.WingXSec(
                         xyz_le=[0, ft_to_m(7),
                                 ft_to_m(7) * np.sind(1)],
                         chord=ft_to_m(5, 4),
                         airfoil=naca2412),
                     asb.WingXSec(xyz_le=[
                         ft_to_m(4, 3 / 4) - ft_to_m(3, 8 + 1 / 2),
                         ft_to_m(33, 4) / 2,
                         ft_to_m(33, 4) / 2 * np.sind(1)