Propulsion#

The propulsion subsystem in Aviary organizes and executes models for engine sizing and performance.

Aviary does not natively model gas-turbine performance, and instead relies on user-provided data and/or custom performance models to perform propulsion analysis.

Aviary supports an arbitrary number of propulsor models on a vehicle, each with their own unique properties such as performance characteristics, scaling behaviors, and number of propulsors for that given type.

Note

In Aviary, when we refer to multiple engines of the same type, we say they are homogenous. When you are dealing with multiple engines of different types, we say they are heterogeneous.

Each unique type of engine is defined by a engine model. In Aviary, an engine model contains information on how to size and estimate performance for a single instance of an engine of that type. During analysis, Aviary handles summing performance data to a system level. This way, information is available on the performance of both a single instance of an engine, as well as aircraft-level totals, for other Aviary subsystems to utilize.

Aviary’s variable hierarchy makes a distinction between variables that apply to a single instance of an engine, under the Aircraft.Engine sub-category, and variables that apply to the propulsion system as a whole under Aircraft.Propulsion. As an example, imagine an aircraft with a heterogeneous set of engines (those with unique properties). Maximum sea-level-static thrust would be defined differently per engine vs propulsion system like so:

aircraft:engine:scaled_sls_thrust = [1500, 2200], lbf

aircraft:engine:num_engines = [3, 2], unitless

aircraft:propulsion:total_scaled_sls_thrust = 8900, lbf

As you can see, variables under engine are vectors that store a value for a single each instance of a single type of engine, while variables under propulsion only store a single value that is relevant to the entire aircraft rather than any one specific engine or set of engines. Put another way, this aircraft has two hereogenous types of engines, the first that produces 1,500 lbf of thrust per engine, with three of those engines on the aircraft, and the second engine that produces 2,200 lbf of thrust per engine with only two copies of that engine on the aircraft. The propulsion-level total is 8,900 lbf of thrust, which is every engine physically present on the aircraft combined together (1500*3 + 2200*2).

In general, the user does not need to define propulsion variables, as Aviary can calculate them given values in engine, but they are important to understand when reading results.

In this section, we will explain how to set up the propulsion systems of an Aviary model, focusing on relatively straightforward aircraft configurations.

Engine Decks#

The primary way Aviary handles engine performance is by interpolating tabular data from a user-defined file that describes performance characteristics for a given engine. Engines modeled in this manner are called engine decks. Engine decks are a type of engine model - they use the same basic interface, but have additional functionality to handle reading and processing data files.

Engine decks can contain a variety of different data to represent any number of propulsion systems, typically ones that utilize combustion such as turbofan or turboshaft engines, including hybridized ones. The most common application of an engine deck is to represent a turbofan engine, essentially as black box model that describes the relationship between energy consuption (in the form of fuel) into useful work (the production of thrust).

More advanced applications of engine decks are as parts of larger, more detailed engine models, such as a turboprop. A turboprop model, as described later, connects a turboshaft engine deck with a gearbox and propeller model to bridge the gap between energy consumption and thrust production, packaged together into a single model that treated as a singular unit by the greater propulsion system.

Formatting#

An engine deck data file requires specific formatting for Aviary to correctly interpret. These files must follow the Aviary data file format. An example of a properly-formatted engine deck can be found here.

Variables#

The following engine performance parameters are supported natively by Aviary for use in engine decks. If units are not specified, the default units are assumed. A variety of alternate names for these variables are understood by Aviary, but it is recommended to use the official names given here. A column with a header not recognized by Aviary will be ignored, with a warning raised at runtime. This allows for variables not used by Aviary to still be included in a data file, either for reference or compatibility with another analysis tool.

Variable

Default Units

Required?

Mach Number

unitless

Altitude

ft

Throttle

unitless

Hybrid Throttle

unitless

Net Thrust

lbf

✔*

Gross Thrust

lbf

✘*

Ram Drag

lbf

✘*

Shaft Power

hp

RPM

rpm

Fuel Flow Rate

lbm/h

Electric Power

kW

NOx Rate

lbm/h

T4 Temperature

degR

*Net Thrust (defined as Gross Thrust - Ram Drag) is not required if both of those variables are provided for calculation

Mach Number, Altitude, and the two throttle parameters are independent variables required to describe the operating conditions of the engine. Hybrid Throttle is optional, and is intended for use as a second degree of control for engines using independently controllable fuel- and electric-based power. The remaining variables are dependent on the operating conditions and are therefore typically optional.

Engine decks without headers are assumed to contain only the required variable set, in the order specified by the table (Mach, Altitude, Throttle, and Net Thrust), and with default units.

Comments may be added to an engine deck data file by using a ‘#’ symbol preceding the comment. Anything after this symbol on that line is ignored by Aviary, allowing the user to temporarily remove data points or add in-line comments with context for the data. It is good practice to include comments at the start of the file to explain what kind of engine the data represents, and where it came from.

Setting Up Propulsion Analysis#

Beginner Guide#

To add an engine deck to Aviary, the minimum set of variables to describe it must be provided in your input file. This list includes:

  • Aircraft.Engine.SCALE_PERFORMANCE

  • Aircraft.Engine.IGNORE_NEGATIVE_THRUST

  • Aircraft.Engine.GEOPOTENTIAL_ALT

  • Aircraft.Engine.GENERATE_FLIGHT_IDLE

  • Aircraft.Engine.NUM_WING_ENGINES and/or Aircraft.Engine.NUM_FUSELAGE_ENGINES

If generating flight idle points is desired, the following variables are also required. More information on flight idle generation is available here .

  • Aircraft.Engine.FLIGHT_IDLE_THRUST_FRACTION

  • Aircraft.Engine.FLIGHT_IDLE_MIN_FRACTION

  • Aircraft.Engine.FLIGHT_IDLE_MAX_FRACTION

