aerosandbox#

Subpackages#

Submodules#

Package Contents#

Classes#

Opti

The base class for mathematical optimization. For detailed usage, see the docstrings in its key methods:

AeroSandboxObject

Helper class that provides a standard way to create an ABC using

ExplicitAnalysis

Helper class that provides a standard way to create an ABC using

ImplicitAnalysis

Helper class that provides a standard way to create an ABC using

Opti

The base class for mathematical optimization. For detailed usage, see the docstrings in its key methods:

OptiSol

FittedModel

A model that is fitted to data. Maps from R^N -> R^1.

InterpolatedModel

A model that is interpolated to structured (i.e., gridded) N-dimensional data. Maps from R^N -> R^1.

UnstructuredInterpolatedModel

A model that is interpolated to unstructured (i.e., point cloud) N-dimensional data. Maps from R^N -> R^1.

Airfoil

An airfoil. See constructor docstring for usage details.

KulfanAirfoil

An airfoil. See constructor docstring for usage details.

Wing

Definition for a Wing.

WingXSec

Definition for a wing cross-section ("X-section").

ControlSurface

Definition for a control surface, which is attached to a particular WingXSec via WingXSec's control_surfaces=[] parameter.

Fuselage

Definition for a Fuselage or other slender body (pod, fuel tank, etc.).

FuselageXSec

Definition for a fuselage cross-section ("X-section").

Airplane

Definition for an airplane.

Propulsor

Definition for a Propulsor, which could be a propeller, a rotor, or a jet engine.

Atmosphere

All models here are smoothed fits to the 1976 COESA model;

AeroSandboxObject

Helper class that provides a standard way to create an ABC using

MassProperties

Mass properties of a rigid 3D object.

OperatingPoint

Helper class that provides a standard way to create an ABC using

DynamicsPointMass1DHorizontal

Dynamics instance:

DynamicsPointMass1DVertical

Dynamics instance:

DynamicsPointMass2DCartesian

Dynamics instance:

DynamicsPointMass2DSpeedGamma

Dynamics instance:

DynamicsPointMass3DCartesian

Dynamics instance:

DynamicsPointMass3DSpeedGammaTrack

Dynamics instance:

DynamicsRigidBody2DBody

Dynamics instance:

DynamicsRigidBody3DBodyEuler

Dynamics instance:

AirfoilInviscid

An implicit analysis for inviscid analysis of an airfoil (or family of airfoils).

XFoil

An interface to XFoil, a 2D airfoil analysis tool developed by Mark Drela at MIT.

MSES

An interface to MSES, MSET, and MPLOT, a 2D airfoil analysis system developed by Mark Drela at MIT.

VortexLatticeMethod

An explicit (linear) vortex-lattice-method aerodynamics analysis.

LiftingLine

An implicit aerodynamics analysis based on lifting line theory, with modifications for nonzero sweep

NonlinearLiftingLine

An implicit aerodynamics analysis based on lifting line theory, with modifications for nonzero sweep

AeroBuildup

A workbook-style aerodynamics buildup.

AVL

An interface to AVL, a 3D vortex lattice aerodynamics code developed by Mark Drela at MIT.

Functions#

load(filename[, verbose])

Loads an AeroSandboxObject from a file.

black_box(function[, n_in, n_out, fd_method, fd_step, ...])

Wraps a function as a black box, allowing it to be used in AeroSandbox / CasADi optimization problems.

is_casadi_type(object[, recursive])

Returns a boolean of whether an object is a CasADi data type or not. If the recursive flag is True,

reflect_over_XZ_plane(input_vector)

Takes in a vector or an array and flips the y-coordinates.

mass_properties_from_radius_of_gyration(mass[, x_cg, ...])

Returns the mass properties of an object, given its radius of gyration.

trim_string(string[, length])

Trims a string to be less than a given length. If the string would exceed the length, makes it end in ellipses ("…").

docs()

Opens the AeroSandbox documentation.

run_tests()

Runs all of the AeroSandbox internal unit tests on this computer.

Attributes#

aerosandbox._asb_root[source]#
class aerosandbox.Opti(variable_categories_to_freeze=None, cache_filename=None, load_frozen_variables_from_cache=False, save_to_cache_on_solve=False, ignore_violated_parametric_constraints=False, freeze_style='parameter')[source]#

Bases: casadi.Opti

The base class for mathematical optimization. For detailed usage, see the docstrings in its key methods:
  • Opti.variable()

  • Opti.subject_to()

  • Opti.parameter()

  • Opti.solve()

Example usage is as follows:

>>> opti = asb.Opti() # Initializes an optimization environment
>>> x = opti.variable(init_guess=5) # Initializes a new variable in that environment
>>> f = x ** 2 # Evaluates a (in this case, nonlinear) function based on a variable
>>> opti.subject_to(x > 3) # Adds a constraint to be enforced
>>> opti.minimize(f) # Sets the objective function as f
>>> sol = opti.solve() # Solves the problem using CasADi and IPOPT backend
>>> print(sol(x)) # Prints the value of x at the optimum.
Parameters:
  • variable_categories_to_freeze (Union[List[str], str]) –

  • cache_filename (str) –

  • load_frozen_variables_from_cache (bool) –

  • save_to_cache_on_solve (bool) –

  • ignore_violated_parametric_constraints (bool) –

  • freeze_style (str) –

variable(init_guess=None, n_vars=None, scale=None, freeze=False, log_transform=False, category='Uncategorized', lower_bound=None, upper_bound=None, _stacklevel=1)[source]#

Initializes a new decision variable (or vector of decision variables). You should pass an initial guess ( init_guess) upon defining a new variable. Dimensionality is inferred from this initial guess, but it can be overridden; see below for syntax.

It is highly, highly recommended that you provide a scale (scale) for each variable, especially for nonconvex problems, although this is not strictly required.

Usage notes:

When using vector variables, individual components of this vector of variables can be accessed via normal indexing. Example:

>>> opti = asb.Opti()
>>> my_var = opti.variable(n_vars = 5)
>>> opti.subject_to(my_var[3] >= my_var[2])  # This is a valid way of indexing
>>> my_sum = asb.sum(my_var)  # This will sum up all elements of `my_var`
Parameters:
  • init_guess (Union[float, aerosandbox.numpy.ndarray]) –

    Initial guess for the optimal value of the variable being initialized. This is where in the design space the optimizer will start looking.

    This can be either a float or a NumPy ndarray; the dimension of the variable (i.e. scalar, vector) that is created will be automatically inferred from the shape of the initial guess you provide here. (Although it can also be overridden using the n_vars parameter; see below.)

    For scalar variables, your initial guess should be a float:

    >>> opti = asb.Opti()
    >>> scalar_var = opti.variable(init_guess=5) # Initializes a scalar variable at a value of 5
    

    For vector variables, your initial guess should be either:

    • a float, in which case you must pass the length of the vector as n_vars, otherwise a scalar

    variable will be created:

    >>> opti = asb.Opti()
    >>> vector_var = opti.variable(init_guess=5, n_vars=10) # Initializes a vector variable of length
    >>> # 10, with all 10 elements set to an initial guess of 5.
    
    • a NumPy ndarray, in which case each element will be initialized to the corresponding value in

    the given array:

    >>> opti = asb.Opti()
    >>> vector_var = opti.variable(init_guess=np.linspace(0, 5, 10)) # Initializes a vector variable of
    >>> # length 10, with all 10 elements initialized to linearly vary between 0 and 5.
    

    In the case where the variable is to be log-transformed (see log_transform), the initial guess should not be log-transformed as well - just supply the initial guess as usual. (Log-transform of the initial guess happens under the hood.) The initial guess must, of course, be a positive number in this case.

  • n_vars (int) –

    [Optional] Used to manually override the dimensionality of the variable to create; if not provided, the dimensionality of the variable is inferred from the initial guess init_guess.

    The only real case where you need to use this argument would be if you are initializing a vector variable to a scalar value, but you don’t feel like using init_guess=value * np.ones(n_vars). For example:

    >>> opti = asb.Opti()
    >>> vector_var = opti.variable(init_guess=5, n_vars=10) # Initializes a vector variable of length
    >>> # 10, with all 10 elements set to an initial guess of 5.
    

  • scale (float) –

    [Optional] Approximate scale of the variable.

    For example, if you’re optimizing the design of a automobile and setting the tire diameter as an optimization variable, you might choose scale=0.5, corresponding to 0.5 meters.

    Properly scaling your variables can have a huge impact on solution speed (or even if the optimizer converges at all). Although most modern second-order optimizers (such as IPOPT, used here) are theoretically scale-invariant, numerical precision issues due to floating-point arithmetic can make solving poorly-scaled problems really difficult or impossible. See here for more info: https://web.casadi.org/blog/nlp-scaling/

    If not specified, the code will try to pick a sensible value by defaulting to the init_guess.

  • freeze (bool) –

    [Optional] This boolean tells the optimizer to “freeze” the variable at a specific value. In order to select the determine to freeze the variable at, the optimizer will use the following logic:

    • If you initialize a new variable with the parameter freeze=True: the optimizer will freeze

    the variable at the value of initial guess.

    >>> opti = Opti()
    >>> my_var = opti.variable(init_guess=5, freeze=True) # This will freeze my_var at a value of 5.
    
    • If the Opti instance is associated with a cache file, and you told it to freeze a specific

    category(s) of variables that your variable is a member of, and you didn’t manually specify to freeze the variable: the variable will be frozen based on the value in the cache file (and ignore the init_guess). Example:

    >>> opti = Opti(cache_filename="my_file.json", variable_categories_to_freeze=["Wheel Sizing"])
    >>> # Assume, for example, that `my_file.json` was from a previous run where my_var=10.
    >>> my_var = opti.variable(init_guess=5, category="Wheel Sizing")
    >>> # This will freeze my_var at a value of 10 (from the cache file, not the init_guess)
    
    • If the Opti instance is associated with a cache file, and you told it to freeze a specific

    category(s) of variables that your variable is a member of, but you then manually specified that the variable should be frozen: the variable will once again be frozen at the value of init_guess:

    >>> opti = Opti(cache_filename="my_file.json", variable_categories_to_freeze=["Wheel Sizing"])
    >>> # Assume, for example, that `my_file.json` was from a previous run where my_var=10.
    >>> my_var = opti.variable(init_guess=5, category="Wheel Sizing", freeze=True)
    >>> # This will freeze my_var at a value of 5 (`freeze` overrides category loading.)
    

    Motivation for freezing variables:

    The ability to freeze variables is exceptionally useful when designing engineering systems. Let’s say we’re designing an airplane. In the beginning of the design process, we’re doing “clean-sheet” design - any variable is up for grabs for us to optimize on, because the airplane doesn’t exist yet! However, the farther we get into the design process, the more things get “locked in” - we may have ordered jigs, settled on a wingspan, chosen an engine, et cetera. So, if something changes later ( let’s say that we discover that one of our assumptions was too optimistic halfway through the design process), we have to make up for that lost margin using only the variables that are still free. To do this, we would freeze the variables that are already decided on.

    By categorizing variables, you can also freeze entire categories of variables. For example, you can freeze all of the wing design variables for an airplane but leave all of the fuselage variables free.

    This idea of freezing variables can also be used to look at off-design performance - freeze a design, but change the operating conditions.

  • log_transform (bool) – [Optional] Advanced use only. A flag of whether to internally-log-transform this variable before passing it to the optimizer. Good for known positive engineering quantities that become nonsensical if negative (e.g. mass). Log-transforming these variables can also help maintain convexity.

  • category (str) – [Optional] What category of variables does this belong to? # TODO expand docs

  • lower_bound (float) – [Optional] If provided, defines a bounds constraint on the new variable that keeps the variable above a given value.

  • upper_bound (float) – [Optional] If provided, defines a bounds constraint on the new variable that keeps the variable below a given value.

  • _stacklevel (int) – Optional and advanced, purely used for debugging. Allows users to correctly track where variables are declared in the event that they are subclassing aerosandbox.Opti. Modifies the stacklevel of the declaration tracked, which is then presented using aerosandbox.Opti.variable_declaration().

Returns:

The variable itself as a symbolic CasADi variable (MX type).

Return type:

casadi.MX

subject_to(constraint, _stacklevel=1)[source]#

Initialize a new equality or inequality constraint(s).

Parameters:
  • constraint (Union[casadi.MX, bool, List]) –

    A constraint that you want to hold true at the optimum.

    Inequality example:

    >>> x = opti.variable()
    >>> opti.subject_to(x >= 5)
    

    Equality example; also showing that you can directly constrain functions of variables:

    >>> x = opti.variable()
    >>> f = np.sin(x)
    >>> opti.subject_to(f == 0.5)
    

    You can also pass in a list of multiple constraints using list syntax. For example:

    >>> x = opti.variable()
    >>> opti.subject_to([
    >>>     x >= 5,
    >>>     x <= 10
    >>> ])
    

  • _stacklevel (int) – Optional and advanced, purely used for debugging. Allows users to correctly track where

  • the (constraints are declared in the event that they are subclassing aerosandbox.Opti. Modifies) –

  • tracked (stacklevel of the declaration) –

  • using (which is then presented) –

  • aerosandbox.Opti.constraint_declaration().

Returns:

The dual variable associated with the new constraint. If the constraint input is a list, returns a list of dual variables.

Return type:

Union[casadi.MX, None, List[casadi.MX]]

minimize(f)[source]#

[INTERNAL]

minimize(self, MX f)

Set objective.

Objective must be a scalar. Default objective: 0 When method is called

multiple times, the last call takes effect

Extra doc: https://github.com/casadi/casadi/wiki/L_1a

Doc source: https://github.com/casadi/casadi/blob/develop/casadi/core/optistack.hpp#L133

Implementation: https://github.com/casadi/casadi/blob/develop/casadi/core/optistack.cpp#L82-L88

Parameters:

f (casadi.MX) –

Return type:

None

maximize(f)[source]#
Parameters:

f (casadi.MX) –

Return type:

None

parameter(value=0.0, n_params=None)[source]#

Initializes a new parameter (or vector of parameters). You must pass a value (value) upon defining a new parameter. Dimensionality is inferred from this value, but it can be overridden; see below for syntax.

Parameters:
  • value (Union[float, aerosandbox.numpy.ndarray]) –

    Value to set the new parameter to.

    This can either be a float or a NumPy ndarray; the dimension of the parameter (i.e. scalar, vector) that is created will be automatically inferred from the shape of the value you provide here. (Although it can be overridden using the n_params parameter; see below.)

    For scalar parameters, your value should be a float: >>> opti = asb.Opti() >>> scalar_param = opti.parameter(value=5) # Initializes a scalar parameter and sets its value to 5.

    For vector variables, your value should be either:

    • a float, in which case you must pass the length of the vector as n_params, otherwise a scalar

    parameter will be created:

    >>> opti = asb.Opti()
    >>> vector_param = opti.parameter(value=5, n_params=10) # Initializes a vector parameter of length
    >>> # 10, with all 10 elements set to value of 5.
    
    • a NumPy ndarray, in which case each element will be set to the corresponding value in the given

    array:

    >>> opti = asb.Opti()
    >>> vector_param = opti.parameter(value=np.linspace(0, 5, 10)) # Initializes a vector parameter of
    >>> # length 10, with all 10 elements set to a value varying from 0 to 5.
    

  • n_params (int) –

    [Optional] Used to manually override the dimensionality of the parameter to create; if not provided, the dimensionality of the parameter is inferred from value.

    The only real case where you need to use this argument would be if you are initializing a vector parameter to a scalar value, but you don’t feel like using value=my_value * np.ones(n_vars). For example:

    >>> opti = asb.Opti()
    >>> vector_param = opti.parameter(value=5, n_params=10) # Initializes a vector parameter of length
    >>> # 10, with all 10 elements set to a value of 5.
    

Returns:

The parameter itself as a symbolic CasADi variable (MX type).

Return type:

casadi.MX

solve(parameter_mapping=None, max_iter=1000, max_runtime=1e+20, callback=None, verbose=True, jit=False, detect_simple_bounds=False, options=None, behavior_on_failure='raise')[source]#

Solve the optimization problem using CasADi with IPOPT backend.

Parameters:
  • parameter_mapping (Dict[casadi.MX, float]) –

    [Optional] Allows you to specify values for parameters. Dictionary where the key is the parameter and the value is the value to be set to.

    Example: # TODO update syntax for required init_guess
    >>> opti = asb.Opti()
    >>> x = opti.variable()
    >>> p = opti.parameter()
    >>> opti.minimize(x ** 2)
    >>> opti.subject_to(x >= p)
    >>> sol = opti.solve(
    >>>     {
    >>>         p: 5 # Sets the value of parameter p to 5, then solves.
    >>>     }
    >>> )
    

  • max_iter (int) – [Optional] The maximum number of iterations allowed before giving up.

  • max_runtime (float) – [Optional] Gives the maximum allowable runtime before giving up.

  • callback (Callable[[int], Any]) –

    [Optional] A function to be called at each iteration of the optimization algorithm. Useful for printing progress or displaying intermediate results.

    The callback function func should have the syntax func(iteration_number), where iteration_number is an integer corresponding to the current iteration number. In order to access intermediate quantities of optimization variables (e.g. for plotting), use the Opti.debug.value(x) syntax for each variable x.

  • verbose (bool) – Controls the verbosity of the solver. If True, IPOPT will print its progress to the console.

  • jit (bool) – Experimental. If True, the optimization problem will be compiled to C++ and then JIT-compiled using the CasADi JIT compiler. This can lead to significant speedups, but may also lead to unexpected behavior, and may not work on all platforms.

  • options (Dict) – [Optional] A dictionary of options to pass to IPOPT. See the IPOPT documentation for a list of available options.

  • behavior_on_failure (str) –

    [Optional] What should we do if the optimization fails? Options are:

    • ”raise”: Raise an exception. This is the default behavior.

    • ”return_last”: Returns the solution from the last iteration, and raise a warning.

      NOTE: The returned solution may not be feasible! (It also may not be optimal.)

  • detect_simple_bounds (bool) –

Return type:

OptiSol

Returns: An OptiSol object that contains the solved optimization problem. To extract values, use

my_optisol(variable).

Example:
>>> sol = opti.solve()
>>> x_opt = sol(x) # Get the value of variable x at the optimum.
solve_sweep(parameter_mapping, update_initial_guesses_between_solves=False, verbose=True, solve_kwargs=None, return_callable=False, garbage_collect_between_runs=False)[source]#
Parameters:
  • parameter_mapping (Dict[casadi.MX, aerosandbox.numpy.ndarray]) –

  • solve_kwargs (Dict) –

  • return_callable (bool) –

  • garbage_collect_between_runs (bool) –

Return type:

Union[aerosandbox.numpy.ndarray, Callable[[casadi.MX], aerosandbox.numpy.ndarray]]

find_variable_declaration(index, use_full_filename=False, return_string=False)[source]#
Parameters:
  • index (int) –

  • use_full_filename (bool) –

  • return_string (bool) –

Return type:

Union[None, str]

find_constraint_declaration(index, use_full_filename=False, return_string=False)[source]#
Parameters:
  • index (int) –

  • use_full_filename (bool) –

  • return_string (bool) –

Return type:

Union[None, str]

set_initial_from_sol(sol, initialize_primals=True, initialize_duals=True)[source]#

Sets the initial value of all variables in the Opti object to the solution of another Opti instance. Useful for warm-starting an Opti instance based on the result of another instance.

Args: sol: Takes in the solution object. Assumes that sol corresponds to exactly the same optimization problem as this Opti instance, perhaps with different parameter values.

Returns: None (in-place)

Parameters:

sol (casadi.OptiSol) –

Return type:

None

save_solution()[source]#
get_solution_dict_from_cache()[source]#
derivative_of(variable, with_respect_to, derivative_init_guess, derivative_scale=None, method='trapezoidal', explicit=False, _stacklevel=1)[source]#

Returns a quantity that is either defined or constrained to be a derivative of an existing variable.

For example:

>>> opti = Opti()
>>> position = opti.variable(init_guess=0, n_vars=100)
>>> time = np.linspace(0, 1, 100)
>>> velocity = opti.derivative_of(position, with_respect_to=time)
>>> acceleration = opti.derivative_of(velocity, with_respect_to=time)
Parameters:
  • variable (casadi.MX) – The variable or quantity that you are taking the derivative of. The “numerator” of the

  • derivative ("denominator" of the) –

  • parlance. (in colloquial) –

  • with_respect_to (Union[aerosandbox.numpy.ndarray, casadi.MX]) – The variable or quantity that you are taking the derivative with respect to. The

  • derivative – In a typical example case, this with_respect_to parameter would be time. Please make sure that the value of this parameter is monotonically increasing, otherwise you may get nonsensical answers.

  • parlance. – In a typical example case, this with_respect_to parameter would be time. Please make sure that the value of this parameter is monotonically increasing, otherwise you may get nonsensical answers.

  • derivative_init_guess (Union[float, aerosandbox.numpy.ndarray]) – Initial guess for the value of the derivative. Should be either a float (in which

  • same (case the initial guess will be a vector equal to this value) or a vector of initial guesses with the) –

  • info (length as variable. For more) –

  • parameter. (opti.variable()'s scale) –

  • derivative_scale (Union[float, aerosandbox.numpy.ndarray]) – Scale factor for the value of the derivative. For more info, look at the docstring of

  • parameter.

  • method (str) –

    The type of integrator to use to define this derivative. Options are:

    ”forward euler”, “backward euler”, and “midpoint” are all (lower-order) Runge-Kutta methods…

    • ”runge-kutta-3/8” - A modified version of the Runge-Kutta 4 proposed by Kutta in 1901. Also

    fourth-order-accurate, but all of the error coefficients are smaller than they are in the standard Runge-Kutta 4 method. The downside is that more floating point operations are required per timestep, as the Butcher tableau is more dense (i.e. not banded).

    Citation: Kutta, Martin (1901), “Beitrag zur näherungsweisen Integration totaler Differentialgleichungen”, Zeitschrift für Mathematik und Physik, 46: 435–453

  • explicit (bool) – If true, returns an explicit derivative rather than an implicit one. In other words,

  • a (this defines the output to be a derivative of the input rather than constraining the output to the) –

  • input. (derivative of the) –

    Explicit derivatives result in smaller, denser systems of equations that are more akin to shooting-type methods. Implicit derivatives result in larger, sparser systems of equations that are more akin to collocation methods. Explicit derivatives are better for simple, stable systems with few states, while implicit derivatives are better for complex, potentially-unstable systems with many states.

    # TODO implement explicit

  • _stacklevel (int) – Optional and advanced, purely used for debugging. Allows users to correctly track where

  • the (constraints are declared in the event that they are subclassing aerosandbox.Opti. Modifies) –

  • tracked (stacklevel of the declaration) –

  • using (which is then presented) –

  • `aerosandbox.Opti.variable_declaration

Return type:

casadi.MX

Returns: A vector consisting of the derivative of the parameter variable with respect to with_respect_to.

constrain_derivative(derivative, variable, with_respect_to, method='trapezoidal', _stacklevel=1)[source]#

Adds a constraint to the optimization problem such that:

d(variable) / d(with_respect_to) == derivative

Can be used directly; also called indirectly by opti.derivative_of() for implicit derivative creation.

Parameters:
  • derivative (casadi.MX) – The derivative that is to be constrained here.

  • variable (casadi.MX) – The variable or quantity that you are taking the derivative of. The “numerator” of the

  • derivative

  • parlance. (in colloquial) –

  • with_respect_to (Union[aerosandbox.numpy.ndarray, casadi.MX]) – The variable or quantity that you are taking the derivative with respect to. The

  • derivative – In a typical example case, this with_respect_to parameter would be time. Please make sure that the value of this parameter is monotonically increasing, otherwise you may get nonsensical answers.

  • parlance. – In a typical example case, this with_respect_to parameter would be time. Please make sure that the value of this parameter is monotonically increasing, otherwise you may get nonsensical answers.

  • method (str) –

    The type of integrator to use to define this derivative. Options are:

    ”forward euler”, “backward euler”, and “midpoint” are all (lower-order) Runge-Kutta methods…

    • ”runge-kutta-3/8” - A modified version of the Runge-Kutta 4 proposed by Kutta in 1901. Also

    fourth-order-accurate, but all of the error coefficients are smaller than they are in the standard Runge-Kutta 4 method. The downside is that more floating point operations are required per timestep, as the Butcher tableau is more dense (i.e. not banded).

    Citation: Kutta, Martin (1901), “Beitrag zur näherungsweisen Integration totaler Differentialgleichungen”, Zeitschrift für Mathematik und Physik, 46: 435–453

  • prevents (Note that all methods are expressed as integrators rather than differentiators; this) –

  • PDE (singularities from forming in the limit of timestep approaching zero. (For those coming from the) –

  • world

  • allow (this is analogous to using finite volume methods rather than finite difference methods to) –

  • capturing.) (shock) –

  • _stacklevel (int) – Optional and advanced, purely used for debugging. Allows users to correctly track where

  • the (constraints are declared in the event that they are subclassing aerosandbox.Opti. Modifies) –

  • tracked (stacklevel of the declaration) –

  • using (which is then presented) –

  • `aerosandbox.Opti.variable_declaration

Return type:

None

Returns: None (adds constraint in-place).

class aerosandbox.AeroSandboxObject[source]#

Bases: abc.ABC

Helper class that provides a standard way to create an ABC using inheritance.

_asb_metadata: Dict[str, str]#
__eq__(other)[source]#

Checks if two AeroSandbox objects are value-equivalent. A more sensible default for classes that represent physical objects than checking for memory equivalence.

This is done by checking if the two objects are of the same type and have the same __dict__.

Parameters:

other – Another object.

Returns:

True if the objects are equal, False otherwise.

Return type:

bool

save(filename=None, verbose=True, automatically_add_extension=True)[source]#

Saves the object to a binary file, using the dill library.

Creates a .asb file, which is a binary file that can be loaded with aerosandbox.load(). This can be loaded

into memory in a different Python session or a different computer, and it will be exactly the same as when it was saved.

Parameters:
  • filename (Union[str, pathlib.Path]) – The filename to save this object to. Should be a .asb file.

  • verbose (bool) – If True, prints messages to console on successful save.

  • automatically_add_extension (bool) – If True, automatically adds the .asb extension to the filename if it doesn’t already have it. If False, does not add the extension.

Return type:

None

Returns: None (writes to file)

copy()[source]#

Returns a shallow copy of the object.

deepcopy()[source]#

Returns a deep copy of the object.

substitute_solution(sol, inplace=None)[source]#

Substitutes a solution from CasADi’s solver recursively as an in-place operation.

In-place operation. To make it not in-place, do y = copy.deepcopy(x) or similar first. :param sol: OptiSol object. :return:

Parameters:
  • sol (casadi.OptiSol) –

  • inplace (bool) –

aerosandbox.load(filename, verbose=True)[source]#

Loads an AeroSandboxObject from a file.

Upon load, will compare metadata from the file to the current Python version and AeroSandbox version. If there are any discrepancies, will raise a warning.

Parameters:
  • filename (Union[str, pathlib.Path]) – The filename to load from. Should be a .asb file.

  • verbose (bool) – If True, prints messages to console on successful load.

Return type:

AeroSandboxObject

Returns: An AeroSandboxObject.

class aerosandbox.ExplicitAnalysis[source]#

Bases: AeroSandboxObject

Helper class that provides a standard way to create an ABC using inheritance.

default_analysis_specific_options: Dict[type, Dict[str, Any]]#

This is part of AeroSandbox’s “analysis-specific options” feature, which lets you “tag” geometry objects with flags that change how different analyses act on them.

This variable, default_analysis_specific_options, allows you to specify default values for options that can be used for specific problems.

This should be a dictionary, where: * keys are the geometry-like types that you might be interested in defining parameters for. * values are dictionaries, where: * keys are strings that label a given option * values are anything. These are used as the default values, in the event that the associated geometry doesn’t override those.

An example of what this variable might look like, for a vortex-lattice method aerodynamic analysis:

>>> default_analysis_specific_options = {
>>>     Airplane: dict(
>>>         profile_drag_coefficient=0
>>>     ),
>>>     Wing    : dict(
>>>         wing_level_spanwise_spacing=True,
>>>         spanwise_resolution=12,
>>>         spanwise_spacing="cosine",
>>>         chordwise_resolution=12,
>>>         chordwise_spacing="cosine",
>>>         component=None,  # type: int
>>>         no_wake=False,
>>>         no_alpha_beta=False,
>>>         no_load=False,
>>>         drag_polar=dict(
>>>             CL1=0,
>>>             CD1=0,
>>>             CL2=0,
>>>             CD2=0,
>>>             CL3=0,
>>>             CD3=0,
>>>         ),
>>>     )
>>> }
get_options(geometry_object)[source]#

Retrieves the analysis-specific options that correspond to both:

  • An analysis type (which is this object, “self”), and

  • A specific geometry object, such as an Airplane or Wing.

Parameters:

geometry_object (AeroSandboxObject) –

An instance of an AeroSandbox geometry object, such as an Airplane, Wing, etc.

  • In order for this function to do something useful, you probably want this option to have

analysis_specific_options defined. See the asb.Airplane constructor for an example of this.

Return type:

Dict[str, Any]

Returns: A dictionary that combines:

  • This analysis’s default options for this geometry, if any exist.

  • The geometry’s declared analysis-specific-options for this analysis, if it exists. These geometry

options will override the defaults from the analysis.

This dictionary has the format:

  • keys are strings, listing specific options

  • values can be any type, and simply state the value of the analysis-specific option following the

logic above.

Note: if this analysis defines a set of default options for the geometry type in question (by using self.default_analysis_specific_options), all keys from the geometry object’s analysis_specific_options will be validated against those in the default options set. A warning will be raised if keys do not correspond to those in the defaults, as this (potentially) indicates a typo, which would otherwise be difficult to debug.

class aerosandbox.ImplicitAnalysis[source]#

Bases: AeroSandboxObject

Helper class that provides a standard way to create an ABC using inheritance.

property opti#
property opti_provided#
static initialize(init_method)[source]#

A decorator that should be applied to the __init__ method of ImplicitAnalysis or any subclass of it.

Usage example:

>>> class MyAnalysis(ImplicitAnalysis):
>>>
>>>     @ImplicitAnalysis.initialize
>>>     def __init__(self):
>>>         self.a = self.opti.variable(init_guess = 1)
>>>         self.b = self.opti.variable(init_guess = 2)
>>>
>>>         self.opti.subject_to(
>>>             self.a == self.b ** 2
>>>         ) # Add a nonlinear governing equation

Functionality:

The basic purpose of this wrapper is to ensure that every ImplicitAnalysis has an opti property that points to an optimization environment (asb.Opti type) that it can work in.

How do we obtain an asb.Opti environment to work in? Well, this decorator adds an optional opti parameter to the __init__ method that it is applied to.

1. If this opti parameter is not provided, then a new empty asb.Opti environment is created and stored as ImplicitAnalysis.opti.

2. If the opti parameter is provided, then we simply assign the given asb.Opti environment (which may already contain other variables/constraints/objective) to ImplicitAnalysis.opti.

In addition, a property called ImplicitAnalysis.opti_provided is stored, which records whether the user provided an Opti environment or if one was instead created for them.

If the user did not provide an Opti environment (Option 1 from our list above), we assume that the user basically just wants to perform a normal, single-disciplinary analysis. So, in this case, we proceed to solve the analysis as-is and do an in-place substitution of the solution.

If the user did provide an Opti environment (Option 2 from our list above), we assume that the user might potentially want to add other implicit analyses to the problem. So, in this case, we don’t solve the analysis, and the user must later solve the analysis by calling sol = opti.solve() or similar.

class aerosandbox.Opti(variable_categories_to_freeze=None, cache_filename=None, load_frozen_variables_from_cache=False, save_to_cache_on_solve=False, ignore_violated_parametric_constraints=False, freeze_style='parameter')[source]#

Bases: casadi.Opti

The base class for mathematical optimization. For detailed usage, see the docstrings in its key methods:
  • Opti.variable()

  • Opti.subject_to()

  • Opti.parameter()

  • Opti.solve()

Example usage is as follows:

>>> opti = asb.Opti() # Initializes an optimization environment
>>> x = opti.variable(init_guess=5) # Initializes a new variable in that environment
>>> f = x ** 2 # Evaluates a (in this case, nonlinear) function based on a variable
>>> opti.subject_to(x > 3) # Adds a constraint to be enforced
>>> opti.minimize(f) # Sets the objective function as f
>>> sol = opti.solve() # Solves the problem using CasADi and IPOPT backend
>>> print(sol(x)) # Prints the value of x at the optimum.
Parameters:
  • variable_categories_to_freeze (Union[List[str], str]) –

  • cache_filename (str) –

  • load_frozen_variables_from_cache (bool) –

  • save_to_cache_on_solve (bool) –

  • ignore_violated_parametric_constraints (bool) –

  • freeze_style (str) –

variable(init_guess=None, n_vars=None, scale=None, freeze=False, log_transform=False, category='Uncategorized', lower_bound=None, upper_bound=None, _stacklevel=1)[source]#

Initializes a new decision variable (or vector of decision variables). You should pass an initial guess ( init_guess) upon defining a new variable. Dimensionality is inferred from this initial guess, but it can be overridden; see below for syntax.

It is highly, highly recommended that you provide a scale (scale) for each variable, especially for nonconvex problems, although this is not strictly required.

Usage notes:

When using vector variables, individual components of this vector of variables can be accessed via normal indexing. Example:

>>> opti = asb.Opti()
>>> my_var = opti.variable(n_vars = 5)
>>> opti.subject_to(my_var[3] >= my_var[2])  # This is a valid way of indexing
>>> my_sum = asb.sum(my_var)  # This will sum up all elements of `my_var`
Parameters:
  • init_guess (Union[float, aerosandbox.numpy.ndarray]) –

    Initial guess for the optimal value of the variable being initialized. This is where in the design space the optimizer will start looking.

    This can be either a float or a NumPy ndarray; the dimension of the variable (i.e. scalar, vector) that is created will be automatically inferred from the shape of the initial guess you provide here. (Although it can also be overridden using the n_vars parameter; see below.)

    For scalar variables, your initial guess should be a float:

    >>> opti = asb.Opti()
    >>> scalar_var = opti.variable(init_guess=5) # Initializes a scalar variable at a value of 5
    

    For vector variables, your initial guess should be either:

    • a float, in which case you must pass the length of the vector as n_vars, otherwise a scalar

    variable will be created:

    >>> opti = asb.Opti()
    >>> vector_var = opti.variable(init_guess=5, n_vars=10) # Initializes a vector variable of length
    >>> # 10, with all 10 elements set to an initial guess of 5.
    
    • a NumPy ndarray, in which case each element will be initialized to the corresponding value in

    the given array:

    >>> opti = asb.Opti()
    >>> vector_var = opti.variable(init_guess=np.linspace(0, 5, 10)) # Initializes a vector variable of
    >>> # length 10, with all 10 elements initialized to linearly vary between 0 and 5.
    

    In the case where the variable is to be log-transformed (see log_transform), the initial guess should not be log-transformed as well - just supply the initial guess as usual. (Log-transform of the initial guess happens under the hood.) The initial guess must, of course, be a positive number in this case.

  • n_vars (int) –

    [Optional] Used to manually override the dimensionality of the variable to create; if not provided, the dimensionality of the variable is inferred from the initial guess init_guess.

    The only real case where you need to use this argument would be if you are initializing a vector variable to a scalar value, but you don’t feel like using init_guess=value * np.ones(n_vars). For example:

    >>> opti = asb.Opti()
    >>> vector_var = opti.variable(init_guess=5, n_vars=10) # Initializes a vector variable of length
    >>> # 10, with all 10 elements set to an initial guess of 5.
    

  • scale (float) –

    [Optional] Approximate scale of the variable.

    For example, if you’re optimizing the design of a automobile and setting the tire diameter as an optimization variable, you might choose scale=0.5, corresponding to 0.5 meters.

    Properly scaling your variables can have a huge impact on solution speed (or even if the optimizer converges at all). Although most modern second-order optimizers (such as IPOPT, used here) are theoretically scale-invariant, numerical precision issues due to floating-point arithmetic can make solving poorly-scaled problems really difficult or impossible. See here for more info: https://web.casadi.org/blog/nlp-scaling/

    If not specified, the code will try to pick a sensible value by defaulting to the init_guess.

  • freeze (bool) –

    [Optional] This boolean tells the optimizer to “freeze” the variable at a specific value. In order to select the determine to freeze the variable at, the optimizer will use the following logic:

    • If you initialize a new variable with the parameter freeze=True: the optimizer will freeze

    the variable at the value of initial guess.

    >>> opti = Opti()
    >>> my_var = opti.variable(init_guess=5, freeze=True) # This will freeze my_var at a value of 5.
    
    • If the Opti instance is associated with a cache file, and you told it to freeze a specific

    category(s) of variables that your variable is a member of, and you didn’t manually specify to freeze the variable: the variable will be frozen based on the value in the cache file (and ignore the init_guess). Example:

    >>> opti = Opti(cache_filename="my_file.json", variable_categories_to_freeze=["Wheel Sizing"])
    >>> # Assume, for example, that `my_file.json` was from a previous run where my_var=10.
    >>> my_var = opti.variable(init_guess=5, category="Wheel Sizing")
    >>> # This will freeze my_var at a value of 10 (from the cache file, not the init_guess)
    
    • If the Opti instance is associated with a cache file, and you told it to freeze a specific

    category(s) of variables that your variable is a member of, but you then manually specified that the variable should be frozen: the variable will once again be frozen at the value of init_guess:

    >>> opti = Opti(cache_filename="my_file.json", variable_categories_to_freeze=["Wheel Sizing"])
    >>> # Assume, for example, that `my_file.json` was from a previous run where my_var=10.
    >>> my_var = opti.variable(init_guess=5, category="Wheel Sizing", freeze=True)
    >>> # This will freeze my_var at a value of 5 (`freeze` overrides category loading.)
    

    Motivation for freezing variables:

    The ability to freeze variables is exceptionally useful when designing engineering systems. Let’s say we’re designing an airplane. In the beginning of the design process, we’re doing “clean-sheet” design - any variable is up for grabs for us to optimize on, because the airplane doesn’t exist yet! However, the farther we get into the design process, the more things get “locked in” - we may have ordered jigs, settled on a wingspan, chosen an engine, et cetera. So, if something changes later ( let’s say that we discover that one of our assumptions was too optimistic halfway through the design process), we have to make up for that lost margin using only the variables that are still free. To do this, we would freeze the variables that are already decided on.

    By categorizing variables, you can also freeze entire categories of variables. For example, you can freeze all of the wing design variables for an airplane but leave all of the fuselage variables free.

    This idea of freezing variables can also be used to look at off-design performance - freeze a design, but change the operating conditions.

  • log_transform (bool) – [Optional] Advanced use only. A flag of whether to internally-log-transform this variable before passing it to the optimizer. Good for known positive engineering quantities that become nonsensical if negative (e.g. mass). Log-transforming these variables can also help maintain convexity.

  • category (str) – [Optional] What category of variables does this belong to? # TODO expand docs

  • lower_bound (float) – [Optional] If provided, defines a bounds constraint on the new variable that keeps the variable above a given value.

  • upper_bound (float) – [Optional] If provided, defines a bounds constraint on the new variable that keeps the variable below a given value.

  • _stacklevel (int) – Optional and advanced, purely used for debugging. Allows users to correctly track where variables are declared in the event that they are subclassing aerosandbox.Opti. Modifies the stacklevel of the declaration tracked, which is then presented using aerosandbox.Opti.variable_declaration().

Returns:

The variable itself as a symbolic CasADi variable (MX type).

Return type:

casadi.MX

subject_to(constraint, _stacklevel=1)[source]#

Initialize a new equality or inequality constraint(s).

Parameters:
  • constraint (Union[casadi.MX, bool, List]) –

    A constraint that you want to hold true at the optimum.

    Inequality example:

    >>> x = opti.variable()
    >>> opti.subject_to(x >= 5)
    

    Equality example; also showing that you can directly constrain functions of variables:

    >>> x = opti.variable()
    >>> f = np.sin(x)
    >>> opti.subject_to(f == 0.5)
    

    You can also pass in a list of multiple constraints using list syntax. For example:

    >>> x = opti.variable()
    >>> opti.subject_to([
    >>>     x >= 5,
    >>>     x <= 10
    >>> ])
    

  • _stacklevel (int) – Optional and advanced, purely used for debugging. Allows users to correctly track where

  • the (constraints are declared in the event that they are subclassing aerosandbox.Opti. Modifies) –

  • tracked (stacklevel of the declaration) –

  • using (which is then presented) –

  • aerosandbox.Opti.constraint_declaration().

Returns:

The dual variable associated with the new constraint. If the constraint input is a list, returns a list of dual variables.

Return type:

Union[casadi.MX, None, List[casadi.MX]]

minimize(f)[source]#

[INTERNAL]

minimize(self, MX f)

Set objective.

Objective must be a scalar. Default objective: 0 When method is called

multiple times, the last call takes effect

Extra doc: https://github.com/casadi/casadi/wiki/L_1a

Doc source: https://github.com/casadi/casadi/blob/develop/casadi/core/optistack.hpp#L133

Implementation: https://github.com/casadi/casadi/blob/develop/casadi/core/optistack.cpp#L82-L88

Parameters:

f (casadi.MX) –

Return type:

None

maximize(f)[source]#
Parameters:

f (casadi.MX) –

Return type:

None

parameter(value=0.0, n_params=None)[source]#

Initializes a new parameter (or vector of parameters). You must pass a value (value) upon defining a new parameter. Dimensionality is inferred from this value, but it can be overridden; see below for syntax.

Parameters:
  • value (Union[float, aerosandbox.numpy.ndarray]) –

    Value to set the new parameter to.

    This can either be a float or a NumPy ndarray; the dimension of the parameter (i.e. scalar, vector) that is created will be automatically inferred from the shape of the value you provide here. (Although it can be overridden using the n_params parameter; see below.)

    For scalar parameters, your value should be a float: >>> opti = asb.Opti() >>> scalar_param = opti.parameter(value=5) # Initializes a scalar parameter and sets its value to 5.

    For vector variables, your value should be either:

    • a float, in which case you must pass the length of the vector as n_params, otherwise a scalar

    parameter will be created:

    >>> opti = asb.Opti()
    >>> vector_param = opti.parameter(value=5, n_params=10) # Initializes a vector parameter of length
    >>> # 10, with all 10 elements set to value of 5.
    
    • a NumPy ndarray, in which case each element will be set to the corresponding value in the given

    array:

    >>> opti = asb.Opti()
    >>> vector_param = opti.parameter(value=np.linspace(0, 5, 10)) # Initializes a vector parameter of
    >>> # length 10, with all 10 elements set to a value varying from 0 to 5.
    

  • n_params (int) –

    [Optional] Used to manually override the dimensionality of the parameter to create; if not provided, the dimensionality of the parameter is inferred from value.

    The only real case where you need to use this argument would be if you are initializing a vector parameter to a scalar value, but you don’t feel like using value=my_value * np.ones(n_vars). For example:

    >>> opti = asb.Opti()
    >>> vector_param = opti.parameter(value=5, n_params=10) # Initializes a vector parameter of length
    >>> # 10, with all 10 elements set to a value of 5.
    

Returns:

The parameter itself as a symbolic CasADi variable (MX type).

Return type:

casadi.MX

solve(parameter_mapping=None, max_iter=1000, max_runtime=1e+20, callback=None, verbose=True, jit=False, detect_simple_bounds=False, options=None, behavior_on_failure='raise')[source]#

Solve the optimization problem using CasADi with IPOPT backend.

Parameters:
  • parameter_mapping (Dict[casadi.MX, float]) –

    [Optional] Allows you to specify values for parameters. Dictionary where the key is the parameter and the value is the value to be set to.

    Example: # TODO update syntax for required init_guess
    >>> opti = asb.Opti()
    >>> x = opti.variable()
    >>> p = opti.parameter()
    >>> opti.minimize(x ** 2)
    >>> opti.subject_to(x >= p)
    >>> sol = opti.solve(
    >>>     {
    >>>         p: 5 # Sets the value of parameter p to 5, then solves.
    >>>     }
    >>> )
    

  • max_iter (int) – [Optional] The maximum number of iterations allowed before giving up.

  • max_runtime (float) – [Optional] Gives the maximum allowable runtime before giving up.

  • callback (Callable[[int], Any]) –

    [Optional] A function to be called at each iteration of the optimization algorithm. Useful for printing progress or displaying intermediate results.

    The callback function func should have the syntax func(iteration_number), where iteration_number is an integer corresponding to the current iteration number. In order to access intermediate quantities of optimization variables (e.g. for plotting), use the Opti.debug.value(x) syntax for each variable x.

  • verbose (bool) – Controls the verbosity of the solver. If True, IPOPT will print its progress to the console.

  • jit (bool) – Experimental. If True, the optimization problem will be compiled to C++ and then JIT-compiled using the CasADi JIT compiler. This can lead to significant speedups, but may also lead to unexpected behavior, and may not work on all platforms.

  • options (Dict) – [Optional] A dictionary of options to pass to IPOPT. See the IPOPT documentation for a list of available options.

  • behavior_on_failure (str) –

    [Optional] What should we do if the optimization fails? Options are:

    • ”raise”: Raise an exception. This is the default behavior.

    • ”return_last”: Returns the solution from the last iteration, and raise a warning.

      NOTE: The returned solution may not be feasible! (It also may not be optimal.)

  • detect_simple_bounds (bool) –

Return type:

OptiSol

Returns: An OptiSol object that contains the solved optimization problem. To extract values, use

my_optisol(variable).

Example:
>>> sol = opti.solve()
>>> x_opt = sol(x) # Get the value of variable x at the optimum.
solve_sweep(parameter_mapping, update_initial_guesses_between_solves=False, verbose=True, solve_kwargs=None, return_callable=False, garbage_collect_between_runs=False)[source]#
Parameters:
  • parameter_mapping (Dict[casadi.MX, aerosandbox.numpy.ndarray]) –

  • solve_kwargs (Dict) –

  • return_callable (bool) –

  • garbage_collect_between_runs (bool) –

Return type:

Union[aerosandbox.numpy.ndarray, Callable[[casadi.MX], aerosandbox.numpy.ndarray]]

find_variable_declaration(index, use_full_filename=False, return_string=False)[source]#
Parameters:
  • index (int) –

  • use_full_filename (bool) –

  • return_string (bool) –

Return type:

Union[None, str]

find_constraint_declaration(index, use_full_filename=False, return_string=False)[source]#
Parameters:
  • index (int) –

  • use_full_filename (bool) –

  • return_string (bool) –

Return type:

Union[None, str]

set_initial_from_sol(sol, initialize_primals=True, initialize_duals=True)[source]#

Sets the initial value of all variables in the Opti object to the solution of another Opti instance. Useful for warm-starting an Opti instance based on the result of another instance.

Args: sol: Takes in the solution object. Assumes that sol corresponds to exactly the same optimization problem as this Opti instance, perhaps with different parameter values.

Returns: None (in-place)

Parameters:

sol (casadi.OptiSol) –

Return type:

None

save_solution()[source]#
get_solution_dict_from_cache()[source]#
derivative_of(variable, with_respect_to, derivative_init_guess, derivative_scale=None, method='trapezoidal', explicit=False, _stacklevel=1)[source]#

Returns a quantity that is either defined or constrained to be a derivative of an existing variable.

For example:

>>> opti = Opti()
>>> position = opti.variable(init_guess=0, n_vars=100)
>>> time = np.linspace(0, 1, 100)
>>> velocity = opti.derivative_of(position, with_respect_to=time)
>>> acceleration = opti.derivative_of(velocity, with_respect_to=time)
Parameters:
  • variable (casadi.MX) – The variable or quantity that you are taking the derivative of. The “numerator” of the

  • derivative ("denominator" of the) –

  • parlance. (in colloquial) –

  • with_respect_to (Union[aerosandbox.numpy.ndarray, casadi.MX]) – The variable or quantity that you are taking the derivative with respect to. The

  • derivative – In a typical example case, this with_respect_to parameter would be time. Please make sure that the value of this parameter is monotonically increasing, otherwise you may get nonsensical answers.

  • parlance. – In a typical example case, this with_respect_to parameter would be time. Please make sure that the value of this parameter is monotonically increasing, otherwise you may get nonsensical answers.

  • derivative_init_guess (Union[float, aerosandbox.numpy.ndarray]) – Initial guess for the value of the derivative. Should be either a float (in which

  • same (case the initial guess will be a vector equal to this value) or a vector of initial guesses with the) –

  • info (length as variable. For more) –

  • parameter. (opti.variable()'s scale) –

  • derivative_scale (Union[float, aerosandbox.numpy.ndarray]) – Scale factor for the value of the derivative. For more info, look at the docstring of

  • parameter.

  • method (str) –

    The type of integrator to use to define this derivative. Options are:

    ”forward euler”, “backward euler”, and “midpoint” are all (lower-order) Runge-Kutta methods…

    • ”runge-kutta-3/8” - A modified version of the Runge-Kutta 4 proposed by Kutta in 1901. Also

    fourth-order-accurate, but all of the error coefficients are smaller than they are in the standard Runge-Kutta 4 method. The downside is that more floating point operations are required per timestep, as the Butcher tableau is more dense (i.e. not banded).

    Citation: Kutta, Martin (1901), “Beitrag zur näherungsweisen Integration totaler Differentialgleichungen”, Zeitschrift für Mathematik und Physik, 46: 435–453

  • explicit (bool) – If true, returns an explicit derivative rather than an implicit one. In other words,

  • a (this defines the output to be a derivative of the input rather than constraining the output to the) –

  • input. (derivative of the) –

    Explicit derivatives result in smaller, denser systems of equations that are more akin to shooting-type methods. Implicit derivatives result in larger, sparser systems of equations that are more akin to collocation methods. Explicit derivatives are better for simple, stable systems with few states, while implicit derivatives are better for complex, potentially-unstable systems with many states.

    # TODO implement explicit

  • _stacklevel (int) – Optional and advanced, purely used for debugging. Allows users to correctly track where

  • the (constraints are declared in the event that they are subclassing aerosandbox.Opti. Modifies) –

  • tracked (stacklevel of the declaration) –

  • using (which is then presented) –

  • `aerosandbox.Opti.variable_declaration

Return type:

casadi.MX

Returns: A vector consisting of the derivative of the parameter variable with respect to with_respect_to.

constrain_derivative(derivative, variable, with_respect_to, method='trapezoidal', _stacklevel=1)[source]#

Adds a constraint to the optimization problem such that:

d(variable) / d(with_respect_to) == derivative

Can be used directly; also called indirectly by opti.derivative_of() for implicit derivative creation.

Parameters:
  • derivative (casadi.MX) – The derivative that is to be constrained here.

  • variable (casadi.MX) – The variable or quantity that you are taking the derivative of. The “numerator” of the

  • derivative

  • parlance. (in colloquial) –

  • with_respect_to (Union[aerosandbox.numpy.ndarray, casadi.MX]) – The variable or quantity that you are taking the derivative with respect to. The

  • derivative – In a typical example case, this with_respect_to parameter would be time. Please make sure that the value of this parameter is monotonically increasing, otherwise you may get nonsensical answers.

  • parlance. – In a typical example case, this with_respect_to parameter would be time. Please make sure that the value of this parameter is monotonically increasing, otherwise you may get nonsensical answers.

  • method (str) –

    The type of integrator to use to define this derivative. Options are:

    ”forward euler”, “backward euler”, and “midpoint” are all (lower-order) Runge-Kutta methods…

    • ”runge-kutta-3/8” - A modified version of the Runge-Kutta 4 proposed by Kutta in 1901. Also

    fourth-order-accurate, but all of the error coefficients are smaller than they are in the standard Runge-Kutta 4 method. The downside is that more floating point operations are required per timestep, as the Butcher tableau is more dense (i.e. not banded).

    Citation: Kutta, Martin (1901), “Beitrag zur näherungsweisen Integration totaler Differentialgleichungen”, Zeitschrift für Mathematik und Physik, 46: 435–453

  • prevents (Note that all methods are expressed as integrators rather than differentiators; this) –

  • PDE (singularities from forming in the limit of timestep approaching zero. (For those coming from the) –

  • world

  • allow (this is analogous to using finite volume methods rather than finite difference methods to) –

  • capturing.) (shock) –

  • _stacklevel (int) – Optional and advanced, purely used for debugging. Allows users to correctly track where

  • the (constraints are declared in the event that they are subclassing aerosandbox.Opti. Modifies) –

  • tracked (stacklevel of the declaration) –

  • using (which is then presented) –

  • `aerosandbox.Opti.variable_declaration

Return type:

None

Returns: None (adds constraint in-place).

class aerosandbox.OptiSol(opti, cas_optisol)[source]#
Parameters:
  • opti (Opti) –

  • cas_optisol (casadi.OptiSol) –

__call__(x)[source]#

A shorthand alias for sol.value(x). See OptiSol.value() documentation for details.

Parameters:

x (Union[casadi.MX, aerosandbox.numpy.ndarray, float, int, List, Tuple, Set, Dict, Any]) – A Python data structure to substitute values into, using the solution in this OptiSol object.

Returns:

A copy of x, where all symbolic optimization variables (recursively substituted at unlimited depth) have been converted to float or array values.

Return type:

Any

_value_scalar(x)[source]#

Gets the value of a variable at the solution point. For developer use - see following paragraph.

This method is basically a less-powerful version of calling sol(x) - if you’re a

user and not a developer, you almost-certainly want to use that method instead, as those are less fragile with respect to various input data types. This method exists only as an abstraction to make it easier for other developers to subclass OptiSol, if they wish to intercept the variable substitution process.

Parameters:

x (Union[casadi.MX, aerosandbox.numpy.ndarray, float, int]) –

Return type:

Union[float, aerosandbox.numpy.ndarray]

Returns:

value(x, recursive=True, warn_on_unknown_types=False)[source]#
Gets the value of a variable (or a data structure) at the solution point. This solution point is the optimum,

if the optimization process solved successfully.

On a computer science level, this method converts a symbolic optimization variable to a concrete float or

array value. More generally, it converts any Python data structure (along with any of its contents, recursively, at unlimited depth), replacing any symbolic optimization variables it finds with concrete float or array values.

Note that, for convenience, you can simply call: >>> sol(x) if you prefer. This is equivalent to calling this method with the syntax: >>> sol.value(x) (these are aliases of each other)

Parameters:
  • x (Union[casadi.MX, aerosandbox.numpy.ndarray, float, int, List, Tuple, Set, Dict, Any]) – A Python data structure to substitute values into, using the solution in this OptiSol object.

  • recursive (bool) – If True, the substitution will be performed recursively. Otherwise, only the top-level data structure will be converted.

  • warn_on_unknown_types (bool) – If True, a warning will be issued if a data type that cannot be converted or parsed as definitively un-convertable is encountered.

Returns:

A copy of x, where all symbolic optimization variables (recursively substituted at unlimited depth)

have been converted to float or array values.

Return type:

Any

Usage:

stats()[source]#
Return type:

Dict[str, Any]

value_variables()[source]#
value_parameters()[source]#
show_infeasibilities(tol=0.001)[source]#

Prints a summary of any violated constraints in the solution.

Parameters:

tol (float) – The tolerance for violation. If the constraint is violated by less than this amount, it will not be printed.

Return type:

None

Returns: None (prints to console)

class aerosandbox.FittedModel(model, x_data, y_data, parameter_guesses, parameter_bounds=None, residual_norm_type='L2', fit_type='best', weights=None, put_residuals_in_logspace=False, verbose=True)[source]#

Bases: aerosandbox.modeling.surrogate_model.SurrogateModel

A model that is fitted to data. Maps from R^N -> R^1.

You can evaluate this model at a given point by calling it just like a function, e.g.:

>>> my_fitted_model = FittedModel(...)  # See FittedModel.__init__ docstring for syntax
>>> y = my_fitted_model(x)
The input to the model (x in the example above) is of the type:
  • in the general N-dimensional case, a dictionary where: keys are variable names and values are float/array

  • in the case of a 1-dimensional input (R^1 -> R^1), a float/array.

If you’re not sure what the input type of my_fitted_model should be, just do:

>>> print(my_fitted_model) # Displays the valid input type to the model

The output of the model (y in the example above) is always a float or array.

See the docstring __init__ method of FittedModel for more details of how to instantiate and use FittedModel.

One might have expected a fitted model to be a literal Python function rather than a Python class - the benefit of having FittedModel as a class rather than a function is that you can easily save (pickle) classes including data (e.g. parameters, x_data, y_data), but you can’t do that with functions. And, because the FittedModel class has a __call__ method, you can basically still just think of it like a function.

Parameters:
  • model (Callable[[Union[aerosandbox.numpy.ndarray, Dict[str, aerosandbox.numpy.ndarray]], Dict[str, float]], aerosandbox.numpy.ndarray]) –

  • x_data (Union[aerosandbox.numpy.ndarray, Dict[str, aerosandbox.numpy.ndarray]]) –

  • y_data (aerosandbox.numpy.ndarray) –

  • parameter_guesses (Dict[str, float]) –

  • parameter_bounds (Dict[str, tuple]) –

  • residual_norm_type (str) –

  • fit_type (str) –

  • weights (aerosandbox.numpy.ndarray) –

  • put_residuals_in_logspace (bool) –

__call__(x)[source]#

Evaluates the surrogate model at some given input x.

The input x is of the type:
  • in the general N-dimensional case, a dictionary where keys are variable names and values are float/array.

  • in the case of a 1-dimensional input (R^1 -> R^2), a float/array.

goodness_of_fit(type='R^2')[source]#

Returns a metric of the goodness of the fit.

Parameters:

type

Type of metric to use for goodness of fit. One of:

  • ”R^2”: The coefficient of determination. Strictly speaking only mathematically rigorous to use this

for linear fits.

  • ”mean_absolute_error” or “mae” or “L1”: The mean absolute error of the fit.

  • ”root_mean_squared_error” or “rms” or “L2”: The root mean squared error of the fit.

  • ”max_absolute_error” or “Linf”: The maximum deviation of the fit from any of the data points.

Returns: The metric of the goodness of the fit.

class aerosandbox.InterpolatedModel(x_data_coordinates, y_data_structured, method='bspline', fill_value=np.nan)[source]#

Bases: aerosandbox.modeling.surrogate_model.SurrogateModel

A model that is interpolated to structured (i.e., gridded) N-dimensional data. Maps from R^N -> R^1.

You can evaluate this model at a given point by calling it just like a function, e.g.:

>>> y = my_interpolated_model(x)
The input to the model (x in the example above) is of the type:
  • in the general N-dimensional case, a dictionary where: keys are variable names and values are float/array

  • in the case of a 1-dimensional input (R^1 -> R^1), it can optionally just be a float/array.

If you’re not sure what the input type of my_interpolated_model should be, just do:

>>> print(my_interpolated_model) # Displays the valid input type to the model

The output of the model (y in the example above) is always a float or array.

See the docstring __init__ method of InterpolatedModel for more details of how to instantiate and use InterpolatedModel.

One might have expected a interpolated model to be a literal Python function rather than a Python class - the benefit of having InterpolatedModel as a class rather than a function is that you can easily save (pickle) classes including data (e.g. parameters, x_data, y_data), but you can’t do that with functions. And, because the InterpolatedModel class has a __call__ method, you can basically still just think of it like a function.

Parameters:
  • x_data_coordinates (Union[aerosandbox.numpy.ndarray, Dict[str, aerosandbox.numpy.ndarray]]) –

  • y_data_structured (aerosandbox.numpy.ndarray) –

  • method (str) –

__call__(x)[source]#

Evaluates the surrogate model at some given input x.

The input x is of the type:
  • in the general N-dimensional case, a dictionary where keys are variable names and values are float/array.

  • in the case of a 1-dimensional input (R^1 -> R^2), a float/array.

class aerosandbox.UnstructuredInterpolatedModel(x_data, y_data, x_data_resample=10, resampling_interpolator=interpolate.RBFInterpolator, resampling_interpolator_kwargs=None, fill_value=np.nan, interpolated_model_kwargs=None)[source]#

Bases: aerosandbox.modeling.interpolation.InterpolatedModel

A model that is interpolated to unstructured (i.e., point cloud) N-dimensional data. Maps from R^N -> R^1.

You can evaluate this model at a given point by calling it just like a function, e.g.:

>>> y = my_interpolated_model(x)
The input to the model (x in the example above) is of the type:
  • in the general N-dimensional case, a dictionary where: keys are variable names and values are float/array

  • in the case of a 1-dimensional input (R^1 -> R^1), it can optionally just be a float/array.

If you’re not sure what the input type of my_interpolated_model should be, just do:

>>> print(my_interpolated_model) # Displays the valid input type to the model

The output of the model (y in the example above) is always a float or array.

See the docstring __init__ method of InterpolatedModel for more details of how to instantiate and use UnstructuredInterpolatedModel.

Parameters:
  • x_data (Union[aerosandbox.numpy.ndarray, Dict[str, aerosandbox.numpy.ndarray]]) –

  • y_data (aerosandbox.numpy.ndarray) –

  • x_data_resample (Union[int, Dict[str, Union[int, aerosandbox.numpy.ndarray]]]) –

  • resampling_interpolator (object) –

  • resampling_interpolator_kwargs (Dict[str, Any]) –

  • interpolated_model_kwargs (Dict[str, Any]) –

aerosandbox.black_box(function, n_in=None, n_out=1, fd_method='central', fd_step=None, fd_step_iter=None)[source]#

Wraps a function as a black box, allowing it to be used in AeroSandbox / CasADi optimization problems.

Obtains gradients via finite differences. Assumes that the function’s Jacobian is fully dense, always.

Parameters:
  • function (Callable[[Any], float]) –

  • n_in (int) –

  • n_out (int) –

  • fd_method (str) – One of: - ‘forward’ - ‘backward’ - ‘central’ - ‘smoothed’

  • fd_step (Optional[float]) –

  • fd_step_iter (Optional[bool]) –

Return type:

Callable[[Any], float]

Returns:

class aerosandbox.Airfoil(name='Untitled', coordinates=None, **deprecated_keyword_arguments)[source]#

Bases: aerosandbox.geometry.polygon.Polygon

An airfoil. See constructor docstring for usage details.

Parameters:
  • name (str) –

  • coordinates (Union[None, str, pathlib.Path, aerosandbox.numpy.ndarray]) –

__repr__()[source]#

Return repr(self).

Return type:

str

to_kulfan_airfoil(n_weights_per_side=8, N1=0.5, N2=1.0, normalize_coordinates=True, use_leading_edge_modification=True)[source]#
Parameters:
  • n_weights_per_side (int) –

  • N1 (float) –

  • N2 (float) –

  • normalize_coordinates (bool) –

  • use_leading_edge_modification (bool) –

Return type:

aerosandbox.geometry.airfoil.kulfan_airfoil.KulfanAirfoil

generate_polars(alphas=np.linspace(-13, 13, 27), Res=np.geomspace(1000.0, 100000000.0, 12), cache_filename=None, xfoil_kwargs=None, unstructured_interpolated_model_kwargs=None, include_compressibility_effects=True, transonic_buffet_lift_knockdown=0.3, make_symmetric_polars=False)[source]#

Generates airfoil polar surrogate models (CL, CD, CM functions) from XFoil data and assigns them in-place to this Airfoil’s polar functions.

In other words, when this function is run, the following functions will be added (or overwritten) to the instance:
  • Airfoil.CL_function(alpha, Re, mach)

  • Airfoil.CD_function(alpha, Re, mach)

  • Airfoil.CM_function(alpha, Re, mach)

Where alpha is in degrees.

Warning: In-place operation! Modifies this Airfoil object by setting Airfoil.CL_function, etc. to the new polars.

Parameters:
  • alphas – The range of alphas to sample from XFoil at. Given in degrees.

  • Res – The range of Reynolds numbers to sample from XFoil at. Dimensionless.

  • cache_filename (str) –

    A path-like filename (ideally a “*.json” file) that can be used to cache the XFoil results, making it much faster to regenerate the results.

    • If the file does not exist, XFoil will be run, and a cache file will be created.

    • If the file does exist, XFoil will not be run, and the cache file will be read instead.

  • xfoil_kwargs (Dict[str, Any]) – Keyword arguments to pass into the AeroSandbox XFoil module. See the aerosandbox.XFoil constructor for options.

  • unstructured_interpolated_model_kwargs (Dict[str, Any]) – Keyword arguments to pass into the UnstructuredInterpolatedModels that contain the polars themselves. See the aerosandbox.UnstructuredInterpolatedModel constructor for options.

  • include_compressibility_effects (bool) – Includes compressibility effects in the polars, such as wave drag, mach tuck, CL effects across normal shocks. Note that accuracy here is dubious in the transonic regime and above - you should really specify your own CL/CD/CM models

  • transonic_buffet_lift_knockdown (float) –

  • make_symmetric_polars (bool) –

Return type:

None

Returns: None (in-place), adds the following functions to the instance:

  • Airfoil.CL_function(alpha, Re, mach)

  • Airfoil.CD_function(alpha, Re, mach)

  • Airfoil.CM_function(alpha, Re, mach)

get_aero_from_neuralfoil(alpha, Re, mach=0.0, n_crit=9.0, xtr_upper=1.0, xtr_lower=1.0, model_size='large', control_surfaces=None, include_360_deg_effects=True)[source]#
Parameters:
  • alpha (Union[float, aerosandbox.numpy.ndarray]) –

  • Re (Union[float, aerosandbox.numpy.ndarray]) –

  • mach (Union[float, aerosandbox.numpy.ndarray]) –

  • n_crit (Union[float, aerosandbox.numpy.ndarray]) –

  • xtr_upper (Union[float, aerosandbox.numpy.ndarray]) –

  • xtr_lower (Union[float, aerosandbox.numpy.ndarray]) –

  • model_size (str) –

  • control_surfaces (List[ControlSurface]) –

  • include_360_deg_effects (bool) –

Return type:

Dict[str, Union[float, aerosandbox.numpy.ndarray]]

plot_polars(alphas=np.linspace(-20, 20, 500), Res=10**np.arange(3, 9), mach=0.0, show=True, Re_colors=None)[source]#
Parameters:
  • alphas (Union[aerosandbox.numpy.ndarray, List[float]]) –

  • Res (Union[aerosandbox.numpy.ndarray, List[float]]) –

  • mach (float) –

  • show (bool) –

Return type:

None

local_camber(x_over_c=np.linspace(0, 1, 101))[source]#

Returns the local camber of the airfoil at a given point or points.

Parameters:

x_over_c (Union[float, aerosandbox.numpy.ndarray]) – The x/c locations to calculate the camber at [1D array, more generally, an iterable of floats]

Returns:

Local camber of the airfoil (y/c) [1D array].

Return type:

Union[float, aerosandbox.numpy.ndarray]

local_thickness(x_over_c=np.linspace(0, 1, 101))[source]#

Returns the local thickness of the airfoil at a given point or points.

Parameters:

x_over_c (Union[float, aerosandbox.numpy.ndarray]) – The x/c locations to calculate the thickness at [1D array, more generally, an iterable of floats]

Returns:

Local thickness of the airfoil (y/c) [1D array].

Return type:

Union[float, aerosandbox.numpy.ndarray]

max_camber(x_over_c_sample=np.linspace(0, 1, 101))[source]#

Returns the maximum camber of the airfoil.

Parameters:

x_over_c_sample (aerosandbox.numpy.ndarray) – Where should the airfoil be sampled to determine the max camber?

Return type:

float

Returns: The maximum thickness, as a fraction of chord.

max_thickness(x_over_c_sample=np.linspace(0, 1, 101))[source]#

Returns the maximum thickness of the airfoil.

Parameters:

x_over_c_sample (aerosandbox.numpy.ndarray) – Where should the airfoil be sampled to determine the max thickness?

Return type:

float

Returns: The maximum thickness, as a fraction of chord.

draw(draw_mcl=False, draw_markers=True, backend='matplotlib', show=True)[source]#

Draw the airfoil object.

Parameters:
  • draw_mcl – Should we draw the mean camber line (MCL)? [boolean]

  • backend – Which backend should we use? “plotly” or “matplotlib”

  • show – Should we show the plot? [boolean]

Return type:

None

Returns: None

LE_index()[source]#

Returns the index of the leading edge point in the airfoil coordinates.

Return type:

int

lower_coordinates()[source]#

Returns an Nx2 ndarray of [x, y] coordinates that describe the lower surface of the airfoil.

Order is from the leading edge to the trailing edge.

Includes the leading edge point; be careful about duplicates if using this method in conjunction with Airfoil.upper_coordinates().

Return type:

aerosandbox.numpy.ndarray

upper_coordinates()[source]#

Returns an Nx2 ndarray of [x, y] coordinates that describe the upper surface of the airfoil.

Order is from the trailing edge to the leading edge.

Includes the leading edge point; be careful about duplicates if using this method in conjunction with Airfoil.lower_coordinates().

Return type:

aerosandbox.numpy.ndarray

LE_radius(softness=1e-06)[source]#
Parameters:

softness (float) –

TE_thickness()[source]#

Returns the thickness of the trailing edge of the airfoil.

Return type:

float

TE_angle()[source]#

Returns the trailing edge angle of the airfoil, in degrees.

Return type:

float

repanel(n_points_per_side=100, spacing_function_per_side=np.cosspace)[source]#

Returns a repaneled copy of the airfoil with cosine-spaced coordinates on the upper and lower surfaces.

Parameters:
  • n_points_per_side (int) –

    Number of points per side (upper and lower) of the airfoil [int]

    Notes: The number of points defining the final airfoil will be n_points_per_side * 2 - 1, since one point (the leading edge point) is shared by both the upper and lower surfaces.

  • spacing_function_per_side – Determines how to space the points on each side of the airfoil. Can be np.linspace or np.cosspace, or any other function of the call signature f(a, b, n) that returns a spaced array of n points between a and b. [function]

Return type:

Airfoil

Returns: A copy of the airfoil with the new coordinates.

normalize(return_dict=False)[source]#
Returns a copy of the Airfoil with a new set of coordinates, such that:
  • The leading edge (LE) is at (0, 0)

  • The trailing edge (TE) is at (1, 0)

  • The chord length is equal to 1

The trailing-edge (TE) point is defined as the midpoint of the line segment connecting the first and last coordinate points (upper and lower surface TE points, respectively). The TE point is not necessarily one of the original points in the airfoil coordinates (Airfoil.coordinates); in general, it will not be one of the points if the TE thickness is nonzero.

The leading-edge (LE) point is defined as the coordinate point with the largest Euclidian distance from the trailing edge. (In other words, if you were to center a circle on the trailing edge and progressively grow it, what’s the last coordinate point that it would intersect?) The LE point is always one of the original points in the airfoil coordinates.

The chord is defined as the Euclidian distance between the LE and TE points.

Coordinate modifications to achieve the constraints described above (LE @ origin, TE at (1, 0), and chord of 1) are done by means of a translation and rotation.

Parameters:

return_dict (bool) –

Determines the output type of the function. - If False (default), returns a copy of the Airfoil with the new coordinates. - If True, returns a dictionary with keys:

  • ”airfoil”: a copy of the Airfoil with the new coordinates

  • ”x_translation”: the amount by which the airfoil’s LE was translated in the x-direction

  • ”y_translation”: the amount by which the airfoil’s LE was translated in the y-direction

  • ”scale_factor”: the amount by which the airfoil was scaled (if >1, the airfoil had to get

    bigger)

  • ”rotation_angle”: the angle (in degrees) by which the airfoil was rotated about the LE.

    Sign convention is that positive angles rotate the airfoil counter-clockwise.

All of thes values represent the “required change”, e.g.:

  • ”x_translation” is the amount by which the airfoil’s LE had to be translated in the

    x-direction to get it to the origin.

  • ”rotation_angle” is the angle (in degrees) by which the airfoil had to be rotated (CCW).

Return type:

Union[Airfoil, Dict[str, Union[Airfoil, float]]]

Returns: Depending on the value of return_dict, either:

  • A copy of the airfoil with the new coordinates (default), or

  • A dictionary with keys “airfoil”, “x_translation”, “y_translation”, “scale_factor”, and “rotation_angle”.

    documentation for return_tuple for more information.

add_control_surface(deflection=0.0, hinge_point_x=0.75, modify_coordinates=True, modify_polars=True)[source]#

Returns a version of the airfoil with a trailing-edge control surface added at a given point. Implicitly repanels the airfoil as part of this operation.

Parameters:
  • deflection (float) – Deflection angle [degrees]. Downwards-positive.

  • hinge_point_x (float) – Chordwise location of the hinge, as a fraction of chord (x/c) [float]

  • modify_coordinates (bool) –

  • modify_polars (bool) –

Return type:

Airfoil

Returns: an Airfoil object with the new control deflection.

set_TE_thickness(thickness=0.0)[source]#

Creates a modified copy of the Airfoil that has a specified trailing-edge thickness.

Note that the trailing-edge thickness is given nondimensionally (e.g., as a fraction of chord).

Parameters:

thickness (float) – The target trailing-edge thickness, given nondimensionally (e.g., as a fraction of chord).

Return type:

Airfoil

Returns: The modified airfoil.

scale(scale_x=1.0, scale_y=1.0)[source]#

Scales an Airfoil about the origin.

Parameters:
  • scale_x (float) – Amount to scale in the x-direction.

  • scale_y (float) – Amount to scale in the y-direction. Scaling by a negative y-value will result in coordinates being re-ordered such that the order of the coordinates is still correct (i.e., starts from the upper-surface trailing edge, continues along the upper surface to the nose, then continues along the lower surface to the trailing edge).

Return type:

Airfoil

Returns: A copy of the Airfoil with appropriate scaling applied.

translate(translate_x=0.0, translate_y=0.0)[source]#

Translates an Airfoil by a given amount. :param translate_x: Amount to translate in the x-direction :param translate_y: Amount to translate in the y-direction

Returns: The translated Airfoil.

Parameters:
  • translate_x (float) –

  • translate_y (float) –

Return type:

Airfoil

rotate(angle, x_center=0.0, y_center=0.0)[source]#

Rotates the airfoil clockwise by the specified amount, in radians.

Rotates about the point (x_center, y_center), which is (0, 0) by default.

Parameters:
  • angle (float) – Angle to rotate, counterclockwise, in radians.

  • x_center (float) – The x-coordinate of the center of rotation.

  • y_center (float) – The y-coordinate of the center of rotation.

Return type:

Airfoil

Returns: The rotated Airfoil.

blend_with_another_airfoil(airfoil, blend_fraction=0.5, n_points_per_side=100)[source]#

Blends this airfoil with another airfoil. Merges both the coordinates and the aerodynamic functions.

Parameters:
  • airfoil (Airfoil) – The other airfoil to blend with.

  • blend_fraction (float) –

    The fraction of the other airfoil to use when blending. Defaults to 0.5 (50%).

    • A blend fraction of 0 will return an identical airfoil to this one (self).

    • A blend fraction of 1 will return an identical airfoil to the other one (airfoil parameter).

  • n_points_per_side (int) – The number of points per side to use when blending the coordinates of the two airfoils.

Return type:

Airfoil

Returns: A new airfoil that is a blend of this airfoil and another one.

write_dat(filepath=None, include_name=True)[source]#

Writes a .dat file corresponding to this airfoil to a filepath.

Parameters:
  • filepath (Union[str, pathlib.Path]) – filepath (including the filename and .dat extension) [string] If None, this function returns the .dat file as a string.

  • include_name (bool) – Should the name be included in the .dat file? (In a standard *.dat file, it usually is.)

Return type:

str

Returns: None

class aerosandbox.KulfanAirfoil(name='Untitled', lower_weights=None, upper_weights=None, leading_edge_weight=0.0, TE_thickness=0.0, N1=0.5, N2=1.0)[source]#

Bases: aerosandbox.geometry.airfoil.airfoil.Airfoil

An airfoil. See constructor docstring for usage details.

Parameters:
  • name (str) –

  • lower_weights (aerosandbox.numpy.ndarray) –

  • upper_weights (aerosandbox.numpy.ndarray) –

  • leading_edge_weight (float) –

  • TE_thickness (float) –

  • N1 (float) –

  • N2 (float) –

property kulfan_parameters#
property coordinates: aerosandbox.numpy.ndarray#
Return type:

aerosandbox.numpy.ndarray

__repr__()[source]#

Return repr(self).

Return type:

str

to_airfoil(n_coordinates_per_side=200, spacing_function_per_side=np.cosspace)[source]#
Return type:

aerosandbox.geometry.airfoil.airfoil.Airfoil

repanel(n_points_per_side=100, spacing_function_per_side=np.cosspace)[source]#

Returns a repaneled copy of the airfoil with cosine-spaced coordinates on the upper and lower surfaces.

Parameters:
  • n_points_per_side (int) –

    Number of points per side (upper and lower) of the airfoil [int]

    Notes: The number of points defining the final airfoil will be n_points_per_side * 2 - 1, since one point (the leading edge point) is shared by both the upper and lower surfaces.

  • spacing_function_per_side – Determines how to space the points on each side of the airfoil. Can be np.linspace or np.cosspace, or any other function of the call signature f(a, b, n) that returns a spaced array of n points between a and b. [function]

Return type:

aerosandbox.geometry.airfoil.airfoil.Airfoil

Returns: A copy of the airfoil with the new coordinates.

normalize(return_dict=False)[source]#
Returns a copy of the Airfoil with a new set of coordinates, such that:
  • The leading edge (LE) is at (0, 0)

  • The trailing edge (TE) is at (1, 0)

  • The chord length is equal to 1

The trailing-edge (TE) point is defined as the midpoint of the line segment connecting the first and last coordinate points (upper and lower surface TE points, respectively). The TE point is not necessarily one of the original points in the airfoil coordinates (Airfoil.coordinates); in general, it will not be one of the points if the TE thickness is nonzero.

The leading-edge (LE) point is defined as the coordinate point with the largest Euclidian distance from the trailing edge. (In other words, if you were to center a circle on the trailing edge and progressively grow it, what’s the last coordinate point that it would intersect?) The LE point is always one of the original points in the airfoil coordinates.

The chord is defined as the Euclidian distance between the LE and TE points.

Coordinate modifications to achieve the constraints described above (LE @ origin, TE at (1, 0), and chord of 1) are done by means of a translation and rotation.

Parameters:

return_dict (bool) –

Determines the output type of the function. - If False (default), returns a copy of the Airfoil with the new coordinates. - If True, returns a dictionary with keys:

  • ”airfoil”: a copy of the Airfoil with the new coordinates

  • ”x_translation”: the amount by which the airfoil’s LE was translated in the x-direction

  • ”y_translation”: the amount by which the airfoil’s LE was translated in the y-direction

  • ”scale_factor”: the amount by which the airfoil was scaled (if >1, the airfoil had to get

    bigger)

  • ”rotation_angle”: the angle (in degrees) by which the airfoil was rotated about the LE.

    Sign convention is that positive angles rotate the airfoil counter-clockwise.

All of thes values represent the “required change”, e.g.:

  • ”x_translation” is the amount by which the airfoil’s LE had to be translated in the

    x-direction to get it to the origin.

  • ”rotation_angle” is the angle (in degrees) by which the airfoil had to be rotated (CCW).

Return type:

Union[KulfanAirfoil, Dict[str, Union[KulfanAirfoil, float]]]

Returns: Depending on the value of return_dict, either:

  • A copy of the airfoil with the new coordinates (default), or

  • A dictionary with keys “airfoil”, “x_translation”, “y_translation”, “scale_factor”, and “rotation_angle”.

    documentation for return_tuple for more information.

draw(*args, draw_markers=False, **kwargs)[source]#

Draw the airfoil object.

Parameters:
  • draw_mcl – Should we draw the mean camber line (MCL)? [boolean]

  • backend – Which backend should we use? “plotly” or “matplotlib”

  • show – Should we show the plot? [boolean]

Returns: None

get_aero_from_neuralfoil(alpha, Re, mach=0.0, n_crit=9.0, xtr_upper=1.0, xtr_lower=1.0, model_size='large', control_surfaces=None, include_360_deg_effects=True)[source]#
Parameters:
  • alpha (Union[float, aerosandbox.numpy.ndarray]) –

  • Re (Union[float, aerosandbox.numpy.ndarray]) –

  • mach (Union[float, aerosandbox.numpy.ndarray]) –

  • n_crit (Union[float, aerosandbox.numpy.ndarray]) –

  • xtr_upper (Union[float, aerosandbox.numpy.ndarray]) –

  • xtr_lower (Union[float, aerosandbox.numpy.ndarray]) –

  • model_size (str) –

  • control_surfaces (List[ControlSurface]) –

  • include_360_deg_effects (bool) –

Return type:

Dict[str, Union[float, aerosandbox.numpy.ndarray]]

upper_coordinates(x_over_c=np.linspace(1, 0, 101))[source]#

Returns an Nx2 ndarray of [x, y] coordinates that describe the upper surface of the airfoil.

Order is from the trailing edge to the leading edge.

Includes the leading edge point; be careful about duplicates if using this method in conjunction with Airfoil.lower_coordinates().

Parameters:

x_over_c (Union[float, aerosandbox.numpy.ndarray]) –

Return type:

aerosandbox.numpy.ndarray

lower_coordinates(x_over_c=np.linspace(0, 1, 101))[source]#

Returns an Nx2 ndarray of [x, y] coordinates that describe the lower surface of the airfoil.

Order is from the leading edge to the trailing edge.

Includes the leading edge point; be careful about duplicates if using this method in conjunction with Airfoil.upper_coordinates().

Parameters:

x_over_c (Union[float, aerosandbox.numpy.ndarray]) –

Return type:

aerosandbox.numpy.ndarray

local_camber(x_over_c=np.linspace(0, 1, 101))[source]#

Returns the local camber of the airfoil at a given point or points.

Parameters:

x_over_c (Union[float, aerosandbox.numpy.ndarray]) – The x/c locations to calculate the camber at [1D array, more generally, an iterable of floats]

Returns:

Local camber of the airfoil (y/c) [1D array].

Return type:

Union[float, aerosandbox.numpy.ndarray]

local_thickness(x_over_c=np.linspace(0, 1, 101))[source]#

Returns the local thickness of the airfoil at a given point or points.

Parameters:

x_over_c (Union[float, aerosandbox.numpy.ndarray]) – The x/c locations to calculate the thickness at [1D array, more generally, an iterable of floats]

Returns:

Local thickness of the airfoil (y/c) [1D array].

Return type:

Union[float, aerosandbox.numpy.ndarray]

LE_radius(relative_softness=0.03)[source]#
Parameters:

relative_softness (float) –

TE_angle()[source]#

Returns the trailing edge angle of the airfoil, in degrees.

area()[source]#

Returns the area of the polygon.

set_TE_thickness(thickness=0.0)[source]#

Creates a modified copy of the KulfanAirfoil that has a specified trailing-edge thickness.

Note that the trailing-edge thickness is given nondimensionally (e.g., as a fraction of chord).

Parameters:

thickness (float) – The target trailing-edge thickness, given nondimensionally (e.g., as a fraction of chord).

Return type:

KulfanAirfoil

Returns: The modified KulfanAirfoil.

scale(scale_x=1.0, scale_y=1.0)[source]#

Scales a KulfanAirfoil about the origin.

Parameters:
  • scale_x (float) – Amount to scale in the x-direction. Note: not supported by KulfanAirfoil due to inherent limitations of parameterization; only given here so that argument symmetry to Airfoil.scale() is retained. Raises a ValueError if modified, along with instructions to use Airfoil if needed.

  • scale_y (float) – Amount to scale in the y-direction. Scaling by a negative y-value will result in lower_weights and upper_weights being flipped as appropriate.

Return type:

KulfanAirfoil

Returns: A copy of the KulfanAirfoil with appropriate scaling applied.

blend_with_another_airfoil(airfoil, blend_fraction=0.5)[source]#

Blends this airfoil with another airfoil. Merges both the coordinates and the aerodynamic functions.

Parameters:
  • airfoil (Union[KulfanAirfoil, aerosandbox.geometry.airfoil.airfoil.Airfoil]) – The other airfoil to blend with.

  • blend_fraction (float) –

    The fraction of the other airfoil to use when blending. Defaults to 0.5 (50%).

    • A blend fraction of 0 will return an identical airfoil to this one (self).

    • A blend fraction of 1 will return an identical airfoil to the other one (airfoil parameter).

  • n_points_per_side – The number of points per side to use when blending the coordinates of the two airfoils.

Return type:

KulfanAirfoil

Returns: A new airfoil that is a blend of this airfoil and another one.

class aerosandbox.Wing(name=None, xsecs=None, symmetric=False, color=None, analysis_specific_options=None, **kwargs)[source]#

Bases: aerosandbox.common.AeroSandboxObject

Definition for a Wing.

Anatomy of a Wing:

A wing consists chiefly of a collection of cross-sections, or “xsecs”. A cross-section is a 2D “slice” of a wing. These can be accessed with Wing.xsecs, which gives a list of xsecs in the Wing. Each xsec is a WingXSec object, a class that is defined separately.

You may also see references to wing “sections”, which are different than cross-sections (xsecs)! Sections are the portions of the wing that are in between xsecs. In other words, a wing with N cross-sections (xsecs, WingXSec objects) will always have N-1 sections. Sections are never explicitly defined, since you can get all needed information by lofting from the adjacent cross-sections. For example, section 0 (the first one) is a loft between cross-sections 0 and 1.

Wings are lofted linearly between cross-sections.

If the wing is symmetric across the XZ plane, just define the right half and supply symmetric=True in the constructor.

If the wing is not symmetric across the XZ plane (e.g., a single vertical stabilizer), just define the wing.

Parameters:
  • name (Optional[str]) –

  • xsecs (List[WingXSec]) –

  • symmetric (bool) –

  • color (Optional[Union[str, Tuple[float]]]) –

  • analysis_specific_options (Optional[Dict[type, Dict[str, Any]]]) –

__repr__()[source]#

Return repr(self).

Return type:

str

translate(xyz)[source]#

Translates the entire Wing by a certain amount.

Parameters:

xyz (Union[aerosandbox.numpy.ndarray, List[float]]) –

Return type:

Wing

Returns: The new wing object.

span(type='yz', include_centerline_distance=False, _sectional=False)[source]#

Computes the span, with options for various ways of measuring this (see type argument).

If the wing is symmetric, both left/right sides are included in order to obtain the full span. In the case where the root cross-section is not coincident with the center plane (e.g., XZ plane), this function’s behavior depends on the include_centerline_distance argument.

Parameters:
  • type (str) –

    One of the following options, as a string:

    • ”xyz”: First, computes the quarter-chord point of each WingXSec. Then, connects these with

    straight lines. Then, adds up the lengths of these lines.

    • ”xy” or “top”: Same as “xyz”, except it projects each line segment onto the XY plane before adding up the

    lengths.

    • ”yz” (default) or “front”: Same as “xyz”, except it projects each line segment onto the YZ plane (i.e., front view)

    before adding up the lengths.

    • ”xz” or “side”: Same as “xyz”, except it projects each line segment onto the XZ plane before adding up the

    lengths. Rarely needed.

    • ”x”: Same as “xyz”, except it only counts the x-components of each line segment when adding up the

    lengths.

    • ”y”: Same as “xyz”, except it only counts the y-components of each line segment when adding up the

    lengths.

    • ”z”: Same as “xyz”, except it only counts the z-components of each line segment when adding up the

    lengths.

  • include_centerline_distance – A boolean flag that tells the function what to do if a wing’s root is not

  • plane (coincident with the centerline) –

    • If True, we first figure out which WingXSec has its quarter-chord point closest to the centerline

    plane (i.e., XZ plane). Then, we compute the distance from that quarter-chord point directly to the centerline plane (along Y). We then add that distance to the span calculation. In other words, the fictitious span connecting the left and right root cross-sections is included.

    • If False, this distance is ignored. In other words, the fictitious span connecting the left and

    right root cross-sections is not included. This is the default behavior.

    Note: For computation, either the root WingXSec (i.e., index=0) or the tip WingXSec (i.e., index=-1) is used, whichever is closer to the centerline plane. This will almost-always be the root WingXSec, but some weird edge cases (e.g., a half-wing defined on the left-hand-side of the airplane, rather than the conventional right-hand side) will result in the tip WingXSec being used.

  • _sectional (bool) – A boolean. If False, returns the total span. If True, returns a list of spans for each of the n-1 lofted sections (between the n wing cross-sections in wing.xsec).

Return type:

Union[float, List[float]]

area(type='planform', include_centerline_distance=False, _sectional=False)[source]#

Computes the wing area, with options for various ways of measuring this (see type argument):

If the wing is symmetric, both left/right sides are included in order to obtain the full area. In the case where the root cross-section is not coincident with the center plane (e.g., XZ plane), this function’s behavior depends on the include_centerline_distance argument.

Parameters:
  • type (str) –

    One of the following options, as a string:

    • ”planform” (default): First, lofts a quadrilateral mean camber surface between each WingXSec. Then,

    computes the area of each of these sectional surfaces. Then, sums up all the areas and returns it. When airplane designers refer to “wing area” (in the absence of any other qualifiers), this is typically what they mean.

    • ”wetted”: Computes the actual surface area of the wing that is in contact with the air. Will

    typically be a little more than double the “planform” area above; intuitively, this is because it adds both the “top” and “bottom” surface areas. Accounts for airfoil thickness/shape effects.

    • ”xy” or “projected” or “top”: Same as “planform”, but each sectional surface is projected onto the XY plane

    (i.e., top-down view) before computing the areas. Note that if you try to use this method with a vertically-oriented wing, like most vertical stabilizers, you will get an area near zero.

    • ”xz” or “side”: Same as “planform”, but each sectional surface is projected onto the XZ plane before

    computing the areas.

  • include_centerline_distance – A boolean flag that tells the function what to do if a wing’s root chord is

  • plane (not coincident with the centerline) –

    • If True, we first figure out which WingXSec is closest to the centerline plane (i.e., XZ plane).

    Then, we imagine that this WingXSec is extruded along the Y axis to the centerline plane (assuming a straight extrusion to produce a rectangular mid-camber surface). In doing so, we use the wing geometric chord as the extrusion width. We then add the area of this fictitious surface to the area calculation.

    • If False, this function will simply ignore this fictitious wing area. This is the default behavior.

  • _sectional (bool) – A boolean. If False, returns the total area. If True, returns a list of areas for each of the n-1 lofted sections (between the n wing cross-sections in wing.xsec).

Return type:

Union[float, List[float]]

aspect_ratio(type='geometric')[source]#

Computes the aspect ratio of the wing, with options for various ways of measuring this.

  • geometric: geometric aspect ratio, computed in the typical fashion (b^2 / S).

  • effective: Differs from the geometric aspect ratio only in the case of symmetric wings whose root

cross-section is not on the centerline. In these cases, it includes the span and area of the fictitious wing center when computing aspect ratio.

Parameters:

type (str) – One of the above options, as a string.

Return type:

float

is_entirely_symmetric()[source]#
Return type:

bool

mean_geometric_chord()[source]#

Returns the mean geometric chord of the wing (S/b). :return:

Return type:

float

mean_aerodynamic_chord()[source]#

Computes the length of the mean aerodynamic chord of the wing. Uses the generalized methodology described here:

Returns: The length of the mean aerodynamic chord.

Return type:

float

mean_twist_angle()[source]#

Returns the mean twist angle (in degrees) of the wing, weighted by area. :return: mean twist angle (in degrees)

Return type:

float

mean_sweep_angle(x_nondim=0.25)[source]#

Returns the mean sweep angle (in degrees) of the wing, relative to the x-axis. Positive sweep is backwards, negative sweep is forward.

This is purely measured from root to tip, with no consideration for the sweep of the individual cross-sections in between.

Parameters:

x_nondim

The nondimensional x-coordinate of the cross-section to use for sweep angle computation.

  • If you provide 0, it will use the leading edge of the cross-section.

  • If you provide 0.25, it will use the quarter-chord point of the cross-section.

  • If you provide 1, it will use the trailing edge of the cross-section.

Returns:

The mean sweep angle, in degrees.

Return type:

float

mean_dihedral_angle(x_nondim=0.25)[source]#

Returns the mean dihedral angle (in degrees) of the wing, relative to the XY plane. Positive dihedral is bending up, negative dihedral is bending down.

This is purely measured from root to tip, with no consideration for the dihedral of the individual cross-sections in between.

Parameters:

x_nondim

The nondimensional x-coordinate of the cross-section to use for sweep angle computation.

  • If you provide 0, it will use the leading edge of the cross-section.

  • If you provide 0.25, it will use the quarter-chord point of the cross-section.

  • If you provide 1, it will use the trailing edge of the cross-section.

Returns:

The mean dihedral angle, in degrees

Return type:

float

aerodynamic_center(chord_fraction=0.25, _sectional=False)[source]#

Computes the location of the aerodynamic center of the wing. Uses the generalized methodology described here:

Args: chord_fraction: The position of the aerodynamic center along the MAC, as a fraction of MAC length.

Typically, this value (denoted h_0 in the literature) is 0.25 for a subsonic wing. However, wing-fuselage interactions can cause a forward shift to a value more like 0.1 or less. Citing Cook, Michael V., “Flight Dynamics Principles”, 3rd Ed., Sect. 3.5.3 “Controls-fixed static stability”. PDF: https://www.sciencedirect.com/science/article/pii/B9780080982427000031

Returns: The (x, y, z) coordinates of the aerodynamic center of the wing.

Parameters:

chord_fraction (float) –

Return type:

aerosandbox.numpy.ndarray

taper_ratio()[source]#

Gives the taper ratio of the Wing. Strictly speaking, only valid for trapezoidal wings.

Returns:

Taper ratio of the Wing.

Return type:

float

volume(_sectional=False)[source]#

Computes the volume of the Wing.

Parameters:
  • _sectional (bool) – A boolean. If False, returns the total volume. If True, returns a list of volumes for each of

  • sections (the n-1 lofted) –

Returns:

The computed volume.

Return type:

Union[float, List[float]]

get_control_surface_names()[source]#

Gets the names of all control surfaces on this wing.

Returns:

A list of control surface names.

Return type:

List[str]

set_control_surface_deflections(control_surface_mappings)[source]#

Sets the deflection of all control surfaces on this wing, based on the provided mapping.

Parameters:

control_surface_mappings (Dict[str, float]) –

A dictionary mapping control surface names to their deflection angles, in degrees.

Note: control surface names are set in the asb.ControlSurface constructor.

Returns:

None. (in-place)

Return type:

None

control_surface_area(by_name=None, type='planform')[source]#

Computes the total area of all control surfaces on this wing, optionally filtered by their name.

Control surfaces are defined on a section-by-section basis, and are defined in the WingXSec constructor using its control_surfaces argument.

Note: If redundant control surfaces are defined (e.g., elevons, as defined by separate ailerons + elevator), the area will be duplicated.

If the wing is symmetric, control surfaces on both left/right sides are included in order to obtain the full area.

Parameters:
  • by_name (Optional[str]) –

    If not None, only control surfaces with this name will be included in the area calculation.

    Note: control surface names are set in the asb.ControlSurface constructor.

  • type (Optional[str]) –

    One of the following options, as a string:

    • ”planform” (default): First, lofts a quadrilateral mean camber surface between each WingXSec. Then,

    computes the area of each of these sectional surfaces. Then, computes what fraction of this area is control surface. Then, sums up all the areas and returns it. When airplane designers refer to “control surface area” (in the absence of any other qualifiers), this is typically what they mean.

    • ”wetted”: Computes the actual surface area of the control surface that is in contact with the air.

    Will typically be a little more than double the “planform” area above; intuitively, this is because it adds both the “top” and “bottom” surface areas. Accounts for airfoil thickness/shape effects.

    • ”xy” or “projected” or “top”: Same as “planform”, but each sectional surface is projected onto the XY plane

    (i.e., top-down view) before computing the areas. Note that if you try to use this method with a vertically-oriented wing, like most vertical stabilizers, you will get an area near zero.

    • ”xz” or “side”: Same as “planform”, but each sectional surface is projected onto the XZ plane before

    computing the areas.

Return type:

float

mesh_body(method='quad', chordwise_resolution=36, chordwise_spacing_function_per_side=np.cosspace, mesh_surface=True, mesh_tips=True, mesh_trailing_edge=True, mesh_symmetric=True)[source]#

Meshes the outer mold line surface of the wing.

Uses the (points, faces) standard mesh format. For reference on this format, see the documentation in aerosandbox.geometry.mesh_utilities.

Order of faces:

  • On the right wing (or, if Wing.symmetric is False, just the wing itself):

    • If mesh_surface is True:

      • First face is nearest the top-side trailing edge of the wing root.

      • Proceeds chordwise, along the upper surface of the wing from back to front. Upon reaching the

      leading edge, continues along the lower surface of the wing from front to back.

      • Then, repeats this process for the next spanwise slice of the wing, and so on.

    • If mesh_trailing_edge is True:

      • Continues by meshing the trailing edge of the wing. Meshes the inboard trailing edge first, then

      proceeds spanwise to the outboard trailing edge.

    • If mesh_tips is True:

      • Continues by meshing the wing tips. Meshes the inboard tip first, then meshes the outboard tip.

      • Within each tip, meshes from the

Parameters:
  • method

    One of the following options, as a string:

    • ”tri”: Triangular mesh.

    • ”quad”: Quadrilateral mesh.

  • chordwise_resolution (int) – Number of points to use per wing chord, per wing section.

  • chordwise_spacing_function_per_side (Callable[[float, float, float], aerosandbox.numpy.ndarray]) – A function that determines how to space points in the chordwise

  • np.cosspace (direction along the top and bottom surfaces. Common values would be np.linspace or) –

  • mesh_surface (bool) –

  • mesh_tips (bool) –

  • mesh_trailing_edge (bool) –

  • mesh_symmetric (bool) –

Return type:

Tuple[aerosandbox.numpy.ndarray, aerosandbox.numpy.ndarray]

:param : :param but it can be any function with the call signature f: :type but it can be any function with the call signature `f: a, b, n :param between `a and b. [function]: :param mesh_surface: If True, includes the actual wing surface in the mesh. :param mesh_tips: If True, includes the wing tips (both on the inboard-most section and on the outboard-most :param section) in the mesh.: :param mesh_trailing_edge: If True, includes the wing trailing edge in the mesh, if the trailing-edge thickness :param is nonzero.: :param mesh_symmetric: Has no effect if the wing is not symmetric. If the wing is symmetric this determines whether :param the generated mesh is also symmetric: :type the generated mesh is also symmetric: right side :param or if if only one side of the wing: :type or if if only one side of the wing: right side

Returns: Standard unstructured mesh format: A tuple of points and faces, where:

  • points is a n x 3 array of points, where n is the number of points in the mesh.

  • faces is a m x 3 array of faces if method is “tri”, or a m x 4 array of faces if method is “quad”.

    • Each row of faces is a list of indices into points, which specifies a face.

mesh_thin_surface(method='tri', chordwise_resolution=36, chordwise_spacing_function=np.cosspace, add_camber=True)[source]#

Meshes the mean camber line of the wing as a thin-sheet body.

Uses the (points, faces) standard mesh format. For reference on this format, see the documentation in aerosandbox.geometry.mesh_utilities.

Order of faces:
  • On the right wing (or, if Wing.symmetric is False, just the wing itself):
    • First face is the face nearest the leading edge of the wing root.

    • Proceeds along a chordwise strip to the trailing edge.

    • Then, goes to the subsequent spanwise location and does another chordwise strip, et cetera until we get to the wing tip.

  • On the left wing (applicable only if Wing.symmetric is True):
    • Same order: Starts at the root leading edge, goes in chordwise strips.

Order of vertices within each face:
  • On the right wing (or, if Wing.symmetric is False, just the wing itself):
    • Front-left

    • Back-left

    • Back-right

    • Front-right

  • On the left wing (applicable only if Wing.symmetric is True):
    • Front-left

    • Back-left

    • Back-right

    • Front-right

Parameters:
  • method

    A string, which determines whether to mesh the fuselage as a series of quadrilaterals or triangles.

    • ”quad” meshes the fuselage as a series of quadrilaterals.

    • ”tri” meshes the fuselage as a series of triangles.

  • chordwise_resolution (int) – Determines the number of chordwise panels to use in the meshing. [int]

  • chordwise_spacing_function (Callable[[float, float, float], aerosandbox.numpy.ndarray]) – Determines how to space the chordwise panels. Can be np.linspace or

  • np.cosspace (a, b, n) –

  • `f (or any other function of the call signature) –

  • [function] (n points between a and b.) –

  • add_camber (bool) – Controls whether to mesh the thin surface with camber (i.e., mean camber line), or to just

  • [bool] (mesh the flat planform.) –

Return type:

Tuple[aerosandbox.numpy.ndarray, aerosandbox.numpy.ndarray]

Returns: Standard unstructured mesh format: A tuple of points and faces, where:

  • points is a n x 3 array of points, where n is the number of points in the mesh.

  • faces is a m x 3 array of faces if method is “tri”, or a m x 4 array of faces if method is “quad”.

    • Each row of faces is a list of indices into points, which specifies a face.

mesh_line(x_nondim=0.25, z_nondim=0, add_camber=True)[source]#

Meshes a line that goes through each of the WingXSec objects in this wing.

Parameters:
  • x_nondim (Union[float, List[float]]) – The nondimensional (chord-normalized) x-coordinate that the line should go through. Can either

  • cross-sections (value used at all) –

  • the (or can be an iterable of values to be used at) –

  • cross-sections. (respective) –

  • z_nondim (Union[float, List[float]]) – The nondimensional (chord-normalized) y-coordinate that the line should go through. Here,

  • component (y-coordinate means the "vertical") –

  • cross-sections

  • cross (or can be an iterable of values to be used at the respective) –

  • sections.

  • add_camber (bool) – Controls whether the camber of each cross-section’s airfoil should be added to the line or

  • camber. (not. Essentially modifies z_nondim to be z_nondim +) –

Return type:

List[aerosandbox.numpy.ndarray]

Returns: A list of points, where each point is a 3-element array of the form [x, y, z]. Goes from the root to the tip. Ignores any wing symmetry (e.g., only gives one side).

draw(*args, **kwargs)[source]#

An alias to the more general Airplane.draw() method. See there for documentation.

Parameters:
  • *args – Arguments to pass through to Airplane.draw()

  • **kwargs – Keyword arguments to pass through to Airplane.draw()

Returns: Same return as Airplane.draw()

draw_wireframe(*args, **kwargs)[source]#

An alias to the more general Airplane.draw_wireframe() method. See there for documentation.

Parameters:
  • *args – Arguments to pass through to Airplane.draw_wireframe()

  • **kwargs – Keyword arguments to pass through to Airplane.draw_wireframe()

Returns: Same return as Airplane.draw_wireframe()

draw_three_view(*args, **kwargs)[source]#

An alias to the more general Airplane.draw_three_view() method. See there for documentation.

Parameters:
  • *args – Arguments to pass through to Airplane.draw_three_view()

  • **kwargs – Keyword arguments to pass through to Airplane.draw_three_view()

Returns: Same return as Airplane.draw_three_view()

subdivide_sections(ratio, spacing_function=np.linspace)[source]#

Generates a new Wing that subdivides the existing sections of this Wing into several smaller ones. Splits each section into N=`ratio` smaller sub-sections by inserting new cross-sections (xsecs) as needed.

This can allow for finer aerodynamic resolution of sectional properties in certain analyses.

Parameters:
  • ratio (int) – The number of new sections to split each old section into.

  • spacing_function (Callable[[float, float, float], aerosandbox.numpy.ndarray]) –

    A function that takes in three arguments: the start, end, and number of points to generate.

    The default is np.linspace, which generates a linearly-spaced array of points.

    Other options include np.cosspace, which generates a cosine-spaced array of points.

Return type:

Wing

Returns: A new Wing object with subdivided sections.

_compute_xyz_le_of_WingXSec(index)[source]#
Parameters:

index (int) –

_compute_xyz_te_of_WingXSec(index)[source]#
Parameters:

index (int) –

_compute_xyz_of_WingXSec(index, x_nondim, z_nondim)[source]#
_compute_frame_of_WingXSec(index)[source]#

Computes the local reference frame associated with a particular cross-section (XSec) of this wing.

Parameters:

index (int) – Which cross-section (as indexed in Wing.xsecs) should we get the frame of?

Returns:

A tuple of (xg_local, yg_local, zg_local), where each entry refers to the respective (normalized) axis of the local reference frame of the WingXSec. Given in geometry axes.

Return type:

Tuple[aerosandbox.numpy.ndarray, aerosandbox.numpy.ndarray, aerosandbox.numpy.ndarray]

_compute_frame_of_section(index)[source]#

Computes the local reference frame associated with a particular section. (Note that sections and cross sections are different! cross-sections, or xsecs, are the vertices, and sections are the parts in between. In other words, a wing with N cross-sections (xsecs) will always have N-1 sections.

Parameters:
  • index (int) – Which section should we get the frame of? If given i, this retrieves the frame of the section

  • i+1. (between xsecs i and) –

Returns:

A tuple of (xg_local, yg_local, zg_local), where each entry refers to the respective (normalized) axis of the local reference frame of the section. Given in geometry axes.

Return type:

Tuple[aerosandbox.numpy.ndarray, aerosandbox.numpy.ndarray, aerosandbox.numpy.ndarray]

class aerosandbox.WingXSec(xyz_le=None, chord=1.0, twist=0.0, airfoil=None, control_surfaces=None, analysis_specific_options=None, **deprecated_kwargs)[source]#

Bases: aerosandbox.common.AeroSandboxObject

Definition for a wing cross-section (“X-section”).

Parameters:
  • xyz_le (Union[aerosandbox.numpy.ndarray, List]) –

  • chord (float) –

  • twist (float) –

  • airfoil (aerosandbox.geometry.airfoil.Airfoil) –

  • control_surfaces (Optional[List[ControlSurface]]) –

  • analysis_specific_options (Optional[Dict[type, Dict[str, Any]]]) –

__repr__()[source]#

Return repr(self).

Return type:

str

translate(xyz)[source]#

Returns a copy of this WingXSec that has been translated by xyz.

Parameters:

xyz (Union[aerosandbox.numpy.ndarray, List]) – The amount to translate the WingXSec. Given as a 3-element NumPy vector.

Return type:

WingXSec

Returns: A new WingXSec object.

xsec_area()[source]#

Computes the WingXSec’s cross-sectional (xsec) area.

Returns: The (dimensional) cross-sectional area of the WingXSec.

class aerosandbox.ControlSurface(name='Untitled', symmetric=True, deflection=0.0, hinge_point=0.75, trailing_edge=True, analysis_specific_options=None)[source]#

Bases: aerosandbox.common.AeroSandboxObject

Definition for a control surface, which is attached to a particular WingXSec via WingXSec’s control_surfaces=[] parameter.

Parameters:
  • name (str) –

  • symmetric (bool) –

  • deflection (float) –

  • hinge_point (float) –

  • trailing_edge (bool) –

  • analysis_specific_options (Optional[Dict[type, Dict[str, Any]]]) –

__repr__()[source]#

Return repr(self).

Return type:

str

class aerosandbox.Fuselage(name='Untitled', xsecs=None, color=None, analysis_specific_options=None, **kwargs)[source]#

Bases: aerosandbox.AeroSandboxObject

Definition for a Fuselage or other slender body (pod, fuel tank, etc.).

Anatomy of a Fuselage:

A fuselage consists chiefly of a collection of cross-sections, or “xsecs”. A cross-section is a 2D “slice” of a fuselage. These can be accessed with Fuselage.xsecs, which gives a list of xsecs in the Fuselage. Each xsec is a FuselageXSec object, a class that is defined separately.

You may also see references to fuselage “sections”, which are different from cross-sections (xsecs)! Sections are the portions of the fuselage that are in between xsecs. In other words, a fuselage with N cross-sections (xsecs, FuselageXSec objects) will always have N-1 sections. Sections are never explicitly defined, since you can get all needed information by lofting from the adjacent cross-sections. For example, section 0 (the first one) is a loft between cross-sections 0 and 1.

Fuselages are lofted linearly between cross-sections.

Parameters:
  • name (Optional[str]) –

  • xsecs (List[FuselageXSec]) –

  • color (Optional[Union[str, Tuple[float]]]) –

  • analysis_specific_options (Optional[Dict[type, Dict[str, Any]]]) –

__repr__()[source]#

Return repr(self).

Return type:

str

abstract add_loft(kind, to_xsec, from_xsec=None, n_points=5, spacing=np.cosspace)[source]#
Parameters:
  • kind (str) –

  • to_xsec (FuselageXSec) –

  • from_xsec (FuselageXSec) –

  • n_points (int) –

  • spacing (Callable[[float, float, int], aerosandbox.geometry.common.np.ndarray]) –

Return type:

Fuselage

translate(xyz)[source]#

Translates the entire Fuselage by a certain amount.

Parameters:

xyz (Union[aerosandbox.geometry.common.np.ndarray, List[float]]) –

Return type:

Fuselage

Returns: self

area_wetted()[source]#

Returns the wetted area of the fuselage.

Returns:

Return type:

float

area_projected(type='XY')[source]#

Returns the area of the fuselage as projected onto one of the principal planes.

Parameters:

type (str) –

A string, which determines which principal plane to use for projection. One of:

  • ”XY”, in which case the projected area is onto the XY plane (i.e., top-down)

  • ”XZ”, in which case the projected area is onto the XZ plane (i.e., side-view)

Return type:

float

Returns: The projected area.

area_base()[source]#

Returns the area of the base (i.e. “trailing edge”) of the fuselage. Useful for certain types of drag calculation.

Returns:

Return type:

float

fineness_ratio(assumed_shape='cylinder')[source]#

Approximates the fineness ratio using the volume and length. The fineness ratio of a fuselage is defined as:

FR = length / max_diameter

Parameters:

assumed_shape

A string, which determines the assumed shape of the fuselage for the approximation. One of:

  • ”cylinder”, in which case the fuselage is assumed to have a cylindrical shape.

  • ”sears-haack”, in which case the fuselage is assumed to have Sears-Haack fuselage shape.

Return type:

float

Returns: An approximate value of the fuselage’s fineness ratio.

length()[source]#

Returns the total front-to-back length of the fuselage. Measured as the difference between the x-coordinates of the leading and trailing cross-sections. :return:

Return type:

float

volume(_sectional=False)[source]#

Computes the volume of the Fuselage.

Parameters:
  • _sectional (bool) – A boolean. If False, returns the total volume. If True, returns a list of volumes for each of

  • sections (the n-1 lofted) –

Returns:

The computed volume.

Return type:

Union[float, List[float]]

x_centroid_projected(type='XY')[source]#

Returns the x_g coordinate of the centroid of the planform area.

Parameters:

type (str) –

A string, which determines which principal plane to use for projection. One of:

  • ”XY”, in which case the projected area is onto the XY plane (i.e., top-down)

  • ”XZ”, in which case the projected area is onto the XZ plane (i.e., side-view)

Return type:

float

Returns: The x_g coordinate of the centroid.

mesh_body(method='quad', tangential_resolution=36)[source]#

Meshes the fuselage as a solid (thickened) body.

Uses the (points, faces) standard mesh format. For reference on this format, see the documentation in aerosandbox.geometry.mesh_utilities.

Parameters:
  • method

    A string, which determines whether to mesh the fuselage as a series of quadrilaterals or triangles.

    • ”quad” meshes the fuselage as a series of quadrilaterals.

    • ”tri” meshes the fuselage as a series of triangles.

  • tangential_resolution (int) – An integer, which determines the number of points to use to mesh each cross-section.

Return type:

Tuple[aerosandbox.geometry.common.np.ndarray, aerosandbox.geometry.common.np.ndarray]

Returns: Standard unstructured mesh format: A tuple of`points` and faces, where:

  • points is a n x 3 array of points, where n is the number of points in the mesh.

  • faces is a m x 3 array of faces if method is “tri”, or a m x 4 array of faces if method is “quad”.

    • Each row of faces is a list of indices into points, which specifies a face.

mesh_line(y_nondim=0.0, z_nondim=0.0)[source]#

Returns points along a line that goes through each of the FuselageXSec objects in this Fuselage.

Parameters:
  • y_nondim (Union[float, List[float]]) – The nondimensional (width-normalized) y-coordinate that the line should go through. Can either

  • cross-sections (be a single value used at all) –

  • the (or can be an iterable of values to be used at) –

  • cross-sections. (respective) –

  • z_nondim (Union[float, List[float]]) – The nondimensional (height-normalized) z-coordinate that the line should go through. Can either

  • cross-sections

  • the

  • cross-sections.

Return type:

List[aerosandbox.geometry.common.np.ndarray]

Returns: A list of points, where each point is a 3-element array of the form [x, y, z]. Goes from the nose to the tail.

draw(*args, **kwargs)[source]#

An alias to the more general Airplane.draw() method. See there for documentation.

Parameters:
  • *args – Arguments to pass through to Airplane.draw()

  • **kwargs – Keyword arguments to pass through to Airplane.draw()

Returns: Same return as Airplane.draw()

draw_wireframe(*args, **kwargs)[source]#

An alias to the more general Airplane.draw_wireframe() method. See there for documentation.

Parameters:
  • *args – Arguments to pass through to Airplane.draw_wireframe()

  • **kwargs – Keyword arguments to pass through to Airplane.draw_wireframe()

Returns: Same return as Airplane.draw_wireframe()

draw_three_view(*args, **kwargs)[source]#

An alias to the more general Airplane.draw_three_view() method. See there for documentation.

Parameters:
  • *args – Arguments to pass through to Airplane.draw_three_view()

  • **kwargs – Keyword arguments to pass through to Airplane.draw_three_view()

Returns: Same return as Airplane.draw_three_view()

subdivide_sections(ratio, spacing_function=np.linspace)[source]#

Generates a new Fuselage that subdivides the existing sections of this Fuselage into several smaller ones. Splits each section into N=`ratio` smaller subsections by inserting new cross-sections (xsecs) as needed.

This can allow for finer aerodynamic resolution of sectional properties in certain analyses.

Parameters:
  • ratio (int) – The number of new sections to split each old section into.

  • spacing_function (Callable[[float, float, float], aerosandbox.geometry.common.np.ndarray]) –

    A function that takes in three arguments: the start, end, and number of points to generate.

    The default is np.linspace, which generates a linearly-spaced array of points.

    Other options include np.cosspace, which generates a cosine-spaced array of points.

Return type:

Fuselage

Returns: A new Fuselage object with subdivided sections.

_compute_frame_of_FuselageXSec(index)[source]#

Computes the local frame of a FuselageXSec, given the index of the FuselageXSec in the Fuselage.xsecs list.

Parameters:

index (int) – The index of the FuselageXSec in the Fuselage.xsecs list.

Return type:

Tuple[aerosandbox.geometry.common.np.ndarray, aerosandbox.geometry.common.np.ndarray, aerosandbox.geometry.common.np.ndarray]

Returns: A tuple:

xg_local: The x-axis of the local coordinate frame, in aircraft geometry axes. yg_local: The y-axis of the local coordinate frame, in aircraft geometry axes. zg_local: The z-axis of the local coordinate frame, in aircraft geometry axes.

class aerosandbox.FuselageXSec(xyz_c=None, xyz_normal=None, radius=None, width=None, height=None, shape=2.0, analysis_specific_options=None)[source]#

Bases: aerosandbox.AeroSandboxObject

Definition for a fuselage cross-section (“X-section”).

Parameters:
  • xyz_c (Union[aerosandbox.geometry.common.np.ndarray, List[float]]) –

  • xyz_normal (Union[aerosandbox.geometry.common.np.ndarray, List[float]]) –

  • radius (float) –

  • width (float) –

  • height (float) –

  • shape (float) –

  • analysis_specific_options (Optional[Dict[type, Dict[str, Any]]]) –

__repr__()[source]#

Return repr(self).

Return type:

str

xsec_area()[source]#

Computes the FuselageXSec’s cross-sectional (xsec) area.

The computation method is a closed-form approximation for the area of a superellipse. The exact equation for the area of a superellipse with shape parameter s is:

area = width * height * (gamma(1 + 1/n))^2 / gamma(1 + 2/n)

where gamma() is the gamma function. The gamma function is (relatively) computationally expensive to evaluate and differentiate, so we replace this area calculation with a closed-form approximation (with essentially no loss in accuracy):

area = width * height / (s^-1.8717618013591173 + 1)

This approximation has the following properties:

  • It is numerically exact for the case of s = 1 (a diamond)

  • It is numerically exact for the case of s = 2 (a circle)

  • It is correct in the asymptotic limit where s -> infinity (a square)

  • In the range of sensible s values (1 < s < infinity), its error is less than 0.6%.

  • It always produces a positive area for any physically-meaningful value of s (s > 0). In the range of s

values where s is physically-meaningful but not in a sensible range (0 < s < 1), this equation will over-predict area.

The value of the constant seen in this expression (1.872…) is given by log(4/pi - 1) / log(2), and it is chosen as such so that the expression is exactly correct in the s=2 (circle) case.

Returns:

xsec_perimeter()[source]#

Computes the FuselageXSec’s perimeter. (“Circumference” in the case of a circular cross-section.)

The computation method is a closed-form approximation for the perimeter of a superellipse. The exact equation for the perimeter of a superellipse is quite long and is not repeated here for brevity; a Google search will bring it up. More importantly, this exact equation can only be represented as an infinite sum - not particularly useful for fast computation.

We replace this exact equation with the following closed-form approximation obtained from symbolic regression:

Imagine a superellipse centered on the origin of a 2D plane. Now, imagine that the superellipse is stretched such that the first quadrant (e.g., x>0, y>0) goes from (1, 0) to (0, h). Assume it has shape parameter s (where, as a reminder, s=1 is a diamond, s=2 is a circle, s=Inf is a square).

Then, the perimeter of that single quadrant is:

h + (((((s-0.88487077) * h + 0.2588574 / h) ^ exp(s / -0.90069205)) + h) + 0.09919785) ^ (-1.4812293 / s)

See AeroSandbox/studies/SuperellipseProperties for details about how this was obtained.

We can extrapolate from here to the general case of a superellipse, as shown in the code below.

This approximation has the following properties:

  • For the s=1 case (diamond), the error is +0.2%.

  • For the s=2 case (circle), the error is -0.1%.

  • In the s -> infinity limit (square), the error is +0.1%.

Returns:

compute_frame()[source]#

Computes the local coordinate frame of the FuselageXSec, in aircraft geometry axes.

xg_local is aligned with the FuselageXSec’s normal vector.

zg_local is roughly aligned with the z-axis of the aircraft geometry axes, but projected onto the FuselageXSec’s plane.

yg_local is the cross product of zg_local and xg_local.

Returns: A tuple:

xg_local: The x-axis of the local coordinate frame, in aircraft geometry axes. yg_local: The y-axis of the local coordinate frame, in aircraft geometry axes. zg_local: The z-axis of the local coordinate frame, in aircraft geometry axes.

Return type:

Tuple[aerosandbox.geometry.common.np.ndarray, aerosandbox.geometry.common.np.ndarray, aerosandbox.geometry.common.np.ndarray]

get_3D_coordinates(theta=None)[source]#

Samples points from the perimeter of this FuselageXSec.

Parameters:
  • theta (Union[float, aerosandbox.geometry.common.np.ndarray]) – Coordinate in the tangential-ish direction to sample points at. Given in the 2D FuselageXSec

  • system (coordinate) –

    • y_2D points along the (global) y_g

    • z_2D points along the (global) z_g

    In other words, a value of:

    • theta=0 -> samples points from the right side of the FuselageXSec

    • theta=pi/2 -> samples points from the top of the FuselageXSec

    • theta=pi -> samples points from the left side of the FuselageXSec

    • theta=3pi/2 -> samples points from the bottom of the FuselageXSec

  • where

    • y_2D points along the (global) y_g

    • z_2D points along the (global) z_g

    In other words, a value of:

    • theta=0 -> samples points from the right side of the FuselageXSec

    • theta=pi/2 -> samples points from the top of the FuselageXSec

    • theta=pi -> samples points from the left side of the FuselageXSec

    • theta=3pi/2 -> samples points from the bottom of the FuselageXSec

Return type:

Tuple[Union[float, aerosandbox.geometry.common.np.ndarray]]

Returns: Points sampled from the perimeter of the FuselageXSec, as a [x, y, z] tuple.

If theta is a float, then each of x, y, and z will be floats.

If theta is an array, then x, y, and z will also be arrays of the same size.

equivalent_radius(preserve='area')[source]#

Computes an equivalent radius for non-circular cross-sections. This may be necessary when doing analysis that uses axisymmetric assumptions.

Can either hold area or perimeter fixed, depending on whether cross-sectional area or wetted area is more important.

Parameters:

preserve

One of:

  • ”area”: holds the cross-sectional area constant

  • ”perimeter”: holds the cross-sectional perimeter (i.e., the wetted area of the Fuselage) constant

Return type:

float

Returns: An equivalent radius value.

translate(xyz)[source]#

Returns a copy of this FuselageXSec that has been translated by xyz.

Parameters:

xyz (Union[aerosandbox.geometry.common.np.ndarray, List[float]]) – The amount to translate the FuselageXSec. Given as a 3-element NumPy vector.

Return type:

FuselageXSec

Returns: A copy of this FuselageXSec, translated by xyz.

class aerosandbox.Airplane(name=None, xyz_ref=None, wings=None, fuselages=None, propulsors=None, s_ref=None, c_ref=None, b_ref=None, analysis_specific_options=None)[source]#

Bases: aerosandbox.AeroSandboxObject

Definition for an airplane.

Anatomy of an Airplane:

An Airplane consists chiefly of a collection of wings and fuselages. These can be accessed with Airplane.wings and Airplane.fuselages, which gives a list of those respective components. Each wing is a Wing object, and each fuselage is a Fuselage object.

Parameters:
__repr__()[source]#

Return repr(self).

mesh_body(method='quad', thin_wings=False, stack_meshes=True)[source]#

Returns a surface mesh of the Airplane, in (points, faces) format. For reference on this format, see the documentation in aerosandbox.geometry.mesh_utilities.

Parameters:
  • method

  • thin_wings – Controls whether wings should be meshed as thin surfaces, rather than full 3D bodies.

  • stack_meshes

    Controls whether the meshes should be merged into a single mesh or not.

    • If True, returns a (points, faces) tuple in standard mesh format.

    • If False, returns a list of (points, faces) tuples in standard mesh format.

Returns:

draw(backend='pyvista', thin_wings=False, ax=None, use_preset_view_angle=None, set_background_pane_color=None, set_background_pane_alpha=None, set_lims=True, set_equal=True, set_axis_visibility=None, show=True, show_kwargs=None)[source]#

Produces an interactive 3D visualization of the airplane.

Parameters:
  • backend (str) –

    The visualization backend to use. Options are:

    • ”matplotlib” for a Matplotlib backend

    • ”pyvista” for a PyVista backend

    • ”plotly” for a Plot.ly backend

    • ”trimesh” for a trimesh backend

  • thin_wings (bool) – A boolean that determines whether to draw the full airplane (i.e. thickened, 3D bodies), or to use a

  • objects. (thin-surface representation for any Wing) –

  • show (bool) – A boolean that determines whether to display the object after plotting it. If False, the object is

  • True (returned but not displayed. If) –

  • returned. (the object is displayed and) –

  • use_preset_view_angle (str) –

  • set_background_pane_color (Union[str, Tuple[float, float, float]]) –

  • set_background_pane_alpha (float) –

  • set_lims (bool) –

  • set_equal (bool) –

  • set_axis_visibility (bool) –

  • show_kwargs (Dict) –

Returns: The plotted object, in its associated backend format. Also displays the object if show is True.

draw_wireframe(ax=None, color='k', thin_linewidth=0.2, thick_linewidth=0.5, fuselage_longeron_theta=None, use_preset_view_angle=None, set_background_pane_color=None, set_background_pane_alpha=None, set_lims=True, set_equal=True, set_axis_visibility=None, show=True)[source]#

Draws a wireframe of the airplane on a Matplotlib 3D axis.

Parameters:
  • ax – The axis to draw on. Must be a 3D axis. If None, creates a new axis.

  • color – The color of the wireframe.

  • thin_linewidth – The linewidth of the thin lines.

  • use_preset_view_angle (str) –

  • set_background_pane_color (Union[str, Tuple[float, float, float]]) –

  • set_background_pane_alpha (float) –

  • set_lims (bool) –

  • set_equal (bool) –

  • set_axis_visibility (bool) –

  • show (bool) –

draw_three_view(style='shaded', show=True)[source]#

Draws a standard 4-panel three-view diagram of the airplane using Matplotlib backend. Creates a new figure.

Parameters:
  • style (str) –

    Determines what drawing style to use for the three-view. A string, one of:

    • ”shaded”

    • ”wireframe”

  • show (bool) – A boolean of whether to show the figure after creating it, or to hold it so that the user can modify the figure further before showing.

Returns:

is_entirely_symmetric()[source]#

Returns a boolean describing whether the airplane is geometrically entirely symmetric across the XZ-plane. :return: [boolean]

aerodynamic_center(chord_fraction=0.25)[source]#

Computes the approximate location of the aerodynamic center of the wing. Uses the generalized methodology described here:

Parameters:
  • chord_fraction (float) – The position of the aerodynamic center along the MAC, as a fraction of MAC length.

  • Typically (denoted h_0 in the literature) –

  • value (this) –

  • Cook (wing-fuselage interactions can cause a forward shift to a value more like 0.1 or less. Citing) –

:param : :param Michael V.: :param “Flight Dynamics Principles”: :param 3rd Ed.: :param Sect. 3.5.3 “Controls-fixed static stability”. PDF: :param https: //www.sciencedirect.com/science/article/pii/B9780080982427000031

Returns: The (x, y, z) coordinates of the aerodynamic center of the airplane.

with_control_deflections(control_surface_deflection_mappings)[source]#

Returns a copy of the airplane with the specified control surface deflections applied.

Parameters:

control_surface_deflection_mappings (Dict[str, float]) –

A dictionary mapping control surface names to deflections.

  • Keys: Control surface names.

  • Values: Deflections, in degrees. Downwards-positive, following typical convention.

Return type:

Airplane

Returns: A copy of the airplane with the specified control surface deflections applied.

generate_cadquery_geometry(minimum_airfoil_TE_thickness=0.001, fuselage_tol=0.0001)[source]#

Uses the CADQuery library (OpenCASCADE backend) to generate a 3D CAD model of the airplane.

Parameters:
  • minimum_airfoil_TE_thickness (float) – The minimum thickness of the trailing edge of the airfoils, as a fraction

  • if (of each airfoil's chord. This will be enforced by thickening the trailing edge of the airfoils) –

  • extremely (necessary. This is useful for avoiding numerical issues in CAD software that can arise from) –

  • thin (i.e., <1e-6 meters) –

  • tol – The geometric tolerance (meters) to use when generating the CAD geometry. This is passed directly to the CADQuery

  • fuselage_tol (float) –

Return type:

Workplane

Returns: A CADQuery Workplane object containing the CAD geometry of the airplane.

export_cadquery_geometry(filename, minimum_airfoil_TE_thickness=0.001)[source]#

Exports the airplane geometry to a STEP file.

Parameters:
  • filename (Union[pathlib.Path, str]) – The filename to export to. Should include the “.step” extension.

  • minimum_airfoil_TE_thickness (float) – The minimum thickness of the trailing edge of the airfoils, as a fraction

  • if (of each airfoil's chord. This will be enforced by thickening the trailing edge of the airfoils) –

  • extremely (necessary. This is useful for avoiding numerical issues in CAD software that can arise from) –

  • thin (i.e., <1e-6 meters) –

Return type:

None

Returns: None, but exports the airplane geometry to a STEP file.

export_AVL(filename, include_fuselages=True)[source]#
Parameters:

include_fuselages (bool) –

export_XFLR(*args, **kwargs)[source]#
Return type:

str

export_XFLR5_xml(filename, mass_props=None, include_fuselages=False, mainwing=None, elevator=None, fin=None)[source]#

Exports the airplane geometry to an XFLR5 .xml file. To import the .xml file into XFLR5, go to File -> Import -> Import from XML.

Parameters:
  • filename (Union[pathlib.Path, str]) – The filename to export to. Should include the “.xml” extension.

  • mass_props (aerosandbox.weights.mass_properties.MassProperties) –

    The MassProperties object to use when exporting the airplane. If not specified, will default to a 1 kg point mass at the origin.

    • Note: XFLR5 does not natively support user-defined inertia tensors, so we have to synthesize an equivalent

    set of point masses to represent the inertia tensor.

  • include_fuselages (bool) – Whether to include fuselages in the export.

  • mainwing (aerosandbox.geometry.wing.Wing) – The main wing of the airplane. If not specified, will default to the first wing in the airplane.

  • elevator (aerosandbox.geometry.wing.Wing) – The elevator of the airplane. If not specified, will default to the second wing in the airplane.

  • fin (aerosandbox.geometry.wing.Wing) – The fin of the airplane. If not specified, will default to the third wing in the airplane.

Return type:

str

Returns: None, but exports the airplane geometry to an XFLR5 .xml file.

To import the .xml file into XFLR5, go to File -> Import -> Import from XML.

export_OpenVSP_vspscript(filename)[source]#

Exports the airplane geometry to a *.vspscript file compatible with OpenVSP. To import the .vspscript file into OpenVSP:

Open OpenVSP, then File -> Run Script -> Select the .vspscript file.

Parameters:

filename (Union[pathlib.Path, str]) – The filename to export to, given as a string or Path. Should include the “.vspscript” extension.

Return type:

str

Returns: A string of the file contents, and also saves the file to the specified filename

class aerosandbox.Propulsor(name='Untitled', xyz_c=None, xyz_normal=None, radius=1.0, length=0.0, color=None, analysis_specific_options=None)[source]#

Bases: aerosandbox.AeroSandboxObject

Definition for a Propulsor, which could be a propeller, a rotor, or a jet engine.

Assumes a disk- or cylinder-shaped propulsor.

Parameters:
  • name (Optional[str]) –

  • xyz_c (Union[aerosandbox.geometry.common.np.ndarray, List[float]]) –

  • xyz_normal (Union[aerosandbox.geometry.common.np.ndarray, List[float]]) –

  • radius (float) –

  • length (float) –

  • color (Optional[Union[str, Tuple[float]]]) –

  • analysis_specific_options (Optional[Dict[type, Dict[str, Any]]]) –

__repr__()[source]#

Return repr(self).

Return type:

str

xsec_area()[source]#

Returns the cross-sectional area of the propulsor, in m^2.

Return type:

float

xsec_perimeter()[source]#

Returns the cross-sectional perimeter of the propulsor, in m.

Return type:

float

volume()[source]#

Returns the volume of the propulsor, in m^3.

Return type:

float

compute_frame()[source]#

Computes the local coordinate frame of the propulsor, in aircraft geometry axes.

xg_local is aligned with the propulsor’s normal vector.

zg_local is roughly aligned with the z-axis of the aircraft geometry axes, but projected onto the propulsor’s plane.

yg_local is the cross product of zg_local and xg_local.

Returns: A tuple:

xg_local: The x-axis of the local coordinate frame, in aircraft geometry axes. yg_local: The y-axis of the local coordinate frame, in aircraft geometry axes. zg_local: The z-axis of the local coordinate frame, in aircraft geometry axes.

Return type:

Tuple[aerosandbox.geometry.common.np.ndarray, aerosandbox.geometry.common.np.ndarray, aerosandbox.geometry.common.np.ndarray]

get_disk_3D_coordinates(theta=None, l_over_length=None)[source]#
Parameters:
  • theta (Union[float, aerosandbox.geometry.common.np.ndarray]) –

  • l_over_length (Union[float, aerosandbox.geometry.common.np.ndarray]) –

Return type:

Tuple[Union[float, aerosandbox.geometry.common.np.ndarray]]

translate(xyz)[source]#

Returns a copy of this propulsor that has been translated by xyz.

Parameters:

xyz (Union[aerosandbox.geometry.common.np.ndarray, List[float]]) – The amount to translate the propulsor, in meters. Given in aircraft geometry axes, as with everything else.

Return type:

Propulsor

Returns: A copy of this propulsor, translated by xyz.

aerosandbox.is_casadi_type(object, recursive=True)[source]#

Returns a boolean of whether an object is a CasADi data type or not. If the recursive flag is True, iterates recursively, returning True if any subelement (at any depth) is a CasADi type.

Parameters:
  • object (Any) – The object to evaluate.

  • recursive (bool) – If the object is a list or tuple, recursively iterate through every subelement. If any of the

  • subelements (at any depth) –

Return type:

bool

Returns: A boolean if the object is (or contains, if recursive=True) a CasADi data type.

aerosandbox.reflect_over_XZ_plane(input_vector)[source]#

Takes in a vector or an array and flips the y-coordinates. :param input_vector: A vector or list of vectors to flip. :return: Vector with flipped sign on y-coordinate.

class aerosandbox.Atmosphere(altitude=0.0, method='differentiable', temperature_deviation=0.0)[source]#

Bases: aerosandbox.common.AeroSandboxObject

All models here are smoothed fits to the 1976 COESA model; see AeroSandboxstudiesAtmosphere Fitting for details.

Parameters:
  • altitude (float) –

  • method (str) –

  • temperature_deviation (float) –

__repr__()[source]#

Return repr(self).

Return type:

str

__getitem__(index)[source]#

Indexes one item from each attribute of an Atmosphere instance. Returns a new Atmosphere instance.

Parameters:

index – The index that is being called; e.g.,: >>> first_atmosphere = atmosphere[0]

Return type:

Atmosphere

Returns: A new Atmosphere instance, where each attribute is subscripted at the given value, if possible.

__len__()[source]#
__array__(dtype='O')[source]#

Allows NumPy array creation without infinite recursion in __len__ and __getitem__.

pressure()[source]#

Returns the pressure, in Pascals.

temperature()[source]#

Returns the temperature, in Kelvin.

density()[source]#

Returns the density, in kg/m^3.

density_altitude(method='approximate')[source]#

Returns the density altitude, in meters.

See https://en.wikipedia.org/wiki/Density_altitude

Parameters:

method (str) –

speed_of_sound()[source]#

Returns the speed of sound, in m/s.

dynamic_viscosity()[source]#

Returns the dynamic viscosity (mu), in kg/(m*s).

Based on Sutherland’s Law, citing https://www.cfd-online.com/Wiki/Sutherland’s_law.

According to Rathakrishnan, E. (2013). Theoretical aerodynamics. John Wiley & Sons.: This relationship is valid from 0.01 to 100 atm, and between 0 and 3000K.

According to White, F. M., & Corfield, I. (2006). Viscous fluid flow (Vol. 3, pp. 433-434). New York: McGraw-Hill.: The error is no more than approximately 2% for air between 170K and 1900K.

kinematic_viscosity()[source]#

Returns the kinematic viscosity (nu), in m^2/s.

Definitional.

ratio_of_specific_heats()[source]#
mean_free_path()[source]#

Returns the mean free path of an air molecule, in meters.

To find the collision radius, assumes “a hard-sphere gas that has the same viscosity as the actual gas being considered”.

From Vincenti, W. G. and Kruger, C. H. (1965). Introduction to physical gas dynamics. Krieger Publishing Company. p. 414.

knudsen(length)[source]#

Computes the Knudsen number for a given length.

aerosandbox.mass_properties_from_radius_of_gyration(mass, x_cg=0, y_cg=0, z_cg=0, radius_of_gyration_x=0, radius_of_gyration_y=0, radius_of_gyration_z=0)[source]#

Returns the mass properties of an object, given its radius of gyration.

It’s assumed that the principle axes of the inertia tensor are aligned with the coordinate axes.

This is a shorthand convenience function for common usage of the MassProperties constructor. For more detailed use, use the MassProperties object directly.

Parameters:
  • mass (float) – Mass [kg]

  • x_cg (float) – x-position of the center of gravity

  • y_cg (float) – y-position of the center of gravity

  • z_cg (float) – z-position of the center of gravity

  • radius_of_gyration_x (float) – Radius of gyration along the x-axis, about the center of gravity [m]

  • radius_of_gyration_y (float) – Radius of gyration along the y-axis, about the center of gravity [m]

  • radius_of_gyration_z (float) – Radius of gyration along the z-axis, about the center of gravity [m]

Return type:

aerosandbox.weights.mass_properties.MassProperties

Returns: MassProperties object.

class aerosandbox.AeroSandboxObject[source]#

Bases: abc.ABC

Helper class that provides a standard way to create an ABC using inheritance.

_asb_metadata: Dict[str, str]#
__eq__(other)[source]#

Checks if two AeroSandbox objects are value-equivalent. A more sensible default for classes that represent physical objects than checking for memory equivalence.

This is done by checking if the two objects are of the same type and have the same __dict__.

Parameters:

other – Another object.

Returns:

True if the objects are equal, False otherwise.

Return type:

bool

save(filename=None, verbose=True, automatically_add_extension=True)[source]#

Saves the object to a binary file, using the dill library.

Creates a .asb file, which is a binary file that can be loaded with aerosandbox.load(). This can be loaded

into memory in a different Python session or a different computer, and it will be exactly the same as when it was saved.

Parameters:
  • filename (Union[str, pathlib.Path]) – The filename to save this object to. Should be a .asb file.

  • verbose (bool) – If True, prints messages to console on successful save.

  • automatically_add_extension (bool) – If True, automatically adds the .asb extension to the filename if it doesn’t already have it. If False, does not add the extension.

Return type:

None

Returns: None (writes to file)

copy()[source]#

Returns a shallow copy of the object.

deepcopy()[source]#

Returns a deep copy of the object.

substitute_solution(sol, inplace=None)[source]#

Substitutes a solution from CasADi’s solver recursively as an in-place operation.

In-place operation. To make it not in-place, do y = copy.deepcopy(x) or similar first. :param sol: OptiSol object. :return:

Parameters:
  • sol (casadi.OptiSol) –

  • inplace (bool) –

aerosandbox.trim_string(string, length=80)[source]#

Trims a string to be less than a given length. If the string would exceed the length, makes it end in ellipses (”…”).

Parameters:
  • string (str) – The string to be trimmed.

  • length (int) – The length to trim the string to, including any ellipses that may be added.

Return type:

str

Returns: The trimmed string, including ellipses if needed.

class aerosandbox.MassProperties(mass=None, x_cg=0.0, y_cg=0.0, z_cg=0.0, Ixx=0.0, Iyy=0.0, Izz=0.0, Ixy=0.0, Iyz=0.0, Ixz=0.0)[source]#

Bases: aerosandbox.common.AeroSandboxObject

Mass properties of a rigid 3D object.

## Notes on Inertia Tensor Definition

This class uses the standard mathematical definition of the inertia tensor, which is different from the alternative definition used by some CAD and CAE applications (such as SolidWorks, NX, etc.). These differ by a sign flip in the products of inertia.

Specifically, we define the inertia tensor using the standard convention:

[ I11 I12 I13 ] [ Ixx Ixy Ixz ] [sum(m*(y^2+z^2)) -sum(m*x*y) -sum(m*x*z) ]

I = [ I21 I22 I23 ] = [ Ixy Iyy Iyz ] = [-sum(m*x*y) sum(m*(x^2+z^2)) -sum(m*y*z) ]

[ I31 I32 I33 ] [ Ixz Iyz Izz ] [-sum(m*x*z) -sum(m*y*z) sum(m*(x^2+y^2))]

Whereas SolidWorks, NX, etc. define the inertia tensor as:

[ I11 I12 I13 ] [ Ixx -Ixy -Ixz ] [sum(m*(y^2+z^2)) -sum(m*x*y) -sum(m*x*z) ]

I = [ I21 I22 I23 ] = [-Ixy Iyy -Iyz ] = [-sum(m*x*y) sum(m*(x^2+z^2)) -sum(m*y*z) ]

[ I31 I32 I33 ] [-Ixz -Iyz Izz ] [-sum(m*x*z) -sum(m*y*z) sum(m*(x^2+y^2))]

See also: https://en.wikipedia.org/wiki/Moment_of_inertia#Inertia_tensor

Parameters:
  • mass (Union[float, aerosandbox.numpy.ndarray]) –

  • x_cg (Union[float, aerosandbox.numpy.ndarray]) –

  • y_cg (Union[float, aerosandbox.numpy.ndarray]) –

  • z_cg (Union[float, aerosandbox.numpy.ndarray]) –

  • Ixx (Union[float, aerosandbox.numpy.ndarray]) –

  • Iyy (Union[float, aerosandbox.numpy.ndarray]) –

  • Izz (Union[float, aerosandbox.numpy.ndarray]) –

  • Ixy (Union[float, aerosandbox.numpy.ndarray]) –

  • Iyz (Union[float, aerosandbox.numpy.ndarray]) –

  • Ixz (Union[float, aerosandbox.numpy.ndarray]) –

property xyz_cg#
property inertia_tensor#
__repr__()[source]#

Return repr(self).

Return type:

str

__getitem__(index)[source]#

Indexes one item from each attribute of an MassProperties instance. Returns a new MassProperties instance.

Parameters:

index – The index that is being called; e.g.,: >>> first_mass_props = mass_props[0]

Return type:

MassProperties

Returns: A new MassProperties instance, where each attribute is subscripted at the given value, if possible.

__len__()[source]#
__array__(dtype='O')[source]#

Allows NumPy array creation without infinite recursion in __len__ and __getitem__.

__neg__()[source]#
Return type:

MassProperties

__add__(other)[source]#

Combines one MassProperties object with another.

Parameters:

other (MassProperties) –

Return type:

MassProperties

__radd__(other)[source]#

Allows sum() to work with MassProperties objects.

Basically, makes addition commutative.

Parameters:

other (MassProperties) –

Return type:

MassProperties

__sub__(other)[source]#

Subtracts one MassProperties object from another. (opposite of __add__() )

Parameters:

other (MassProperties) –

Return type:

MassProperties

__mul__(other)[source]#

Returns a new MassProperties object that is equivalent to if you had summed together N (with other interpreted as N) identical MassProperties objects.

Parameters:

other (float) –

Return type:

MassProperties

__rmul__(other)[source]#

Allows multiplication of a scalar by a MassProperties object. Makes multiplication commutative.

Parameters:

other (float) –

Return type:

MassProperties

__truediv__(other)[source]#

Returns a new MassProperties object that is equivalent to if you had divided the mass of the current MassProperties object by a factor.

Parameters:

other (float) –

Return type:

MassProperties

allclose(other, rtol=1e-05, atol=1e-08, equal_nan=False)[source]#
Parameters:

other (MassProperties) –

Return type:

bool

inv_inertia_tensor()[source]#

Computes the inverse of the inertia tensor, in a slightly more efficient way than raw inversion by exploiting its known structure.

If you are effectively using this inertia tensor to solve a linear system, you should use a linear algebra solve() method (ideally via Cholesky decomposition) instead, for best speed.

get_inertia_tensor_about_point(x=0.0, y=0.0, z=0.0, return_tensor=True)[source]#

Returns the inertia tensor about an arbitrary point. Using https://en.wikipedia.org/wiki/Parallel_axis_theorem#Tensor_generalization

Parameters:
  • x (float) – x-position of the new point, in the same axes as this MassProperties instance is specified in.

  • y (float) – y-position of the new point, in the same axes as this MassProperties instance is specified in.

  • z (float) – z-position of the new point, in the same axes as this MassProperties instance is specified in.

  • return_tensor (bool) – A switch for the desired return type; see below for details. [boolean]

Returns:

Returns the new inertia tensor, as a 2D numpy ndarray. If return_tensor is False:

Returns the components of the new inertia tensor, as a tuple. If J is the new inertia tensor, the tuple returned is: (Jxx, Jyy, Jzz, Jxy, Jyz, Jxz)

Return type:

If return_tensor is True

is_physically_possible()[source]#

Checks whether it’s possible for this MassProperties object to correspond to the mass properties of a real physical object.

Assumes that all physically-possible objects have a positive mass (or density).

Some special edge cases:

  • A MassProperties object with mass of 0 (i.e., null object) will return True. Note: this will return

True even if the inertia tensor is not zero (which would basically be infinitesimal point masses at infinite distance).

  • A MassProperties object that is a point mass (i.e., inertia tensor is all zeros) will return True.

Returns:

True if the MassProperties object is physically possible, False otherwise.

Return type:

bool

is_point_mass()[source]#

Returns True if this MassProperties object corresponds to a point mass, False otherwise.

Return type:

bool

generate_possible_set_of_point_masses(method='optimization', check_if_already_a_point_mass=True)[source]#

Generates a set of point masses (represented as MassProperties objects with zero inertia tensors), that, when combined, would yield this MassProperties object.

Note that there are an infinite number of possible sets of point masses that could yield this MassProperties object. This method returns one possible set of point masses, but there are many others.

Example

>>> mp = MassProperties(mass=1, Ixx=1, Iyy=1, Izz=1, Ixy=0.1, Iyz=-0.1, Ixz=0.1)
>>> point_masses = mp.generate_possible_set_of_point_masses()
>>> mp.allclose(sum(point_masses))  # Asserts these are equal, within tolerance
True
Parameters:
  • method – The method to use to generate the set of point masses. Currently, only “optimization” is supported.

  • check_if_already_a_point_mass (bool) –

Returns:

A list of MassProperties objects, each of which is a point mass (i.e., zero inertia tensor).

Return type:

List[MassProperties]

export_AVL_mass_file(filename)[source]#

Exports this MassProperties object to an AVL mass file.

Note: AVL uses the SolidWorks convention for inertia tensors, which is different from the typical mathematical convention, and the convention used by this MassProperties class. In short, these differ by a sign flip in the products of inertia. More details available in the MassProperties docstring. See also: https://en.wikipedia.org/wiki/Moment_of_inertia#Inertia_tensor

Parameters:

filename – The filename to export to.

Return type:

None

Returns: None

aerosandbox.mp1[source]#
class aerosandbox.OperatingPoint(atmosphere=Atmosphere(altitude=0), velocity=1.0, alpha=0.0, beta=0.0, p=0.0, q=0.0, r=0.0)[source]#

Bases: aerosandbox.common.AeroSandboxObject

Helper class that provides a standard way to create an ABC using inheritance.

Parameters:
  • atmosphere (aerosandbox.Atmosphere) –

  • velocity (float) –

  • alpha (float) –

  • beta (float) –

  • p (float) –

  • q (float) –

  • r (float) –

property state: Dict[str, float | aerosandbox.numpy.ndarray]#

Returns the state variables of this OperatingPoint instance as a Dict.

Keys are strings that give the name of the variables. Values are the variables themselves.

Return type:

Dict[str, Union[float, aerosandbox.numpy.ndarray]]

get_new_instance_with_state(new_state=None)[source]#

Creates a new instance of the OperatingPoint class from the given state.

Parameters:

new_state (Union[Dict[str, Union[float, aerosandbox.numpy.ndarray]], List, Tuple, aerosandbox.numpy.ndarray]) – The new state to be used for the new instance. Ideally, this is represented as a Dict in identical format to the state of a OperatingPoint instance.

Returns: A new instance of this same OperatingPoint class.

_set_state(new_state=None)[source]#

Force-overwrites all state variables with a new set (either partial or complete) of state variables.

Warning: this is not the intended public usage of OperatingPoint instances. If you want a new state yourself, you should instantiate a new one either:

  1. manually, or

  2. by using OperatingPoint.get_new_instance_with_state()

Hence, this function is meant for PRIVATE use only - be careful how you use this!

Parameters:

new_state (Union[Dict[str, Union[float, aerosandbox.numpy.ndarray]], List, Tuple, aerosandbox.numpy.ndarray]) –

unpack_state(dict_like_state=None)[source]#

‘Unpacks’ a Dict-like state into an array-like that represents the state of the OperatingPoint.

Parameters:

dict_like_state (Dict[str, Union[float, aerosandbox.numpy.ndarray]]) – Takes in a dict-like representation of the state.

Return type:

Tuple[Union[float, aerosandbox.numpy.ndarray]]

Returns: The array representation of the state that you gave.

pack_state(array_like_state=None)[source]#

‘Packs’ an array into a Dict that represents the state of the OperatingPoint.

Parameters:

array_like_state (Union[List, Tuple, aerosandbox.numpy.ndarray]) – Takes in an iterable that must have the same number of entries as the state vector of the OperatingPoint.

Return type:

Dict[str, Union[float, aerosandbox.numpy.ndarray]]

Returns: The Dict representation of the state that you gave.

__repr__()[source]#

Return repr(self).

Return type:

str

__getitem__(index)[source]#

Indexes one item from each attribute of an OperatingPoint instance. Returns a new OperatingPoint instance.

Parameters:

index (Union[int, slice]) – The index that is being called; e.g.,: >>> first_op_point = op_point[0]

Returns: A new OperatingPoint instance, where each attribute is subscripted at the given value, if possible.

__len__()[source]#
__array__(dtype='O')[source]#

Allows NumPy array creation without infinite recursion in __len__ and __getitem__.

dynamic_pressure()[source]#

Dynamic pressure of the working fluid :returns: Dynamic pressure of the working fluid. [Pa] :rtype: float

total_pressure()[source]#

Total (stagnation) pressure of the working fluid.

Assumes a calorically perfect gas (i.e. specific heats do not change across the isentropic deceleration).

Note that total pressure != static pressure + dynamic pressure, due to compressibility effects.

Returns: Total pressure of the working fluid. [Pa]

total_temperature()[source]#

Total (stagnation) temperature of the working fluid.

Assumes a calorically perfect gas (i.e. specific heats do not change across the isentropic deceleration).

Returns: Total temperature of the working fluid [K]

reynolds(reference_length)[source]#

Computes a Reynolds number with respect to a given reference length. :param reference_length: A reference length you choose [m] :return: Reynolds number [unitless]

mach()[source]#

Returns the Mach number associated with the current flight condition.

indicated_airspeed()[source]#

Returns the indicated airspeed associated with the current flight condition, in meters per second.

equivalent_airspeed()[source]#

Returns the equivalent airspeed associated with the current flight condition, in meters per second.

energy_altitude()[source]#

Returns the energy altitude associated with the current flight condition, in meters.

The energy altitude is the altitude at which a stationary aircraft would have the same total energy (kinetic + gravitational potential) as the aircraft at the current flight condition.

convert_axes(x_from, y_from, z_from, from_axes, to_axes)[source]#

Converts a vector [x_from, y_from, z_from], as given in the from_axes frame, to an equivalent vector [x_to, y_to, z_to], as given in the to_axes frame.

Both from_axes and to_axes should be a string, one of:
  • “geometry”

  • “body”

  • “wind”

  • “stability”

This whole function is vectorized, both over the vector and the OperatingPoint (e.g., a vector of OperatingPoint.alpha values)

Wind axes rotations are taken from Eq. 6.7 in Sect. 6.2.2 of Drela’s Flight Vehicle Aerodynamics textbook, with axes corrections to go from [D, Y, L] to true wind axes (and same for geometry to body axes).

Parameters:
  • x_from (Union[float, aerosandbox.numpy.ndarray]) – x-component of the vector, in from_axes frame.

  • y_from (Union[float, aerosandbox.numpy.ndarray]) – y-component of the vector, in from_axes frame.

  • z_from (Union[float, aerosandbox.numpy.ndarray]) – z-component of the vector, in from_axes frame.

  • from_axes (str) – The axes to convert from.

  • to_axes (str) – The axes to convert to.

Return type:

Tuple[float, float, float]

Returns: The x-, y-, and z-components of the vector, in to_axes frame. Given as a tuple.

compute_rotation_matrix_wind_to_geometry()[source]#

Computes the 3x3 rotation matrix that transforms from wind axes to geometry axes.

Returns: a 3x3 rotation matrix.

Return type:

aerosandbox.numpy.ndarray

compute_freestream_direction_geometry_axes()[source]#
compute_freestream_velocity_geometry_axes()[source]#
compute_rotation_velocity_geometry_axes(points)[source]#
class aerosandbox.DynamicsPointMass1DHorizontal(mass_props=None, x_e=0, u_e=0)[source]#

Bases: aerosandbox.dynamics.point_mass.point_3D.cartesian.DynamicsPointMass3DCartesian

Dynamics instance: * simulating a point mass * in 1D, oriented horizontally (i.e., the .add_gravity() method will have no effect)

State variables:

x_e: x-position, in Earth axes. [meters] u_e: x-velocity, in Earth axes. [m/s]

Control variables:

Fx_e: Force along the Earth-x axis. [N]

Parameters:
property state: Dict[str, float | aerosandbox.numpy.ndarray]#

Returns the state variables of this Dynamics instance as a Dict.

Keys are strings that give the name of the variables. Values are the variables themselves.

This method should look something like:
>>> {
>>>     "x_e": self.x_e,
>>>     "u_e": self.u_e,
>>>     ...
>>> }
Return type:

Dict[str, Union[float, aerosandbox.numpy.ndarray]]

property control_variables: Dict[str, float | aerosandbox.numpy.ndarray]#
Return type:

Dict[str, Union[float, aerosandbox.numpy.ndarray]]

state_derivatives()[source]#

A function that returns the derivatives with respect to time of the state specified in the state property.

Should return a Dict with the same keys as the state property.

Return type:

Dict[str, Union[float, aerosandbox.numpy.ndarray]]

class aerosandbox.DynamicsPointMass1DVertical(mass_props=None, z_e=0, w_e=0)[source]#

Bases: aerosandbox.dynamics.point_mass.point_3D.cartesian.DynamicsPointMass3DCartesian

Dynamics instance: * simulating a point mass * in 1D, oriented vertically (i.e., the .add_gravity() method will have an effect)

State variables:

z_e: z-position, in Earth axes. [meters] w_e: z-velocity, in Earth axes. [m/s]

Control variables:

Fz_e: Force along the Earth-x axis. [N]

Parameters:
property state: Dict[str, float | aerosandbox.numpy.ndarray]#

Returns the state variables of this Dynamics instance as a Dict.

Keys are strings that give the name of the variables. Values are the variables themselves.

This method should look something like:
>>> {
>>>     "x_e": self.x_e,
>>>     "u_e": self.u_e,
>>>     ...
>>> }
Return type:

Dict[str, Union[float, aerosandbox.numpy.ndarray]]

property control_variables: Dict[str, float | aerosandbox.numpy.ndarray]#
Return type:

Dict[str, Union[float, aerosandbox.numpy.ndarray]]

state_derivatives()[source]#

A function that returns the derivatives with respect to time of the state specified in the state property.

Should return a Dict with the same keys as the state property.

Return type:

Dict[str, Union[float, aerosandbox.numpy.ndarray]]

class aerosandbox.DynamicsPointMass2DCartesian(mass_props=None, x_e=0, z_e=0, u_e=0, w_e=0, alpha=0)[source]#

Bases: aerosandbox.dynamics.point_mass.point_3D.cartesian.DynamicsPointMass3DCartesian

Dynamics instance: * simulating a point mass * in 2D * with velocity parameterized in Cartesian coordinates

State variables:

x_e: x-position, in Earth axes. [meters] z_e: z-position, in Earth axes. [meters] u_e: x-velocity, in Earth axes. [m/s] w_e: z-velocity, in Earth axes. [m/s]

Indirect control variables:

alpha: Angle of attack. [degrees]

Control variables:

Fx_e: Force along the Earth-x axis. [N] Fz_e: Force along the Earth-z axis. [N]

Parameters:
  • mass_props (aerosandbox.weights.mass_properties.MassProperties) –

  • x_e (Union[float, aerosandbox.numpy.ndarray]) –

  • z_e (Union[float, aerosandbox.numpy.ndarray]) –

  • u_e (Union[float, aerosandbox.numpy.ndarray]) –

  • w_e (Union[float, aerosandbox.numpy.ndarray]) –

  • alpha (Union[float, aerosandbox.numpy.ndarray]) –

property state: Dict[str, float | aerosandbox.numpy.ndarray]#

Returns the state variables of this Dynamics instance as a Dict.

Keys are strings that give the name of the variables. Values are the variables themselves.

This method should look something like:
>>> {
>>>     "x_e": self.x_e,
>>>     "u_e": self.u_e,
>>>     ...
>>> }
Return type:

Dict[str, Union[float, aerosandbox.numpy.ndarray]]

property control_variables: Dict[str, float | aerosandbox.numpy.ndarray]#
Return type:

Dict[str, Union[float, aerosandbox.numpy.ndarray]]

state_derivatives()[source]#

A function that returns the derivatives with respect to time of the state specified in the state property.

Should return a Dict with the same keys as the state property.

Return type:

Dict[str, Union[float, aerosandbox.numpy.ndarray]]

class aerosandbox.DynamicsPointMass2DSpeedGamma(mass_props=None, x_e=0, z_e=0, speed=0, gamma=0, alpha=0)[source]#

Bases: aerosandbox.dynamics.point_mass.point_3D.speed_gamma_track.DynamicsPointMass3DSpeedGammaTrack

Dynamics instance: * simulating a point mass * in 2D * with velocity parameterized in speed-gamma space.

State variables:

x_e: x-position, in Earth axes. [meters] z_e: z-position, in Earth axes. [meters] speed: Speed; equivalent to u_w, the x-velocity in wind axes. [m/s] gamma: Flight path angle. [rad]

Indirect control variables:

alpha: Angle of attack. [degrees]

Control variables:

Fx_w: Force along the wind-x axis. [N] Fz_w: Force along the wind-z axis. [N]

Parameters:
  • mass_props (aerosandbox.weights.mass_properties.MassProperties) –

  • x_e (Union[float, aerosandbox.numpy.ndarray]) –

  • z_e (Union[float, aerosandbox.numpy.ndarray]) –

  • speed (Union[float, aerosandbox.numpy.ndarray]) –

  • gamma (Union[float, aerosandbox.numpy.ndarray]) –

  • alpha (Union[float, aerosandbox.numpy.ndarray]) –

property state: Dict[str, float | aerosandbox.numpy.ndarray]#

Returns the state variables of this Dynamics instance as a Dict.

Keys are strings that give the name of the variables. Values are the variables themselves.

This method should look something like:
>>> {
>>>     "x_e": self.x_e,
>>>     "u_e": self.u_e,
>>>     ...
>>> }
Return type:

Dict[str, Union[float, aerosandbox.numpy.ndarray]]

property control_variables: Dict[str, float | aerosandbox.numpy.ndarray]#
Return type:

Dict[str, Union[float, aerosandbox.numpy.ndarray]]

state_derivatives()[source]#

A function that returns the derivatives with respect to time of the state specified in the state property.

Should return a Dict with the same keys as the state property.

Return type:

Dict[str, Union[float, aerosandbox.numpy.ndarray]]

class aerosandbox.DynamicsPointMass3DCartesian(mass_props=None, x_e=0, y_e=0, z_e=0, u_e=0, v_e=0, w_e=0, alpha=0, beta=0, bank=0)[source]#

Bases: aerosandbox.dynamics.point_mass.common_point_mass._DynamicsPointMassBaseClass

Dynamics instance: * simulating a point mass * in 3D * with velocity parameterized in Cartesian coordinates

State variables:

x_e: x-position, in Earth axes. [meters] y_e: y-position, in Earth axes. [meters] z_e: z-position, in Earth axes. [meters] u_e: x-velocity, in Earth axes. [m/s] v_e: v-velocity, in Earth axes. [m/s] w_e: z-velocity, in Earth axes. [m/s]

Indirect control variables:

alpha: Angle of attack. [degrees] beta: Sideslip angle. [degrees] bank: Bank angle. [radians]

Control variables:

Fx_e: Force along the Earth-x axis. [N] Fy_e: Force along the Earth-y axis. [N] Fz_e: Force along the Earth-z axis. [N]

Parameters:
  • mass_props (aerosandbox.weights.mass_properties.MassProperties) –

  • x_e (Union[float, aerosandbox.numpy.ndarray]) –

  • y_e (Union[float, aerosandbox.numpy.ndarray]) –

  • z_e (Union[float, aerosandbox.numpy.ndarray]) –

  • u_e (Union[float, aerosandbox.numpy.ndarray]) –

  • v_e (Union[float, aerosandbox.numpy.ndarray]) –

  • w_e (Union[float, aerosandbox.numpy.ndarray]) –

  • alpha (Union[float, aerosandbox.numpy.ndarray]) –

  • beta (Union[float, aerosandbox.numpy.ndarray]) –

  • bank (Union[float, aerosandbox.numpy.ndarray]) –

property state: Dict[str, float | aerosandbox.numpy.ndarray]#

Returns the state variables of this Dynamics instance as a Dict.

Keys are strings that give the name of the variables. Values are the variables themselves.

This method should look something like:
>>> {
>>>     "x_e": self.x_e,
>>>     "u_e": self.u_e,
>>>     ...
>>> }
Return type:

Dict[str, Union[float, aerosandbox.numpy.ndarray]]

property control_variables: Dict[str, float | aerosandbox.numpy.ndarray]#
Return type:

Dict[str, Union[float, aerosandbox.numpy.ndarray]]

property speed: float#
Return type:

float

property gamma#

Returns the flight path angle, in radians.

Positive flight path angle indicates positive vertical speed.

property track#

Returns the track angle, in radians.

  • Track of 0 == North == aligned with x_e axis

  • Track of np.pi / 2 == East == aligned with y_e axis

state_derivatives()[source]#

A function that returns the derivatives with respect to time of the state specified in the state property.

Should return a Dict with the same keys as the state property.

Return type:

Dict[str, Union[float, aerosandbox.numpy.ndarray]]

convert_axes(x_from, y_from, z_from, from_axes, to_axes)[source]#

Converts a vector [x_from, y_from, z_from], as given in the from_axes frame, to an equivalent vector [x_to, y_to, z_to], as given in the to_axes frame.

Identical to OperatingPoint.convert_axes(), but adds in “earth” as a valid axis frame. For more documentation, see the docstring of OperatingPoint.convert_axes().

Both from_axes and to_axes should be a string, one of:
  • “geometry”

  • “body”

  • “wind”

  • “stability”

  • “earth”

Parameters:
  • x_from (float) – x-component of the vector, in from_axes frame.

  • y_from (float) – y-component of the vector, in from_axes frame.

  • z_from (float) – z-component of the vector, in from_axes frame.

  • from_axes (str) – The axes to convert from. See above for options.

  • to_axes (str) – The axes to convert to. See above for options.

Return type:

Tuple[float, float, float]

Returns: The x-, y-, and z-components of the vector, in to_axes frame. Given as a tuple.

add_force(Fx=0, Fy=0, Fz=0, axes='earth')[source]#

Adds a force (in whichever axis system you choose) to this Dynamics instance.

Parameters:
  • Fx (Union[float, aerosandbox.numpy.ndarray]) – Force in the x-direction in the axis system chosen. [N]

  • Fy (Union[float, aerosandbox.numpy.ndarray]) – Force in the y-direction in the axis system chosen. [N]

  • Fz (Union[float, aerosandbox.numpy.ndarray]) – Force in the z-direction in the axis system chosen. [N]

  • axes – The axis system that the specified force is in. One of: * “geometry” * “body” * “wind” * “stability” * “earth”

Return type:

None

Returns: None (in-place)

class aerosandbox.DynamicsPointMass3DSpeedGammaTrack(mass_props=None, x_e=0, y_e=0, z_e=0, speed=0, gamma=0, track=0, alpha=0, beta=0, bank=0)[source]#

Bases: aerosandbox.dynamics.point_mass.common_point_mass._DynamicsPointMassBaseClass

Dynamics instance: * simulating a point mass * in 3D * with velocity parameterized in speed-gamma-track space

State variables:

x_e: x-position, in Earth axes. [meters] y_e: y-position, in Earth axes. [meters] z_e: z-position, in Earth axes. [meters] speed: Speed; equivalent to u_w, the x-velocity in wind axes. [m/s] gamma: Flight path angle. [radians] track: Track angle. [radians]

  • Track of 0 == North == aligned with x_e axis

  • Track of np.pi / 2 == East == aligned with y_e axis

Indirect control variables:

alpha: Angle of attack. [degrees] beta: Sideslip angle. [degrees] bank: Bank angle. [radians]

Control variables:

Fx_w: Force along the wind-x axis. [N] Fy_w: Force along the wind-y axis. [N] Fz_w: Force along the wind-z axis. [N]

Parameters:
  • mass_props (aerosandbox.weights.mass_properties.MassProperties) –

  • x_e (Union[float, aerosandbox.numpy.ndarray]) –

  • y_e (Union[float, aerosandbox.numpy.ndarray]) –

  • z_e (Union[float, aerosandbox.numpy.ndarray]) –

  • speed (Union[float, aerosandbox.numpy.ndarray]) –

  • gamma (Union[float, aerosandbox.numpy.ndarray]) –

  • track (Union[float, aerosandbox.numpy.ndarray]) –

  • alpha (Union[float, aerosandbox.numpy.ndarray]) –

  • beta (Union[float, aerosandbox.numpy.ndarray]) –

  • bank (Union[float, aerosandbox.numpy.ndarray]) –

property state: Dict[str, float | aerosandbox.numpy.ndarray]#

Returns the state variables of this Dynamics instance as a Dict.

Keys are strings that give the name of the variables. Values are the variables themselves.

This method should look something like:
>>> {
>>>     "x_e": self.x_e,
>>>     "u_e": self.u_e,
>>>     ...
>>> }
Return type:

Dict[str, Union[float, aerosandbox.numpy.ndarray]]

property control_variables: Dict[str, float | aerosandbox.numpy.ndarray]#
Return type:

Dict[str, Union[float, aerosandbox.numpy.ndarray]]

property u_e#
property v_e#
property w_e#
state_derivatives()[source]#

A function that returns the derivatives with respect to time of the state specified in the state property.

Should return a Dict with the same keys as the state property.

Return type:

Dict[str, Union[float, aerosandbox.numpy.ndarray]]

convert_axes(x_from, y_from, z_from, from_axes, to_axes)[source]#

Converts a vector [x_from, y_from, z_from], as given in the from_axes frame, to an equivalent vector [x_to, y_to, z_to], as given in the to_axes frame.

Identical to OperatingPoint.convert_axes(), but adds in “earth” as a valid axis frame. For more documentation, see the docstring of OperatingPoint.convert_axes().

Both from_axes and to_axes should be a string, one of:
  • “geometry”

  • “body”

  • “wind”

  • “stability”

  • “earth”

Parameters:
  • x_from (float) – x-component of the vector, in from_axes frame.

  • y_from (float) – y-component of the vector, in from_axes frame.

  • z_from (float) – z-component of the vector, in from_axes frame.

  • from_axes (str) – The axes to convert from. See above for options.

  • to_axes (str) – The axes to convert to. See above for options.

Return type:

Tuple[float, float, float]

Returns: The x-, y-, and z-components of the vector, in to_axes frame. Given as a tuple.

add_force(Fx=0, Fy=0, Fz=0, axes='wind')[source]#

Adds a force (in whichever axis system you choose) to this Dynamics instance.

Parameters:
  • Fx (Union[float, aerosandbox.numpy.ndarray]) – Force in the x-direction in the axis system chosen. [N]

  • Fy (Union[float, aerosandbox.numpy.ndarray]) – Force in the y-direction in the axis system chosen. [N]

  • Fz (Union[float, aerosandbox.numpy.ndarray]) – Force in the z-direction in the axis system chosen. [N]

  • axes – The axis system that the specified force is in. One of: * “geometry” * “body” * “wind” * “stability” * “earth”

Return type:

None

Returns: None (in-place)

class aerosandbox.DynamicsRigidBody2DBody(mass_props=None, x_e=0, z_e=0, u_b=0, w_b=0, theta=0, q=0)[source]#

Bases: aerosandbox.dynamics.rigid_body.rigid_3D.body_euler.DynamicsRigidBody3DBodyEuler

Dynamics instance: * simulating a rigid body * in 2D * with velocity parameterized in body axes

State variables:

x_e: x-position, in Earth axes. [meters] z_e: z-position, in Earth axes. [meters] u_b: x-velocity, in body axes. [m/s] w_b: z-velocity, in body axes. [m/s] theta: pitch angle. [rad] q: y-angular-velocity, in body axes. [rad/sec]

Control variables:

Fx_b: Force along the body-x axis. [N] Fz_b: Force along the body-z axis. [N] My_b: Moment about the body-y axis. [Nm]

Parameters:
  • mass_props (aerosandbox.weights.mass_properties.MassProperties) –

  • x_e (Union[float, aerosandbox.numpy.ndarray]) –

  • z_e (Union[float, aerosandbox.numpy.ndarray]) –

  • u_b (Union[float, aerosandbox.numpy.ndarray]) –

  • w_b (Union[float, aerosandbox.numpy.ndarray]) –

  • theta (Union[float, aerosandbox.numpy.ndarray]) –

  • q (Union[float, aerosandbox.numpy.ndarray]) –

property state#

Returns the state variables of this Dynamics instance as a Dict.

Keys are strings that give the name of the variables. Values are the variables themselves.

This method should look something like:
>>> {
>>>     "x_e": self.x_e,
>>>     "u_e": self.u_e,
>>>     ...
>>> }
property control_variables#
state_derivatives()[source]#

Computes the state derivatives (i.e. equations of motion) for a body in 3D space.

Based on Section 9.8.2 of Flight Vehicle Aerodynamics by Mark Drela.

Returns:

{

“xe” : d_xe, “ye” : d_ye, “ze” : d_ze, “u” : d_u, “v” : d_v, “w” : d_w, “phi” : d_phi, “theta”: d_theta, “psi” : d_psi, “p” : d_p, “q” : d_q, “r” : d_r,

}

Return type:

Time derivatives of each of the 12 state variables, given in a dictionary

class aerosandbox.DynamicsRigidBody3DBodyEuler(mass_props=None, x_e=0, y_e=0, z_e=0, u_b=0, v_b=0, w_b=0, phi=0, theta=0, psi=0, p=0, q=0, r=0)[source]#

Bases: aerosandbox.dynamics.rigid_body.common_rigid_body._DynamicsRigidBodyBaseClass

Dynamics instance: * simulating a rigid body * in 3D * with velocity parameterized in body axes * and angle parameterized in Euler angles

State variables:

x_e: x-position, in Earth axes. [meters] y_e: y-position, in Earth axes. [meters] z_e: z-position, in Earth axes. [meters] u_b: x-velocity, in body axes. [m/s] v_b: y-velocity, in body axes. [m/s] w_b: z-velocity, in body axes. [m/s] phi: roll angle. Uses yaw-pitch-roll Euler angle convention. [rad] theta: pitch angle. Uses yaw-pitch-roll Euler angle convention. [rad] psi: yaw angle. Uses yaw-pitch-roll Euler angle convention. [rad] p: x-angular-velocity, in body axes. [rad/sec] q: y-angular-velocity, in body axes. [rad/sec] r: z-angular-velocity, in body axes. [rad/sec]

Control variables:

Fx_b: Force along the body-x axis. [N] Fy_b: Force along the body-y axis. [N] Fz_b: Force along the body-z axis. [N] Mx_b: Moment about the body-x axis. [Nm] My_b: Moment about the body-y axis. [Nm] Mz_b: Moment about the body-z axis. [Nm] hx_b: Angular momentum (e.g., propellers) about the body-x axis. [kg*m^2/sec] hy_b: Angular momentum (e.g., propellers) about the body-y axis. [kg*m^2/sec] hz_b: Angular momentum (e.g., propellers) about the body-z axis. [kg*m^2/sec]

Parameters:
  • mass_props (aerosandbox.weights.mass_properties.MassProperties) –

  • x_e (Union[float, aerosandbox.numpy.ndarray]) –

  • y_e (Union[float, aerosandbox.numpy.ndarray]) –

  • z_e (Union[float, aerosandbox.numpy.ndarray]) –

  • u_b (Union[float, aerosandbox.numpy.ndarray]) –

  • v_b (Union[float, aerosandbox.numpy.ndarray]) –

  • w_b (Union[float, aerosandbox.numpy.ndarray]) –

  • phi (Union[float, aerosandbox.numpy.ndarray]) –

  • theta (Union[float, aerosandbox.numpy.ndarray]) –

  • psi (Union[float, aerosandbox.numpy.ndarray]) –

  • p (Union[float, aerosandbox.numpy.ndarray]) –

  • q (Union[float, aerosandbox.numpy.ndarray]) –

  • r (Union[float, aerosandbox.numpy.ndarray]) –

property state#

Returns the state variables of this Dynamics instance as a Dict.

Keys are strings that give the name of the variables. Values are the variables themselves.

This method should look something like:
>>> {
>>>     "x_e": self.x_e,
>>>     "u_e": self.u_e,
>>>     ...
>>> }
property control_variables#
property speed#

The speed of the object, expressed as a scalar.

property alpha#

The angle of attack, in degrees.

property beta#

The sideslip angle, in degrees.

state_derivatives()[source]#

Computes the state derivatives (i.e. equations of motion) for a body in 3D space.

Based on Section 9.8.2 of Flight Vehicle Aerodynamics by Mark Drela.

Returns:

{

“xe” : d_xe, “ye” : d_ye, “ze” : d_ze, “u” : d_u, “v” : d_v, “w” : d_w, “phi” : d_phi, “theta”: d_theta, “psi” : d_psi, “p” : d_p, “q” : d_q, “r” : d_r,

}

Return type:

Time derivatives of each of the 12 state variables, given in a dictionary

convert_axes(x_from, y_from, z_from, from_axes, to_axes)[source]#

Converts a vector [x_from, y_from, z_from], as given in the from_axes frame, to an equivalent vector [x_to, y_to, z_to], as given in the to_axes frame.

Identical to OperatingPoint.convert_axes(), but adds in “earth” as a valid axis frame. For more documentation, see the docstring of OperatingPoint.convert_axes().

Both from_axes and to_axes should be a string, one of:
  • “geometry”

  • “body”

  • “wind”

  • “stability”

  • “earth”

Parameters:
  • x_from – x-component of the vector, in from_axes frame.

  • y_from – y-component of the vector, in from_axes frame.

  • z_from – z-component of the vector, in from_axes frame.

  • from_axes (str) – The axes to convert from.

  • to_axes (str) – The axes to convert to.

Returns: The x-, y-, and z-components of the vector, in to_axes frame. Given as a tuple.

add_force(Fx=0, Fy=0, Fz=0, axes='body')[source]#

Adds a force (in whichever axis system you choose) to this Dynamics instance.

Parameters:
  • Fx (Union[float, aerosandbox.numpy.ndarray]) – Force in the x-direction in the axis system chosen. [N]

  • Fy (Union[float, aerosandbox.numpy.ndarray]) – Force in the y-direction in the axis system chosen. [N]

  • Fz (Union[float, aerosandbox.numpy.ndarray]) – Force in the z-direction in the axis system chosen. [N]

  • axes – The axis system that the specified force is in. One of: * “geometry” * “body” * “wind” * “stability” * “earth”

Returns: None (in-place)

add_moment(Mx=0, My=0, Mz=0, axes='body')[source]#

Adds a moment (in whichever axis system you choose) to this Dynamics instance.

Parameters:
  • Mx (Union[float, aerosandbox.numpy.ndarray]) – Moment about the x-axis in the axis system chosen. Assumed these moments are applied about the center of mass. [Nm]

  • My (Union[float, aerosandbox.numpy.ndarray]) – Moment about the y-axis in the axis system chosen. Assumed these moments are applied about the center of mass. [Nm]

  • Mz (Union[float, aerosandbox.numpy.ndarray]) – Moment about the z-axis in the axis system chosen. Assumed these moments are applied about the center of mass. [Nm]

  • axes – The axis system that the specified moment is in. One of: * “geometry” * “body” * “wind” * “stability” * “earth”

Returns: None (in-place)

class aerosandbox.AirfoilInviscid(airfoil, op_point, ground_effect=False)[source]#

Bases: aerosandbox.common.ImplicitAnalysis

An implicit analysis for inviscid analysis of an airfoil (or family of airfoils).

Key outputs:

  • AirfoilInviscid.Cl

Parameters:
__repr__()[source]#

Return repr(self).

_setup_unknowns()[source]#
calculate_velocity(x_field, y_field)[source]#
Return type:

[aerosandbox.numpy.ndarray, aerosandbox.numpy.ndarray]

_enforce_governing_equations()[source]#
_calculate_forces()[source]#
draw_streamlines(res=200, show=True)[source]#
draw_cp(show=True)[source]#
class aerosandbox.XFoil(airfoil, Re=0.0, mach=0.0, n_crit=9.0, xtr_upper=1.0, xtr_lower=1.0, hinge_point_x=0.75, full_potential=False, max_iter=100, xfoil_command='xfoil', xfoil_repanel=True, xfoil_repanel_n_points=279, include_bl_data=False, verbose=False, timeout=30, working_directory=None)[source]#

Bases: aerosandbox.common.ExplicitAnalysis

An interface to XFoil, a 2D airfoil analysis tool developed by Mark Drela at MIT.

Requires XFoil to be on your computer; XFoil is available here: https://web.mit.edu/drela/Public/web/xfoil/

It is recommended (but not required) that you add XFoil to your system PATH environment variable such that it can be called with the command xfoil. If this is not the case, you need to specify the path to your XFoil executable using the xfoil_command argument of the constructor.

Usage example:

>>> xf = XFoil(
>>>     airfoil=Airfoil("naca2412").repanel(n_points_per_side=100),
>>>     Re=1e6,
>>> )
>>>
>>> result_at_single_alpha = xf.alpha(5)
>>> result_at_several_CLs = xf.cl([0.5, 0.7, 0.8, 0.9])
>>> result_at_multiple_alphas = xf.alpha([3, 5, 60]) # Note: if a result does not converge (such as the 60 degree case here), it will not be included in the results.
Parameters:
  • airfoil (aerosandbox.geometry.Airfoil) –

  • Re (float) –

  • mach (float) –

  • n_crit (float) –

  • xtr_upper (float) –

  • xtr_lower (float) –

  • hinge_point_x (float) –

  • full_potential (bool) –

  • max_iter (int) –

  • xfoil_command (str) –

  • xfoil_repanel (bool) –

  • xfoil_repanel_n_points (int) –

  • include_bl_data (bool) –

  • verbose (bool) –

  • timeout (Union[float, int, None]) –

  • working_directory (Union[pathlib.Path, str]) –

__repr__()[source]#

Return repr(self).

_default_keystrokes(airfoil_filename, output_filename)[source]#

Returns a list of XFoil keystrokes that are common to all XFoil runs.

Returns:

A list of strings, each of which is a single XFoil keystroke to be followed by <enter>.

Parameters:
  • airfoil_filename (str) –

  • output_filename (str) –

Return type:

List[str]

_run_xfoil(run_command, read_bl_data_from=None)[source]#

Private function to run XFoil.

Args: run_command: A string with any XFoil keystroke inputs that you’d like. By default, you start off within the OPER menu. All of the inputs indicated in the constructor have been set already, but you can override them here (for this run only) if you want.

Returns: A dictionary containing all converged solutions obtained with your inputs.

Parameters:
  • run_command (str) –

  • read_bl_data_from (str) –

Return type:

Dict[str, aerosandbox.numpy.ndarray]

open_interactive()[source]#

Opens a new terminal window and runs XFoil interactively. This is useful for detailed analysis or debugging.

Returns: None

Return type:

None

alpha(alpha, start_at=0)[source]#

Execute XFoil at a given angle of attack, or at a sequence of angles of attack.

Parameters:
  • alpha (Union[float, aerosandbox.numpy.ndarray]) – The angle of attack [degrees]. Can be either a float or an iterable of floats, such as an array.

  • start_at (Union[float, None]) – Chooses whether to split a large sweep into two runs that diverge away from some central value,

  • example (to improve convergence. As an) –

  • alpha=20 (if you wanted to sweep from alpha=-20 to) –

  • want (you might) –

  • together (to instead do two sweeps and stitch them) –

    0 to 20, and 0 to -20. start_at can be either:

    • None, in which case the alpha inputs are run as a single sequence in the order given.

    • A float that corresponds to an angle of attack (in degrees), in which case the alpha inputs are

    split into two sequences that diverge from the start_at value. Successful runs are then sorted by alpha before returning.

Return type:

Dict[str, aerosandbox.numpy.ndarray]

Returns: A dictionary with the XFoil results. Dictionary values are arrays; they may not be the same shape as your input array if some points did not converge.

cl(cl, start_at=0)[source]#

Execute XFoil at a given lift coefficient, or at a sequence of lift coefficients.

Parameters:
  • cl (Union[float, aerosandbox.numpy.ndarray]) – The lift coefficient [-]. Can be either a float or an iterable of floats, such as an array.

  • start_at (Union[float, None]) – Chooses whether to split a large sweep into two runs that diverge away from some central value,

  • example (to improve convergence. As an) –

  • cl=1.5 (if you wanted to sweep from cl=-1.5 to) –

  • to (you might want) –

  • together (instead do two sweeps and stitch them) –

    0 to 1.5, and 0 to -1.5. start_at can be either:

    • None, in which case the cl inputs are run as a single sequence in the order given.

    • A float that corresponds to an lift coefficient, in which case the cl inputs are

    split into two sequences that diverge from the start_at value. Successful runs are then sorted by alpha before returning.

Return type:

Dict[str, aerosandbox.numpy.ndarray]

Returns: A dictionary with the XFoil results. Dictionary values are arrays; they may not be the same shape as your input array if some points did not converge.

class aerosandbox.MSES(airfoil, n_crit=9.0, xtr_upper=1.0, xtr_lower=1.0, max_iter=100, mset_command='mset', mses_command='mses', mplot_command='mplot', use_xvfb=None, xvfb_command='xvfb-run -a', verbosity=1, timeout_mset=10, timeout_mses=60, timeout_mplot=10, working_directory=None, behavior_after_unconverged_run='reinitialize', mset_alpha=0, mset_n=141, mset_e=0.4, mset_io=37, mset_x=0.85, mses_mcrit=0.99, mses_mucon=-1.0)[source]#

Bases: aerosandbox.common.ExplicitAnalysis

An interface to MSES, MSET, and MPLOT, a 2D airfoil analysis system developed by Mark Drela at MIT.

Requires compiled binaries for all the programs to be on your computer; MSES is available here: https://web.mit.edu/drela/Public/web/mses/ Academics can get a copy by emailing the MIT Tech. Licensing Office; MIT affiliates can find a copy on Athena.

It is recommended (but not required) that you add MSES, MSET, and MPLOT to your system PATH environment variable such that they can be called with the commands mses, mset, and mplot. If this is not the case, you need to specify the path to these executables using the command arguments of the constructor.

Note that MSES, MSET, and MPLOT by default open up X11 windows on your computer. If you prefer that this doesn’t happen (for extra speed), or if you cannot have this happen (e.g., you are computing in an environment without proper X11 support, like Windows Subsystem for Linux), you should use XVFB. https://en.wikipedia.org/wiki/Xvfb

XVFB is a virtual “display” server that can receive X11 output and safely dump it. (If you don’t use XVFB and you don’t have proper X11 support on your computer, this AeroSandbox MSES module will simply error out during the MSET call - probably not what you want.)

To install XVFB on a Linux machine, use:

`bash sudo apt-get install xvfb `

Then, when instantiating this MSES instance in AeroSandbox, pass the use_xvfb flag to be True. Default behavior here is that this class will look for the XVFB executable, xvfb-run, on your machine. If it finds it, it will run with XVFB enabled. If it does not, it will run without XVFB.


Usage example:

>>> ms = MSES(
>>>     airfoil=Airfoil("naca2412").repanel(n_points_per_side=100),
>>>     Re=1e6,
>>>     mach=0.2,
>>> )
>>>
>>> result_at_single_alpha = ms.alpha(5)
>>> #result_at_several_CLs = ms.cl([0.5, 0.7, 0.8, 0.9])
>>> result_at_multiple_alphas = ms.alpha([3, 5, 60]) # Note: if a result does not converge (such as the 60 degree case here), it will not be included in the results.
Parameters:
  • airfoil (aerosandbox.geometry.Airfoil) –

  • n_crit (float) –

  • xtr_upper (float) –

  • xtr_lower (float) –

  • max_iter (int) –

  • mset_command (str) –

  • mses_command (str) –

  • mplot_command (str) –

  • use_xvfb (bool) –

  • xvfb_command (str) –

  • verbosity (int) –

  • timeout_mset (Union[float, int, None]) –

  • timeout_mses (Union[float, int, None]) –

  • timeout_mplot (Union[float, int, None]) –

  • working_directory (str) –

  • behavior_after_unconverged_run (str) –

  • mset_alpha (float) –

  • mset_n (int) –

  • mset_e (float) –

  • mset_io (int) –

  • mset_x (float) –

  • mses_mcrit (float) –

  • mses_mucon (float) –

run(alpha=0.0, Re=0.0, mach=0.01)[source]#
Parameters:
  • alpha (Union[float, aerosandbox.numpy.ndarray, List]) –

  • Re (Union[float, aerosandbox.numpy.ndarray, List]) –

  • mach (Union[float, aerosandbox.numpy.ndarray, List]) –

class aerosandbox.VortexLatticeMethod(airplane, op_point, xyz_ref=None, run_symmetric_if_possible=False, verbose=False, spanwise_resolution=10, spanwise_spacing_function=np.cosspace, chordwise_resolution=10, chordwise_spacing_function=np.cosspace, vortex_core_radius=1e-08, align_trailing_vortices_with_wind=False)[source]#

Bases: aerosandbox.ExplicitAnalysis

An explicit (linear) vortex-lattice-method aerodynamics analysis.

Usage example:
>>> analysis = asb.VortexLatticeMethod(
>>>     airplane=my_airplane,
>>>     op_point=asb.OperatingPoint(
>>>         velocity=100, # m/s
>>>         alpha=5, # deg
>>>         beta=4, # deg
>>>         p=0.01, # rad/sec
>>>         q=0.02, # rad/sec
>>>         r=0.03, # rad/sec
>>>     )
>>> )
>>> aero_data = analysis.run()
>>> analysis.draw()
Parameters:
  • airplane (aerosandbox.geometry.Airplane) –

  • op_point (aerosandbox.performance.OperatingPoint) –

  • xyz_ref (List[float]) –

  • run_symmetric_if_possible (bool) –

  • verbose (bool) –

  • spanwise_resolution (int) –

  • spanwise_spacing_function (Callable[[float, float, float], aerosandbox.geometry.np.ndarray]) –

  • chordwise_resolution (int) –

  • chordwise_spacing_function (Callable[[float, float, float], aerosandbox.geometry.np.ndarray]) –

  • vortex_core_radius (float) –

  • align_trailing_vortices_with_wind (bool) –

__repr__()[source]#

Return repr(self).

run()[source]#

Computes the aerodynamic forces.

Returns a dictionary with keys:

  • ‘F_g’ : an [x, y, z] list of forces in geometry axes [N]

  • ‘F_b’ : an [x, y, z] list of forces in body axes [N]

  • ‘F_w’ : an [x, y, z] list of forces in wind axes [N]

  • ‘M_g’ : an [x, y, z] list of moments about geometry axes [Nm]

  • ‘M_b’ : an [x, y, z] list of moments about body axes [Nm]

  • ‘M_w’ : an [x, y, z] list of moments about wind axes [Nm]

  • ‘L’ : the lift force [N]. Definitionally, this is in wind axes.

  • ‘Y’ : the side force [N]. This is in wind axes.

  • ‘D’ : the drag force [N]. Definitionally, this is in wind axes.

  • ‘l_b’, the rolling moment, in body axes [Nm]. Positive is roll-right.

  • ‘m_b’, the pitching moment, in body axes [Nm]. Positive is pitch-up.

  • ‘n_b’, the yawing moment, in body axes [Nm]. Positive is nose-right.

  • ‘CL’, the lift coefficient [-]. Definitionally, this is in wind axes.

  • ‘CY’, the sideforce coefficient [-]. This is in wind axes.

  • ‘CD’, the drag coefficient [-]. Definitionally, this is in wind axes.

  • ‘Cl’, the rolling coefficient [-], in body axes

  • ‘Cm’, the pitching coefficient [-], in body axes

  • ‘Cn’, the yawing coefficient [-], in body axes

Nondimensional values are nondimensionalized using reference values in the VortexLatticeMethod.airplane object.

Return type:

Dict[str, Any]

run_with_stability_derivatives(alpha=True, beta=True, p=True, q=True, r=True)[source]#

Computes the aerodynamic forces and moments on the airplane, and the stability derivatives.

Arguments essentially determine which stability derivatives are computed. If a stability derivative is not needed, leaving it False will speed up the computation.

Parameters:
  • alpha (-) – If True, compute the stability derivatives with respect to the angle of attack (alpha).

  • beta (-) – If True, compute the stability derivatives with respect to the sideslip angle (beta).

  • p (-) – If True, compute the stability derivatives with respect to the body-axis roll rate (p).

  • q (-) – If True, compute the stability derivatives with respect to the body-axis pitch rate (q).

  • r (-) – If True, compute the stability derivatives with respect to the body-axis yaw rate (r).

Returns: a dictionary with keys:

  • ‘F_g’ : an [x, y, z] list of forces in geometry axes [N]

  • ‘F_b’ : an [x, y, z] list of forces in body axes [N]

  • ‘F_w’ : an [x, y, z] list of forces in wind axes [N]

  • ‘M_g’ : an [x, y, z] list of moments about geometry axes [Nm]

  • ‘M_b’ : an [x, y, z] list of moments about body axes [Nm]

  • ‘M_w’ : an [x, y, z] list of moments about wind axes [Nm]

  • ‘L’ : the lift force [N]. Definitionally, this is in wind axes.

  • ‘Y’ : the side force [N]. This is in wind axes.

  • ‘D’ : the drag force [N]. Definitionally, this is in wind axes.

  • ‘l_b’, the rolling moment, in body axes [Nm]. Positive is roll-right.

  • ‘m_b’, the pitching moment, in body axes [Nm]. Positive is pitch-up.

  • ‘n_b’, the yawing moment, in body axes [Nm]. Positive is nose-right.

  • ‘CL’, the lift coefficient [-]. Definitionally, this is in wind axes.

  • ‘CY’, the sideforce coefficient [-]. This is in wind axes.

  • ‘CD’, the drag coefficient [-]. Definitionally, this is in wind axes.

  • ‘Cl’, the rolling coefficient [-], in body axes

  • ‘Cm’, the pitching coefficient [-], in body axes

  • ‘Cn’, the yawing coefficient [-], in body axes

Along with additional keys, depending on the value of the alpha, beta, p, q, and r arguments. For example, if alpha=True, then the following additional keys will be present:

  • ‘CLa’, the lift coefficient derivative with respect to alpha [1/rad]

  • ‘CDa’, the drag coefficient derivative with respect to alpha [1/rad]

  • ‘CYa’, the sideforce coefficient derivative with respect to alpha [1/rad]

  • ‘Cla’, the rolling moment coefficient derivative with respect to alpha [1/rad]

  • ‘Cma’, the pitching moment coefficient derivative with respect to alpha [1/rad]

  • ‘Cna’, the yawing moment coefficient derivative with respect to alpha [1/rad]

  • ‘x_np’, the neutral point location in the x direction [m]

Nondimensional values are nondimensionalized using reference values in the VortexLatticeMethod.airplane object.

Data types:
  • The “L”, “Y”, “D”, “l_b”, “m_b”, “n_b”, “CL”, “CY”, “CD”, “Cl”, “Cm”, and “Cn” keys are:

    • floats if the OperatingPoint object is not vectorized (i.e., if all attributes of OperatingPoint

    are floats, not arrays).

    • arrays if the OperatingPoint object is vectorized (i.e., if any attribute of OperatingPoint is an

    array).

  • The “F_g”, “F_b”, “F_w”, “M_g”, “M_b”, and “M_w” keys are always lists, which will contain either

floats or arrays, again depending on whether the OperatingPoint object is vectorized or not.

get_induced_velocity_at_points(points)[source]#

Computes the induced velocity at a set of points in the flowfield.

Parameters:

points (aerosandbox.geometry.np.ndarray) – A Nx3 array of points that you would like to know the induced velocities at. Given in geometry axes.

Return type:

aerosandbox.geometry.np.ndarray

Returns: A Nx3 of the induced velocity at those points. Given in geometry axes.

get_velocity_at_points(points)[source]#

Computes the velocity at a set of points in the flowfield.

Parameters:

points (aerosandbox.geometry.np.ndarray) – A Nx3 array of points that you would like to know the velocities at. Given in geometry axes.

Return type:

aerosandbox.geometry.np.ndarray

Returns: A Nx3 of the velocity at those points. Given in geometry axes.

calculate_streamlines(seed_points=None, n_steps=300, length=None)[source]#

Computes streamlines, starting at specific seed points.

After running this function, a new instance variable VortexLatticeFilaments.streamlines is computed

Uses simple forward-Euler integration with a fixed spatial stepsize (i.e., velocity vectors are normalized before ODE integration). After investigation, it’s not worth doing fancier ODE integration methods (adaptive schemes, RK substepping, etc.), due to the near-singular conditions near vortex filaments.

Parameters:
  • seed_points (aerosandbox.geometry.np.ndarray) – A Nx3 ndarray that contains a list of points where streamlines are started. Will be

  • specified. (not) –

  • n_steps (int) – The number of individual streamline steps to trace. Minimum of 2.

  • length (float) – The approximate total length of the streamlines desired, in meters. Will be auto-calculated if

  • specified.

Returns:

a 3D array with dimensions: (n_seed_points) x (3) x (n_steps). Consists of streamlines data.

Result is also saved as an instance variable, VortexLatticeMethod.streamlines.

Return type:

streamlines

draw(c=None, cmap=None, colorbar_label=None, show=True, show_kwargs=None, draw_streamlines=True, recalculate_streamlines=False, backend='pyvista')[source]#

Draws the solution. Note: Must be called on a SOLVED AeroProblem object. To solve an AeroProblem, use opti.solve(). To substitute a solved solution, use ap = sol(ap). :return:

Parameters:
  • c (aerosandbox.geometry.np.ndarray) –

  • cmap (str) –

  • colorbar_label (str) –

  • show (bool) –

  • show_kwargs (Dict) –

  • backend (str) –

class aerosandbox.LiftingLine(airplane, op_point, xyz_ref=None, model_size='medium', run_symmetric_if_possible=False, verbose=False, spanwise_resolution=4, spanwise_spacing_function=np.cosspace, vortex_core_radius=1e-08, align_trailing_vortices_with_wind=False)[source]#

Bases: aerosandbox.ExplicitAnalysis

An implicit aerodynamics analysis based on lifting line theory, with modifications for nonzero sweep and dihedral + multiple wings.

Nonlinear, and includes viscous effects based on 2D data.

Usage example:
>>> analysis = asb.LiftingLine(
>>>     airplane=my_airplane,
>>>     op_point=asb.OperatingPoint(
>>>         velocity=100, # m/s
>>>         alpha=5, # deg
>>>         beta=4, # deg
>>>         p=0.01, # rad/sec
>>>         q=0.02, # rad/sec
>>>         r=0.03, # rad/sec
>>>     )
>>> )
>>> outputs = analysis.run()
Parameters:
  • airplane (aerosandbox.geometry.Airplane) –

  • op_point (aerosandbox.performance.OperatingPoint) –

  • xyz_ref (List[float]) –

  • model_size (str) –

  • run_symmetric_if_possible (bool) –

  • verbose (bool) –

  • spanwise_resolution (int) –

  • spanwise_spacing_function (Callable[[float, float, float], aerosandbox.geometry.np.ndarray]) –

  • vortex_core_radius (float) –

  • align_trailing_vortices_with_wind (bool) –

class AeroComponentResults#
property F_b: List[float | aerosandbox.geometry.np.ndarray]#

An [x, y, z] list of forces in body axes [N]

Return type:

List[Union[float, aerosandbox.geometry.np.ndarray]]

property F_w: List[float | aerosandbox.geometry.np.ndarray]#

An [x, y, z] list of forces in wind axes [N]

Return type:

List[Union[float, aerosandbox.geometry.np.ndarray]]

property M_b: List[float | aerosandbox.geometry.np.ndarray]#

An [x, y, z] list of moments about body axes [Nm]

Return type:

List[Union[float, aerosandbox.geometry.np.ndarray]]

property M_w: List[float | aerosandbox.geometry.np.ndarray]#

An [x, y, z] list of moments about wind axes [Nm]

Return type:

List[Union[float, aerosandbox.geometry.np.ndarray]]

property L: float | aerosandbox.geometry.np.ndarray#

The lift force [N]. Definitionally, this is in wind axes.

Return type:

Union[float, aerosandbox.geometry.np.ndarray]

property Y: float | aerosandbox.geometry.np.ndarray#

The side force [N]. Definitionally, this is in wind axes.

Return type:

Union[float, aerosandbox.geometry.np.ndarray]

property D: float | aerosandbox.geometry.np.ndarray#

The drag force [N]. Definitionally, this is in wind axes.

Return type:

Union[float, aerosandbox.geometry.np.ndarray]

property l_b: float | aerosandbox.geometry.np.ndarray#

The rolling moment [Nm] in body axes. Positive is roll-right.

Return type:

Union[float, aerosandbox.geometry.np.ndarray]

property m_b: float | aerosandbox.geometry.np.ndarray#

The pitching moment [Nm] in body axes. Positive is nose-up.

Return type:

Union[float, aerosandbox.geometry.np.ndarray]

property n_b: float | aerosandbox.geometry.np.ndarray#

The yawing moment [Nm] in body axes. Positive is nose-right.

Return type:

Union[float, aerosandbox.geometry.np.ndarray]

s_ref: float#
c_ref: float#
b_ref: float#
op_point: aerosandbox.performance.OperatingPoint#
F_g: List[float | aerosandbox.geometry.np.ndarray]#
M_g: List[float | aerosandbox.geometry.np.ndarray]#
__repr__()#

Return repr(self).

__repr__()[source]#

Return repr(self).

run()[source]#

Computes the aerodynamic forces.

Returns a dictionary with keys:

  • ‘F_g’ : an [x, y, z] list of forces in geometry axes [N]

  • ‘F_b’ : an [x, y, z] list of forces in body axes [N]

  • ‘F_w’ : an [x, y, z] list of forces in wind axes [N]

  • ‘M_g’ : an [x, y, z] list of moments about geometry axes [Nm]

  • ‘M_b’ : an [x, y, z] list of moments about body axes [Nm]

  • ‘M_w’ : an [x, y, z] list of moments about wind axes [Nm]

  • ‘L’ : the lift force [N]. Definitionally, this is in wind axes.

  • ‘Y’ : the side force [N]. This is in wind axes.

  • ‘D’ : the drag force [N]. Definitionally, this is in wind axes.

  • ‘l_b’, the rolling moment, in body axes [Nm]. Positive is roll-right.

  • ‘m_b’, the pitching moment, in body axes [Nm]. Positive is pitch-up.

  • ‘n_b’, the yawing moment, in body axes [Nm]. Positive is nose-right.

  • ‘CL’, the lift coefficient [-]. Definitionally, this is in wind axes.

  • ‘CY’, the sideforce coefficient [-]. This is in wind axes.

  • ‘CD’, the drag coefficient [-]. Definitionally, this is in wind axes.

  • ‘Cl’, the rolling coefficient [-], in body axes

  • ‘Cm’, the pitching coefficient [-], in body axes

  • ‘Cn’, the yawing coefficient [-], in body axes

Nondimensional values are nondimensionalized using reference values in the LiftingLine.airplane object.

Data types:
  • The “L”, “Y”, “D”, “l_b”, “m_b”, “n_b”, “CL”, “CY”, “CD”, “Cl”, “Cm”, and “Cn” keys are:

    • floats if the OperatingPoint object is not vectorized (i.e., if all attributes of OperatingPoint

    are floats, not arrays).

    • arrays if the OperatingPoint object is vectorized (i.e., if any attribute of OperatingPoint is an

    array).

  • The “F_g”, “F_b”, “F_w”, “M_g”, “M_b”, and “M_w” keys are always lists, which will contain either

floats or arrays, again depending on whether the OperatingPoint object is vectorized or not.

Return type:

Dict

run_with_stability_derivatives(alpha=True, beta=True, p=True, q=True, r=True)[source]#

Computes the aerodynamic forces and moments on the airplane, and the stability derivatives.

Arguments essentially determine which stability derivatives are computed. If a stability derivative is not needed, leaving it False will speed up the computation.

Parameters:
  • alpha (-) – If True, compute the stability derivatives with respect to the angle of attack (alpha).

  • beta (-) – If True, compute the stability derivatives with respect to the sideslip angle (beta).

  • p (-) – If True, compute the stability derivatives with respect to the body-axis roll rate (p).

  • q (-) – If True, compute the stability derivatives with respect to the body-axis pitch rate (q).

  • r (-) – If True, compute the stability derivatives with respect to the body-axis yaw rate (r).

Return type:

Dict[str, Union[Union[float, aerosandbox.geometry.np.ndarray], List[Union[float, aerosandbox.geometry.np.ndarray]]]]

Returns: a dictionary with keys:

  • ‘F_g’ : an [x, y, z] list of forces in geometry axes [N]

  • ‘F_b’ : an [x, y, z] list of forces in body axes [N]

  • ‘F_w’ : an [x, y, z] list of forces in wind axes [N]

  • ‘M_g’ : an [x, y, z] list of moments about geometry axes [Nm]

  • ‘M_b’ : an [x, y, z] list of moments about body axes [Nm]

  • ‘M_w’ : an [x, y, z] list of moments about wind axes [Nm]

  • ‘L’ : the lift force [N]. Definitionally, this is in wind axes.

  • ‘Y’ : the side force [N]. This is in wind axes.

  • ‘D’ : the drag force [N]. Definitionally, this is in wind axes.

  • ‘l_b’ : the rolling moment, in body axes [Nm]. Positive is roll-right.

  • ‘m_b’ : the pitching moment, in body axes [Nm]. Positive is pitch-up.

  • ‘n_b’ : the yawing moment, in body axes [Nm]. Positive is nose-right.

  • ‘CL’ : the lift coefficient [-]. Definitionally, this is in wind axes.

  • ‘CY’ : the sideforce coefficient [-]. This is in wind axes.

  • ‘CD’ : the drag coefficient [-]. Definitionally, this is in wind axes.

  • ‘Cl’ : the rolling coefficient [-], in body axes

  • ‘Cm’ : the pitching coefficient [-], in body axes

  • ‘Cn’ : the yawing coefficient [-], in body axes

Along with additional keys, depending on the value of the alpha, beta, p, q, and r arguments. For example, if alpha=True, then the following additional keys will be present:

  • ‘CLa’ : the lift coefficient derivative with respect to alpha [1/rad]

  • ‘CDa’ : the drag coefficient derivative with respect to alpha [1/rad]

  • ‘CYa’ : the sideforce coefficient derivative with respect to alpha [1/rad]

  • ‘Cla’ : the rolling moment coefficient derivative with respect to alpha [1/rad]

  • ‘Cma’ : the pitching moment coefficient derivative with respect to alpha [1/rad]

  • ‘Cna’ : the yawing moment coefficient derivative with respect to alpha [1/rad]

  • ‘x_np’: the neutral point location in the x direction [m]

Nondimensional values are nondimensionalized using reference values in the AeroBuildup.airplane object.

Data types:
  • The “L”, “Y”, “D”, “l_b”, “m_b”, “n_b”, “CL”, “CY”, “CD”, “Cl”, “Cm”, and “Cn” keys are:

    • floats if the OperatingPoint object is not vectorized (i.e., if all attributes of OperatingPoint

    are floats, not arrays).

    • arrays if the OperatingPoint object is vectorized (i.e., if any attribute of OperatingPoint is an

    array).

  • The “F_g”, “F_b”, “F_w”, “M_g”, “M_b”, and “M_w” keys are always lists, which will contain either

floats or arrays, again depending on whether the OperatingPoint object is vectorized or not.

wing_aerodynamics()[source]#
Return type:

AeroComponentResults

get_induced_velocity_at_points(points, vortex_strengths=None)[source]#

Computes the induced velocity at a set of points in the flowfield.

Parameters:
  • points (aerosandbox.geometry.np.ndarray) – A Nx3 array of points that you would like to know the induced velocities at. Given in geometry axes.

  • vortex_strengths (aerosandbox.geometry.np.ndarray) –

Return type:

aerosandbox.geometry.np.ndarray

Returns: A Nx3 of the induced velocity at those points. Given in geometry axes.

get_velocity_at_points(points, vortex_strengths=None)[source]#

Computes the velocity at a set of points in the flowfield.

Parameters:
  • points (aerosandbox.geometry.np.ndarray) – A Nx3 array of points that you would like to know the velocities at. Given in geometry axes.

  • vortex_strengths (aerosandbox.geometry.np.ndarray) –

Return type:

aerosandbox.geometry.np.ndarray

Returns: A Nx3 of the velocity at those points. Given in geometry axes.

calculate_fuselage_influences(points)[source]#
Parameters:

points (aerosandbox.geometry.np.ndarray) –

Return type:

aerosandbox.geometry.np.ndarray

calculate_streamlines(seed_points=None, n_steps=300, length=None)[source]#

Computes streamlines, starting at specific seed points.

After running this function, a new instance variable VortexLatticeFilaments.streamlines is computed

Uses simple forward-Euler integration with a fixed spatial stepsize (i.e., velocity vectors are normalized before ODE integration). After investigation, it’s not worth doing fancier ODE integration methods (adaptive schemes, RK substepping, etc.), due to the near-singular conditions near vortex filaments.

Parameters:
  • seed_points (aerosandbox.geometry.np.ndarray) – A Nx3 ndarray that contains a list of points where streamlines are started. Will be

  • specified. (not) –

  • n_steps (int) – The number of individual streamline steps to trace. Minimum of 2.

  • length (float) – The approximate total length of the streamlines desired, in meters. Will be auto-calculated if

  • specified.

Returns:

a 3D array with dimensions: (n_seed_points) x (3) x (n_steps). Consists of streamlines data.

Result is also saved as an instance variable, VortexLatticeMethod.streamlines.

Return type:

streamlines

draw(c=None, cmap=None, colorbar_label=None, show=True, show_kwargs=None, draw_streamlines=True, recalculate_streamlines=False, backend='pyvista')[source]#

Draws the solution. Note: Must be called on a SOLVED AeroProblem object. To solve an AeroProblem, use opti.solve(). To substitute a solved solution, use ap = sol(ap). :return:

Parameters:
  • c (aerosandbox.geometry.np.ndarray) –

  • cmap (str) –

  • colorbar_label (str) –

  • show (bool) –

  • show_kwargs (Dict) –

  • backend (str) –

class aerosandbox.NonlinearLiftingLine(airplane, op_point, xyz_ref=None, run_symmetric_if_possible=False, verbose=False, spanwise_resolution=8, spanwise_spacing_function=np.cosspace, vortex_core_radius=1e-08, align_trailing_vortices_with_wind=False)[source]#

Bases: aerosandbox.ImplicitAnalysis

An implicit aerodynamics analysis based on lifting line theory, with modifications for nonzero sweep and dihedral + multiple wings.

Nonlinear, and includes viscous effects based on 2D data.

Usage example:
>>> analysis = asb.NonlinearLiftingLine(
>>>     airplane=my_airplane,
>>>     op_point=asb.OperatingPoint(
>>>         velocity=100, # m/s
>>>         alpha=5, # deg
>>>         beta=4, # deg
>>>         p=0.01, # rad/sec
>>>         q=0.02, # rad/sec
>>>         r=0.03, # rad/sec
>>>     )
>>> )
>>> outputs = analysis.run()
Parameters:
  • airplane (aerosandbox.geometry.Airplane) –

  • op_point (aerosandbox.performance.OperatingPoint) –

  • xyz_ref (List[float]) –

  • run_symmetric_if_possible (bool) –

  • verbose (bool) –

  • spanwise_spacing_function (Callable[[float, float, float], aerosandbox.numpy.ndarray]) –

  • vortex_core_radius (float) –

  • align_trailing_vortices_with_wind (bool) –

__repr__()[source]#

Return repr(self).

run(solve=True)[source]#

Computes the aerodynamic forces.

Returns a dictionary with keys:
  • ‘residuals’: a list of residuals for each horseshoe element

  • ‘F_g’ : an [x, y, z] list of forces in geometry axes [N]

  • ‘F_b’ : an [x, y, z] list of forces in body axes [N]

  • ‘F_w’ : an [x, y, z] list of forces in wind axes [N]

  • ‘M_g’ : an [x, y, z] list of moments about geometry axes [Nm]

  • ‘M_b’ : an [x, y, z] list of moments about body axes [Nm]

  • ‘M_w’ : an [x, y, z] list of moments about wind axes [Nm]

  • ‘L’ : the lift force [N]. Definitionally, this is in wind axes.

  • ‘Y’ : the side force [N]. This is in wind axes.

  • ‘D’ : the drag force [N]. Definitionally, this is in wind axes.

  • ‘l_b’, the rolling moment, in body axes [Nm]. Positive is roll-right.

  • ‘m_b’, the pitching moment, in body axes [Nm]. Positive is pitch-up.

  • ‘n_b’, the yawing moment, in body axes [Nm]. Positive is nose-right.

  • ‘CL’, the lift coefficient [-]. Definitionally, this is in wind axes.

  • ‘CY’, the sideforce coefficient [-]. This is in wind axes.

  • ‘CD’, the drag coefficient [-]. Definitionally, this is in wind axes.

  • ‘CDi’ the induced drag coefficient

  • ‘CDp’ the profile drag coefficient

  • ‘Cl’, the rolling coefficient [-], in body axes

  • ‘Cm’, the pitching coefficient [-], in body axes

  • ‘Cn’, the yawing coefficient [-], in body axes

Nondimensional values are nondimensionalized using reference values in the VortexLatticeMethod.airplane object.

Parameters:

solve (bool) –

Return type:

Dict[str, Any]

get_induced_velocity_at_points(points, vortex_strengths=None)[source]#

Computes the induced velocity at a set of points in the flowfield.

Parameters:
  • points (aerosandbox.numpy.ndarray) – A Nx3 array of points that you would like to know the induced velocities at. Given in geometry axes.

  • vortex_strengths (aerosandbox.numpy.ndarray) –

Return type:

aerosandbox.numpy.ndarray

Returns: A Nx3 of the induced velocity at those points. Given in geometry axes.

get_velocity_at_points(points, vortex_strengths=None)[source]#

Computes the velocity at a set of points in the flowfield.

Parameters:
  • points (aerosandbox.numpy.ndarray) – A Nx3 array of points that you would like to know the velocities at. Given in geometry axes.

  • vortex_strengths (aerosandbox.numpy.ndarray) –

Return type:

aerosandbox.numpy.ndarray

Returns: A Nx3 of the velocity at those points. Given in geometry axes.

calculate_fuselage_influences(points)[source]#
Parameters:

points (aerosandbox.numpy.ndarray) –

Return type:

aerosandbox.numpy.ndarray

calculate_streamlines(seed_points=None, n_steps=300, length=None)[source]#

Computes streamlines, starting at specific seed points.

After running this function, a new instance variable VortexLatticeFilaments.streamlines is computed

Uses simple forward-Euler integration with a fixed spatial stepsize (i.e., velocity vectors are normalized before ODE integration). After investigation, it’s not worth doing fancier ODE integration methods (adaptive schemes, RK substepping, etc.), due to the near-singular conditions near vortex filaments.

Parameters:
  • seed_points (aerosandbox.numpy.ndarray) – A Nx3 ndarray that contains a list of points where streamlines are started. Will be

  • specified. (not) –

  • n_steps (int) – The number of individual streamline steps to trace. Minimum of 2.

  • length (float) – The approximate total length of the streamlines desired, in meters. Will be auto-calculated if

  • specified.

Returns:

a 3D array with dimensions: (n_seed_points) x (3) x (n_steps). Consists of streamlines data.

Result is also saved as an instance variable, VortexLatticeMethod.streamlines.

Return type:

streamlines

draw(c=None, cmap=None, colorbar_label=None, show=True, show_kwargs=None, draw_streamlines=True, recalculate_streamlines=False, backend='pyvista')[source]#

Draws the solution. Note: Must be called on a SOLVED AeroProblem object. To solve an AeroProblem, use opti.solve(). To substitute a solved solution, use ap = sol(ap). :return:

Parameters:
  • c (aerosandbox.numpy.ndarray) –

  • cmap (str) –

  • colorbar_label (str) –

  • show (bool) –

  • show_kwargs (Dict) –

  • backend (str) –

class aerosandbox.AeroBuildup(airplane, op_point, xyz_ref=None, model_size='small', include_wave_drag=True)[source]#

Bases: aerosandbox.ExplicitAnalysis

A workbook-style aerodynamics buildup.

Example usage:

>>> import aerosandbox as asb
>>> ab = asb.AeroBuildup(  # This sets up the analysis, but doesn't execute calculation
>>>     airplane=my_airplane,  # type: asb.Airplane
>>>     op_point=my_operating_point,  # type: asb.OperatingPoint
>>>     xyz_ref=[0.1, 0.2, 0.3],  # Moment reference and center of rotation.
>>> )
>>> aero = ab.run()  # This executes the actual aero analysis.
>>> aero_with_stability_derivs = ab.run_with_stability_derivatives()  # Same, but also gets stability derivatives.
Parameters:
class AeroComponentResults#
property F_b: List[float | aerosandbox.aerodynamics.aero_3D.aero_buildup_submodels.fuselage_aerodynamics_utilities.np.ndarray]#

An [x, y, z] list of forces in body axes [N]

Return type:

List[Union[float, aerosandbox.aerodynamics.aero_3D.aero_buildup_submodels.fuselage_aerodynamics_utilities.np.ndarray]]

property F_w: List[float | aerosandbox.aerodynamics.aero_3D.aero_buildup_submodels.fuselage_aerodynamics_utilities.np.ndarray]#

An [x, y, z] list of forces in wind axes [N]

Return type:

List[Union[float, aerosandbox.aerodynamics.aero_3D.aero_buildup_submodels.fuselage_aerodynamics_utilities.np.ndarray]]

property M_b: List[float | aerosandbox.aerodynamics.aero_3D.aero_buildup_submodels.fuselage_aerodynamics_utilities.np.ndarray]#

An [x, y, z] list of moments about body axes [Nm]

Return type:

List[Union[float, aerosandbox.aerodynamics.aero_3D.aero_buildup_submodels.fuselage_aerodynamics_utilities.np.ndarray]]

property M_w: List[float | aerosandbox.aerodynamics.aero_3D.aero_buildup_submodels.fuselage_aerodynamics_utilities.np.ndarray]#

An [x, y, z] list of moments about wind axes [Nm]

Return type:

List[Union[float, aerosandbox.aerodynamics.aero_3D.aero_buildup_submodels.fuselage_aerodynamics_utilities.np.ndarray]]

property L: float | aerosandbox.aerodynamics.aero_3D.aero_buildup_submodels.fuselage_aerodynamics_utilities.np.ndarray#

The lift force [N]. Definitionally, this is in wind axes.

Return type:

Union[float, aerosandbox.aerodynamics.aero_3D.aero_buildup_submodels.fuselage_aerodynamics_utilities.np.ndarray]

property Y: float | aerosandbox.aerodynamics.aero_3D.aero_buildup_submodels.fuselage_aerodynamics_utilities.np.ndarray#

The side force [N]. Definitionally, this is in wind axes.

Return type:

Union[float, aerosandbox.aerodynamics.aero_3D.aero_buildup_submodels.fuselage_aerodynamics_utilities.np.ndarray]

property D: float | aerosandbox.aerodynamics.aero_3D.aero_buildup_submodels.fuselage_aerodynamics_utilities.np.ndarray#

The drag force [N]. Definitionally, this is in wind axes.

Return type:

Union[float, aerosandbox.aerodynamics.aero_3D.aero_buildup_submodels.fuselage_aerodynamics_utilities.np.ndarray]

property l_b: float | aerosandbox.aerodynamics.aero_3D.aero_buildup_submodels.fuselage_aerodynamics_utilities.np.ndarray#

The rolling moment [Nm] in body axes. Positive is roll-right.

Return type:

Union[float, aerosandbox.aerodynamics.aero_3D.aero_buildup_submodels.fuselage_aerodynamics_utilities.np.ndarray]

property m_b: float | aerosandbox.aerodynamics.aero_3D.aero_buildup_submodels.fuselage_aerodynamics_utilities.np.ndarray#

The pitching moment [Nm] in body axes. Positive is nose-up.

Return type:

Union[float, aerosandbox.aerodynamics.aero_3D.aero_buildup_submodels.fuselage_aerodynamics_utilities.np.ndarray]

property n_b: float | aerosandbox.aerodynamics.aero_3D.aero_buildup_submodels.fuselage_aerodynamics_utilities.np.ndarray#

The yawing moment [Nm] in body axes. Positive is nose-right.

Return type:

Union[float, aerosandbox.aerodynamics.aero_3D.aero_buildup_submodels.fuselage_aerodynamics_utilities.np.ndarray]

s_ref: float#
c_ref: float#
b_ref: float#
op_point: aerosandbox.performance.OperatingPoint#
F_g: List[float | aerosandbox.aerodynamics.aero_3D.aero_buildup_submodels.fuselage_aerodynamics_utilities.np.ndarray]#
M_g: List[float | aerosandbox.aerodynamics.aero_3D.aero_buildup_submodels.fuselage_aerodynamics_utilities.np.ndarray]#
span_effective: float#
oswalds_efficiency: float#
__repr__()#

Return repr(self).

default_analysis_specific_options#
__repr__()[source]#

Return repr(self).

run()[source]#

Computes the aerodynamic forces and moments on the airplane.

Returns: a dictionary with keys:

  • ‘F_g’ : an [x, y, z] list of forces in geometry axes [N]

  • ‘F_b’ : an [x, y, z] list of forces in body axes [N]

  • ‘F_w’ : an [x, y, z] list of forces in wind axes [N]

  • ‘M_g’ : an [x, y, z] list of moments about geometry axes [Nm]

  • ‘M_b’ : an [x, y, z] list of moments about body axes [Nm]

  • ‘M_w’ : an [x, y, z] list of moments about wind axes [Nm]

  • ‘L’ : the lift force [N]. Definitionally, this is in wind axes.

  • ‘Y’ : the side force [N]. This is in wind axes.

  • ‘D’ : the drag force [N]. Definitionally, this is in wind axes.

  • ‘l_b’, the rolling moment, in body axes [Nm]. Positive is roll-right.

  • ‘m_b’, the pitching moment, in body axes [Nm]. Positive is pitch-up.

  • ‘n_b’, the yawing moment, in body axes [Nm]. Positive is nose-right.

  • ‘CL’, the lift coefficient [-]. Definitionally, this is in wind axes.

  • ‘CY’, the sideforce coefficient [-]. This is in wind axes.

  • ‘CD’, the drag coefficient [-]. Definitionally, this is in wind axes.

  • ‘Cl’, the rolling coefficient [-], in body axes

  • ‘Cm’, the pitching coefficient [-], in body axes

  • ‘Cn’, the yawing coefficient [-], in body axes

Nondimensional values are nondimensionalized using reference values in the AeroBuildup.airplane object.

Data types:
  • The “L”, “Y”, “D”, “l_b”, “m_b”, “n_b”, “CL”, “CY”, “CD”, “Cl”, “Cm”, and “Cn” keys are:

    • floats if the OperatingPoint object is not vectorized (i.e., if all attributes of OperatingPoint

    are floats, not arrays).

    • arrays if the OperatingPoint object is vectorized (i.e., if any attribute of OperatingPoint is an

    array).

  • The “F_g”, “F_b”, “F_w”, “M_g”, “M_b”, and “M_w” keys are always lists, which will contain either

floats or arrays, again depending on whether the OperatingPoint object is vectorized or not.

Return type:

Dict[str, Union[Union[float, aerosandbox.aerodynamics.aero_3D.aero_buildup_submodels.fuselage_aerodynamics_utilities.np.ndarray], List[Union[float, aerosandbox.aerodynamics.aero_3D.aero_buildup_submodels.fuselage_aerodynamics_utilities.np.ndarray]]]]

run_with_stability_derivatives(alpha=True, beta=True, p=True, q=True, r=True)[source]#

Computes the aerodynamic forces and moments on the airplane, and the stability derivatives.

Arguments essentially determine which stability derivatives are computed. If a stability derivative is not needed, leaving it False will speed up the computation.

Parameters:
  • alpha (-) – If True, compute the stability derivatives with respect to the angle of attack (alpha).

  • beta (-) – If True, compute the stability derivatives with respect to the sideslip angle (beta).

  • p (-) – If True, compute the stability derivatives with respect to the body-axis roll rate (p).

  • q (-) – If True, compute the stability derivatives with respect to the body-axis pitch rate (q).

  • r (-) – If True, compute the stability derivatives with respect to the body-axis yaw rate (r).

Return type:

Dict[str, Union[Union[float, aerosandbox.aerodynamics.aero_3D.aero_buildup_submodels.fuselage_aerodynamics_utilities.np.ndarray], List[Union[float, aerosandbox.aerodynamics.aero_3D.aero_buildup_submodels.fuselage_aerodynamics_utilities.np.ndarray]]]]

Returns: a dictionary with keys:

  • ‘F_g’ : an [x, y, z] list of forces in geometry axes [N]

  • ‘F_b’ : an [x, y, z] list of forces in body axes [N]

  • ‘F_w’ : an [x, y, z] list of forces in wind axes [N]

  • ‘M_g’ : an [x, y, z] list of moments about geometry axes [Nm]

  • ‘M_b’ : an [x, y, z] list of moments about body axes [Nm]

  • ‘M_w’ : an [x, y, z] list of moments about wind axes [Nm]

  • ‘L’ : the lift force [N]. Definitionally, this is in wind axes.

  • ‘Y’ : the side force [N]. This is in wind axes.

  • ‘D’ : the drag force [N]. Definitionally, this is in wind axes.

  • ‘l_b’ : the rolling moment, in body axes [Nm]. Positive is roll-right.

  • ‘m_b’ : the pitching moment, in body axes [Nm]. Positive is pitch-up.

  • ‘n_b’ : the yawing moment, in body axes [Nm]. Positive is nose-right.

  • ‘CL’ : the lift coefficient [-]. Definitionally, this is in wind axes.

  • ‘CY’ : the sideforce coefficient [-]. This is in wind axes.

  • ‘CD’ : the drag coefficient [-]. Definitionally, this is in wind axes.

  • ‘Cl’ : the rolling coefficient [-], in body axes

  • ‘Cm’ : the pitching coefficient [-], in body axes

  • ‘Cn’ : the yawing coefficient [-], in body axes

Along with additional keys, depending on the value of the alpha, beta, p, q, and r arguments. For example, if alpha=True, then the following additional keys will be present:

  • ‘CLa’ : the lift coefficient derivative with respect to alpha [1/rad]

  • ‘CDa’ : the drag coefficient derivative with respect to alpha [1/rad]

  • ‘CYa’ : the sideforce coefficient derivative with respect to alpha [1/rad]

  • ‘Cla’ : the rolling moment coefficient derivative with respect to alpha [1/rad]

  • ‘Cma’ : the pitching moment coefficient derivative with respect to alpha [1/rad]

  • ‘Cna’ : the yawing moment coefficient derivative with respect to alpha [1/rad]

  • ‘x_np’: the neutral point location in the x direction [m]

Nondimensional values are nondimensionalized using reference values in the AeroBuildup.airplane object.

Data types:
  • The “L”, “Y”, “D”, “l_b”, “m_b”, “n_b”, “CL”, “CY”, “CD”, “Cl”, “Cm”, and “Cn” keys are:

    • floats if the OperatingPoint object is not vectorized (i.e., if all attributes of OperatingPoint

    are floats, not arrays).

    • arrays if the OperatingPoint object is vectorized (i.e., if any attribute of OperatingPoint is an

    array).

  • The “F_g”, “F_b”, “F_w”, “M_g”, “M_b”, and “M_w” keys are always lists, which will contain either

floats or arrays, again depending on whether the OperatingPoint object is vectorized or not.

wing_aerodynamics(wing, include_induced_drag=True)[source]#

Estimates the aerodynamic forces, moments, and derivatives on a wing in isolation.

Moments are given with the reference at Wing [0, 0, 0].

Parameters:
  • wing (aerosandbox.geometry.Wing) – A Wing object that you wish to analyze.

  • op_point – The OperatingPoint that you wish to analyze the fuselage at.

  • include_induced_drag (bool) –

Return type:

AeroComponentResults

Returns:

fuselage_aerodynamics(fuselage, include_induced_drag=True)[source]#

Estimates the aerodynamic forces, moments, and derivatives on a fuselage in isolation.

Assumes:
  • The fuselage is a body of revolution aligned with the x_b axis.

  • The angle between the nose and the freestream is less than 90 degrees.

Moments are given with the reference at Fuselage [0, 0, 0].

Uses methods from Jorgensen, Leland Howard. “Prediction of Static Aerodynamic Characteristics for Slender Bodies Alone and with Lifting Surfaces to Very High Angles of Attack”. NASA TR R-474. 1977.

Parameters:
Return type:

AeroComponentResults

Returns:

class aerosandbox.AVL(airplane, op_point, xyz_ref=None, avl_command='avl', verbose=False, timeout=5, working_directory=None, ground_effect=False, ground_effect_height=0)[source]#

Bases: aerosandbox.common.ExplicitAnalysis

An interface to AVL, a 3D vortex lattice aerodynamics code developed by Mark Drela at MIT.

Requires AVL to be on your computer; AVL is available here: https://web.mit.edu/drela/Public/web/avl/

It is recommended (but not required) that you add AVL to your system PATH environment variable such that it can be called with the command avl. If this is not the case, you need to specify the path to your AVL executable using the avl_command argument of the constructor.

Usage example:

>>> avl = asb.AVL(
>>>     airplane=my_airplane,
>>>     op_point=asb.OperatingPoint(
>>>         velocity=100, # m/s
>>>         alpha=5, # deg
>>>         beta=4, # deg
>>>         p=0.01, # rad/sec
>>>         q=0.02, # rad/sec
>>>         r=0.03, # rad/sec
>>>     )
>>> )
>>> outputs = avl.run()
Parameters:
default_analysis_specific_options#
AVL_spacing_parameters#
__repr__()[source]#

Return repr(self).

open_interactive()[source]#

Opens a new terminal window and runs AVL interactively. This is useful for detailed analysis or debugging.

Returns: None

Return type:

None

run(run_command=None)[source]#

Private function to run AVL.

Args: run_command: A string with any AVL keystroke inputs that you’d like. By default, you start off within the OPER menu. All of the inputs indicated in the constructor have been set already, but you can override them here ( for this run only) if you want.

Returns: A dictionary containing all of your results.

Parameters:

run_command (str) –

Return type:

Dict[str, float]

_default_keystroke_file_contents()[source]#
Return type:

List[str]

write_avl(filepath=None)[source]#

Writes a .avl file corresponding to this airplane to a filepath.

For use with the AVL vortex-lattice-method aerodynamics analysis tool by Mark Drela at MIT. AVL is available here: https://web.mit.edu/drela/Public/web/avl/

Parameters:

filepath (Union[pathlib.Path, str]) – filepath (including the filename and .avl extension) [string] If None, this function returns the .avl file as a string.

Return type:

None

Returns: None

static write_avl_bfile(fuselage, filepath=None, include_name=True)[source]#

Writes an AVL-compatible BFILE corresponding to this fuselage to a filepath.

For use with the AVL vortex-lattice-method aerodynamics analysis tool by Mark Drela at MIT. AVL is available here: https://web.mit.edu/drela/Public/web/avl/

Parameters:
  • filepath (Union[pathlib.Path, str]) – filepath (including the filename and .avl extension) [string] If None, this function returns the would-be file contents as a string.

  • include_name (bool) – Should the name of the fuselage be included in the .dat file? (This should be True for use with AVL.)

Return type:

str

Returns:

static parse_unformatted_data_output(s, data_identifier=' = ', cast_outputs_to_float=True, overwrite=None)[source]#

Parses a (multiline) string of unformatted data into a nice and tidy dictionary.

The expected input string looks like what you might get as an output from AVL (or many other Drela codes), which may list data in ragged order.

An example input s that you might want to parse could look like the following:

```

Standard axis orientation, X fwd, Z down

Run case: -unnamed-

Alpha = 0.43348 pb/2V = -0.00000 p’b/2V = -0.00000 Beta = 0.00000 qc/2V = 0.00000 Mach = 0.003 rb/2V = -0.00000 r’b/2V = -0.00000

CXtot = -0.02147 Cltot = 0.00000 Cl’tot = 0.00000 CYtot = 0.00000 Cmtot = 0.28149 CZtot = -1.01474 Cntot = -0.00000 Cn’tot = -0.00000

CLtot = 1.01454 CDtot = 0.02915 CDvis = 0.00000 CDind = 0.0291513 CLff = 1.00050 CDff = 0.0297201 | Trefftz CYff = 0.00000 e = 0.9649 | Plane

```

Here, this function will go through this string and extract each key-value pair, as denoted by the data identifier (by default, “ = “). It will pull the next whole word without spaces to the left as the key, and it will pull the next whole word without spaces to the right as the value. Together, these will be returned as a Dict.

So, the output for the input above would be: {

‘Alpha’ : 0.43348, ‘pb/2V’ : -0.00000, ‘p’b/2V’ : -0.00000, ‘Beta’ : 0.00000, # and so on…

}

Parameters:
  • s (str) – The input string to identify. Can be multiline.

  • data_identifier (str) – The triggering substring for a new key-value pair. By default, it’s “ = “,

  • this (which is convention in many output files from Mark Drela's codes. Be careful if you decide to change) –

  • "=" (to) –

  • separators (as you could pick up on heading) –

  • cast_outputs_to_float (bool) – If this boolean flag is set true, the values of the key-value pairs are cast to

  • returning (floating-point numbers before) –

  • cast

  • downstream (a NaN is returned (guaranteeing that you can do floating-point math with the outputs in) –

  • applications.)

  • overwrite (bool) –

    Determines the behavior if you find a key that’s already in the dictionary.

    • By default, value is None. In this case, an error is raised.

    • If you set it to True, the new value will overwrite the old one. Thus, your dictionary will have

    the last matching value from the string.

    • If you set it to False, the new value will be discarded. Thus, your dictionary will have the first

    matching value from the string.

Return type:

Dict[str, float]

Returns: A dictionary of key-value pairs, corresponding to the unformatted data in the input string.

Keys are strings, values are floats if cast_outputs_to_float is True, otherwise also strings.

aerosandbox.__version__ = '4.2.4'[source]#
aerosandbox.docs()[source]#

Opens the AeroSandbox documentation.

aerosandbox.run_tests()[source]#

Runs all of the AeroSandbox internal unit tests on this computer.