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)
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)
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_conventional(): from aerosandbox.aerodynamics.aero_3D.test_aero_3D.geometries.conventional import airplane analysis = asb.VortexLatticeMethod( airplane=airplane, op_point=asb.OperatingPoint(alpha=10), ) return analysis.run()
def get_aero(alpha, taper_ratio): airplane = asb.Airplane(wings=[ asb.Wing(symmetric=True, xsecs=[ asb.WingXSec( xyz_le=[-0.25, 0, 0], chord=1, ), asb.WingXSec( xyz_le=[-0.25 * taper_ratio, 1, 0], chord=taper_ratio, ) ]) ]) op_point = asb.OperatingPoint( velocity=1, alpha=alpha, ) vlm = asb.VortexLatticeMethod( airplane, op_point, chordwise_resolution=6, spanwise_resolution=6, ) return vlm.run()
def test_flat_plate_mirrored(): if not avl_present: return from aerosandbox.aerodynamics.aero_3D.test_aero_3D.geometries.flat_plate_mirrored import airplane analysis = asb.AVL( airplane=airplane, op_point=asb.OperatingPoint(alpha=10), ) return analysis.run()
def test_order_wind_body(): op_point = asb.OperatingPoint( alpha=90, beta=90, ) x, y, z = op_point.convert_axes(0, 1, 0, "body", "wind") assert x == pytest.approx(1) assert y == pytest.approx(0) assert z == pytest.approx(0)
def test_flat_plate_mirrored(): from aerosandbox.aerodynamics.aero_3D.test_aero_3D.geometries.flat_plate_mirrored import airplane analysis = asb.VortexLatticeMethod( airplane=airplane, op_point=asb.OperatingPoint(alpha=10), spanwise_resolution=1, chordwise_resolution=3, ) return analysis.run()
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
def _solve(self, value, mode=None): """Create and solve a VLM3 problem for a given angle of attack or lift coefficient. Parameters ---------- value : float mode : str [SolverMode.ALPHA, SolverMode.CL] Returns ------- aero_problem : VLM3-like object """ # Create vlm3-object if mode == SolverMode.ALPHA: atmosphere = self._atmosphere rho = atmosphere.density(T=atmosphere.T, P=atmosphere.P) aero_problem = sbx.vlm3( airplane=self.model.airplane, op_point=sbx.OperatingPoint(velocity=self.velocity, alpha=value, density=rho), ) elif mode == SolverMode.CL: aero_problem = self._find_alpha_for_cl(cl=value) else: raise NotImplementedError("'mode' must be either 'alpha' or 'cl'.") # Solve aero_problem.run(verbose=False) self.CL = aero_problem.CL self.CDi = aero_problem.CDi self.CY = aero_problem.CY self.alpha = aero_problem.op_point.alpha return aero_problem
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")
# # # # # aero_problem.run() aleph = np.linspace(0, 15, 16) sol = pd.DataFrame(columns=['alpha', 'cl', 'cdi', 'cl/cdi']) for a in aleph: aero_problem = ae.vlm3( # Analysis type: Vortex Lattice Method, version 3 airplane=testPlane, op_point=ae.OperatingPoint( velocity=4.5, alpha=a, beta=0, p=0, q=0, r=0, ), ) aero_problem.run() sol = sol.append( { 'alpha': a, 'cl': aero_problem.Cl, 'cdi': aero_problem.CDi, 'cl/cdi': (aero_problem.Cl / aero_problem.CDi) }, ignore_index=True) print(sol)
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 test_aero_buildup(): analysis = asb.AeroBuildup( airplane=airplane, op_point=asb.OperatingPoint(), ) return analysis.run()
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]
analysis = asb.VortexLatticeMethod( airplane=airplane, op_point=asb.OperatingPoint(alpha=10), ) return analysis.run() def test_flat_plate_mirrored(): from aerosandbox.aerodynamics.aero_3D.test_aero_3D.geometries.flat_plate_mirrored import airplane analysis = asb.VortexLatticeMethod( airplane=airplane, op_point=asb.OperatingPoint(alpha=10), spanwise_resolution=1, chordwise_resolution=3, ) return analysis.run() if __name__ == '__main__': # test_conventional() # test_vanilla() # test_flat_plate()['CL'] # test_flat_plate_mirrored() # pytest.main() from aerosandbox.aerodynamics.aero_3D.test_aero_3D.geometries.conventional import airplane analysis = asb.VortexLatticeMethod( airplane=airplane, op_point=asb.OperatingPoint(alpha=10), ) aero = analysis.run() analysis.draw()
def test_beta_stability_body(): op_point = asb.OperatingPoint(alpha=0, beta=90) x, y, z = op_point.convert_axes(0, 1, 0, "body", "stability") assert x == pytest.approx(0) assert y == pytest.approx(1) assert z == pytest.approx(0)
def display_geometry( display_geometry, run_ll_analysis, run_vlm_analysis, n_booms, wing_span, alpha, ): ### Figure out which button was clicked try: button_pressed = np.argmax( np.array([ float(display_geometry), float(run_ll_analysis), float(run_vlm_analysis), ])) assert button_pressed is not None except: button_pressed = 0 ### Make the airplane airplane = make_airplane( n_booms=n_booms, wing_span=wing_span, ) op_point = asb.OperatingPoint( density=0.10, velocity=20, alpha=alpha, ) if button_pressed == 0: # Display the geometry figure = airplane.draw(show=False, colorbar_title=None) output = "Please run an analysis to display the data." elif button_pressed == 1: # Run an analysis opti = cas.Opti() # Initialize an analysis/optimization environment ap = asb.Casll1(airplane=airplane, op_point=op_point, opti=opti, run_setup=False) ap.setup(verbose=False) # Solver options p_opts = {} s_opts = {} # s_opts["mu_strategy"] = "adaptive" opti.solver('ipopt', p_opts, s_opts) # Solve try: sol = opti.solve() output = make_table( pd.DataFrame({ "Figure": ["CL", "CD", "CDi", "CDp", "L/D"], "Value": [ sol.value(ap.CL), sol.value(ap.CD), sol.value(ap.CDi), sol.value(ap.CDp), sol.value(ap.CL / ap.CD), ] })) except: sol = opti.debug output = html.P( "Aerodynamic analysis failed! Most likely the airplane is stalled at this flight condition." ) figure = ap.draw(show=False) # Generates figure elif button_pressed == 2: # Run an analysis opti = cas.Opti() # Initialize an analysis/optimization environment ap = asb.Casvlm1(airplane=airplane, op_point=op_point, opti=opti, run_setup=False) ap.setup(verbose=False) # Solver options p_opts = {} s_opts = {} s_opts["max_iter"] = 50 # s_opts["mu_strategy"] = "adaptive" opti.solver('ipopt', p_opts, s_opts) # Solve try: sol = opti.solve() output = make_table( pd.DataFrame({ "Figure": ["CL", "CDi", "L/Di"], "Value": [ sol.value(ap.CL), sol.value(ap.CDi), sol.value(ap.CL / ap.CDi), ] })) except: sol = opti.debug output = html.P( "Aerodynamic analysis failed! Most likely the airplane is stalled at this flight condition." ) figure = ap.draw(show=False) # Generates figure figure.update_layout( autosize=True, # width=1000, # height=700, margin=dict( l=0, r=0, b=0, t=0, )) return (figure, output)
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("naca0010").local_thickness(xi)) for xi in np.cosspace(0, 1, 20) ], ) fig, ax = plt.subplots(figsize=(7, 6)) Beta, Alpha = np.meshgrid(np.linspace(-90, 90, 500), np.linspace(-90, 90, 500)) aero = asb.AeroBuildup(airplane=asb.Airplane(fuselages=[fuselage]), op_point=asb.OperatingPoint( velocity=10, alpha=Alpha, beta=Beta, )).run() from aerosandbox.tools.string_formatting import eng_string p.contour( Beta, Alpha, aero["L"], colorbar_label="Lift $L$ [N]", # levels=100, linelabels_format=lambda s: eng_string(s, unit="N"), cmap=plt.get_cmap("coolwarm")) p.equal() p.show_plot("3D Fuselage Lift", r"$\beta$ [deg]", r"$\alpha$ [deg]")
from aerosandbox.aerodynamics.aero_3D.test_aero_3D.geometries.conventional import airplane import aerosandbox as asb import aerosandbox.numpy as np for i, wing in enumerate(airplane.wings): for j, xsec in enumerate(wing.xsecs): af = xsec.airfoil af.generate_polars( cache_filename=f"cache/{af.name}.json", xfoil_kwargs=dict(xfoil_repanel="naca" in af.name.lower())) airplane.wings[i].xsecs[j].airfoil = af op_point = asb.OperatingPoint(velocity=25, alpha=3) vlm = asb.VortexLatticeMethod( airplane, op_point, align_trailing_vortices_with_wind=True, chordwise_resolution=12, spanwise_resolution=12, ) vlm_aero = vlm.run() ab = asb.AeroBuildup(airplane, op_point) ab_aero = ab.run() avl = asb.AVL( airplane, op_point, ) avl_aero = avl.run()
import aerosandbox as asb import aerosandbox.numpy as np from aerosandbox.aerodynamics.aero_3D.test_aero_3D.conventional import airplane analysis = asb.AeroBuildup( airplane=airplane, op_point=asb.OperatingPoint( atmosphere=asb.Atmosphere(altitude=0, method="ISA"), velocity=10, # m/s alpha=5, # In degrees beta=0, # In degrees p=0, # About the body x-axis, in rad/sec q=0, # About the body y-axis, in rad/sec r=0, # About the body z-axis, in rad/sec ), )
geometry_folder = Path( asb.__file__ ).parent.parent / "tutorial" / "04 - Geometry" / "example_geometry" import sys sys.path.insert(0, str(geometry_folder)) from vanilla import airplane as vanilla ### Do the AVL run analysis = VortexLatticeMethod( airplane=vanilla, op_point=asb.OperatingPoint( atmosphere=asb.Atmosphere(altitude=0), velocity=10, alpha=0, beta=0, p=0, q=0, r=0, ), spanwise_resolution=12, chordwise_resolution=12, ) res = analysis.run() for k, v in res.items(): print(f"{str(k).rjust(10)} : {v:.4f}")
def op_point(): return sbx.OperatingPoint(velocity=1.0, alpha=1.0, density=1.0)
pressure_total_2: The total pressure at the compressor inlet face, at the conditions to be evaluated. [Pa] Returns: The ratio `m_dot_corrected / m_dot`. """ temperature_standard = 273.15 + 15 pressure_standard = 101325 return (temperature_total_2 / temperature_standard)**0.5 / (pressure_total_2 / pressure_standard) if __name__ == '__main__': import aerosandbox as asb atmo = asb.Atmosphere(altitude=10668) op_point = asb.OperatingPoint(atmo, velocity=0.80 * atmo.speed_of_sound()) m_dot_corrected_over_m_dot_ratio = m_dot_corrected_over_m_dot( temperature_total_2=op_point.total_temperature(), pressure_total_2=op_point.total_pressure()) ### CFM56-2 engine test mass_cfm56_2 = mass_turbofan( # Data here from Wikipedia, cross-referenced to other sources for sanity check. m_dot_core_corrected=364 / (5.95 + 1), overall_pressure_ratio=31.2, bypass_ratio=5.95, diameter_fan=1.73 ) # real mass: (2139 to 2200 kg bare, ~3400 kg installed)
def get_aero(xyz_ref): return asb.AeroBuildup(airplane=asb.Airplane(fuselages=[fuselage], xyz_ref=xyz_ref), op_point=asb.OperatingPoint(velocity=10, alpha=5, beta=5)).run()
import aerosandbox as asb import casadi as cas from airplane import make_airplane n_booms = 1 wing_span = 40 alpha = 5 airplane = make_airplane(n_booms=n_booms, wing_span=wing_span,) op_point = asb.OperatingPoint(density=0.10, velocity=20, alpha=alpha,) ### LL # Run an analysis opti = cas.Opti() # Initialize an analysis/optimization environment # airplane.fuselages=[] ap = asb.Casvlm1(airplane=airplane, op_point=op_point, opti=opti) # Solver options p_opts = {} s_opts = {} # s_opts["mu_strategy"] = "adaptive" opti.solver("ipopt", p_opts, s_opts) # Solve try: sol = opti.solve() except RuntimeError: sol = opti.debug raise Exception("An error occurred!") # Postprocess # ap.substitute_solution(sol) ap.draw(show=False).show()
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() from pprint import pprint pprint(aero)
import aerosandbox as asb import aerosandbox.numpy as np from typing import List import copy import pytest vector = [1, 2, 3] op_point = asb.OperatingPoint(alpha=10, beta=5) def chain_conversion(axes: List[str] = ["geometry", "body", "geometry"]): x, y, z = copy.deepcopy(vector) for from_axes, to_axes in zip(axes, axes[1:]): x, y, z = op_point.convert_axes(x_from=x, y_from=y, z_from=z, from_axes=from_axes, to_axes=to_axes) return np.array(vector) == pytest.approx(np.array([x, y, z])) def test_basic(): assert chain_conversion() def test_geometry(): assert chain_conversion(["body", "geometry", "body"]) def test_stability(): assert chain_conversion(["body", "stability", "body"])
def test_alpha_wind(): op_point = asb.OperatingPoint(alpha=90, beta=0) x, y, z = op_point.convert_axes(0, 0, 1, "geometry", "wind") assert x == pytest.approx(-1) assert y == pytest.approx(0) assert z == pytest.approx(0)