If you are missing any required variables, you may see a warning at runtime, depending on verbosity level. Aviary will try using the default value for the missing variable, which may affect analysis results.

UserWarning: <aircraft:engine:scale_performance> is a required option for EngineDecks, but has not been specified for EngineDeck <example>. The default value will be used.

Intermediate Guide#

Engine models are defined in Aviary using an EngineModel object. An EngineModel is responsible for handling many tasks required to prepare an engine for use in Aviary, such as reading engine data from a file in the case of an EngineDeck (which is a child class of EngineModel).

An EngineModel (and classes inheriting it) can be manually created and added to the Aviary problem, instead of being created from the values provided via an Aviary input file. This is extremely useful when setting up an aircraft with multiple heterogenous types of engines, each with unique properties, or using a custom engine model. An EngineModel requires an AviaryValues object containing the variables required for that engine (such as those outlined in the Beginner Guide example for EngineDeck).

import aviary.api as av
from aviary.api import Aircraft

aviary_options = av.AviaryValues()

# Add relevant inputs and options to engine_options
# using engine_options.set_val(...)
filename = av.get_path('models/engines/turbofan_28k.deck')
aviary_options.set_val(Aircraft.Engine.DATA_FILE, filename)
# example of setting an engine variable to a specific value
aviary_options.set_val(Aircraft.Engine.SCALE_FACTOR, 0.9)

# It is assumed here that aviary_options is configured to have
# all inputs needed for analysis, except engine-level values.
# Because not all required options were defined in this example, we
# see a number of warnings about the missing variables.
engine_deck = av.EngineDeck(name='example', options=aviary_options)
/home/runner/work/Aviary/Aviary/aviary/subsystems/propulsion/engine_deck.py:234: UserWarning: <aircraft:engine:scale_performance> is a required option for EngineDecks, but has not been specified for EngineDeck <example>. The default value True will be used.
  warnings.warn(
/home/runner/work/Aviary/Aviary/aviary/subsystems/propulsion/engine_deck.py:234: UserWarning: <aircraft:engine:ignore_negative_thrust> is a required option for EngineDecks, but has not been specified for EngineDeck <example>. The default value False will be used.
  warnings.warn(
/home/runner/work/Aviary/Aviary/aviary/subsystems/propulsion/engine_deck.py:234: UserWarning: <aircraft:engine:geopotential_alt> is a required option for EngineDecks, but has not been specified for EngineDeck <example>. The default value False will be used.
  warnings.warn(
/home/runner/work/Aviary/Aviary/aviary/subsystems/propulsion/engine_deck.py:234: UserWarning: <aircraft:engine:generate_flight_idle> is a required option for EngineDecks, but has not been specified for EngineDeck <example>. The default value False will be used.
  warnings.warn(
/home/runner/work/Aviary/Aviary/aviary/subsystems/propulsion/engine_deck.py:234: UserWarning: <aircraft:engine:interpolation_method> is a required option for EngineDecks, but has not been specified for EngineDeck <example>. The default value slinear will be used.
  warnings.warn(
/home/runner/work/Aviary/Aviary/aviary/subsystems/propulsion/engine_deck.py:234: UserWarning: <mission:summary:fuel_flow_scaler> is a required option for EngineDecks, but has not been specified for EngineDeck <example>. The default value 1.0 will be used.
  warnings.warn(

In this example code snippet, we didn’t set a value for every required variable and option previously listed - because of this, we get a number of warnings letting us know which ones we forgot to set, and that the default values specified will be used.

Once an EngineDeck has been successfully created, it must be attached to the vehicle model you want to analyze. The simplest way to do this is to take advantage of the propulsion preprocessor utility. This preprocessor handles all of the details of getting data related to EngineModels, which may change during initialization, correctly set up in the AviaryValues object which is used to define the vehicle at the Aviary problem level. This is a critical step, because once Aviary begins analysis it assumes that all of the relevant data present in individual EngineModels have made their way into the vehicle-level data.

av.preprocess_propulsion(aviary_options=aviary_options, engine_models=[engine_deck])
/home/runner/work/Aviary/Aviary/aviary/utils/preprocessors.py:666: UserWarning: Mount location for single engine of type <example> not specified. Assuming it is fuselage-mounted.
  warnings.warn(

Heterogenous Engine Sets#

In this example, our aircraft model has two distinct types of engines, which are assumed to have different properties. To keep this example simple, we will build an aircraft with two sets of engines based on the EngineDeck we just set up, but one set of engines is scaled to half size using Aircraft.Engine.SCALE_FACTOR.

aviary_options is modified in-place with updated values to represent our new engine_deck. When working with multiple heterogenous engines, simply provide preprocess_propulsion() with a list of all EngineModels, like so:

# Test Cell
aviary_options = av.AviaryValues()
# set this to avoid warning in later cell
aviary_options.set_val(Aircraft.Engine.NUM_WING_ENGINES, 2)
av.preprocess_propulsion(
    aviary_options=aviary_options, engine_models=[engine_deck_1, engine_deck_2]
)
# Testing Cell
print(f'Interpolation Method: {aviary_options.get_val(Aircraft.Engine.SCALE_FACTOR)}')
Interpolation Method: [1.  0.5]

Note how calling preprocess_propulsion() changes Aircraft.Engine.SCALE_FACTOR, which was individually defined for each EngineDeck, into a list containing both values. This way Aviary can access information on every EngineModel present on the aircraft without needing access to each individual EngineModel object. This is important to be aware of if you are manually setting any variables related to engines or propulsion rather than using the built-in methods and functions presented in the Intermediate guide, which will do this work for you.

Advanced Guide#

This section is a work in progress. Please check back later for more information.