Defining a Custom Variable Hierarchy#

Aviary comes with a relatively robust variable hierarchy that defines a large number of aircraft, mission, and other parameters. However, this is not an exhaustive list and when integrating external subsystems with Aviary it is common to need new variables. This is done by creating a new variable hierarchy that defines these new variables and their associated metadata.

Custom hierarchies can be added to an Aviary model in two primary ways. Either a “complete” hierarchy containing all variables needed by core Aviary as well as the new external subsystems is provided when setting up your AviaryProblem, or you define a “partial” hierarchy just defining the new variables in your SubsystemBuilder for the new subsystem. In the first case, Aviary will simply use your new hierarchy instead of the core one, and in the second case Aviary will attempt to merge the hierarchies provided by each external subsystem into the core hierarchy.

This page will explain the requirements for defining a new variable hierarchy, and walk through some of the helper functions Aviary contains for managing variable hierarchies.

Conventions and Requirements of the Variable Hierarchies#

There are some conventions surrounding the variable hierarchy that are required, and other things that are purely convention. Below is a list of the programmatically required aspects of the variable hierarchy:

  • Avoiding periods in the string-valued variable names is a must. Periods that are included here will end up as periods in an OpenMDAO variable name which will throw an error.

  • Including a colon after the first word in the string-valued variable name is also a must. The expressions promotes=["aircraft:*"] and promotes=["mission:*"] appear frequently within Aviary, and if these colons are not included variables will not get properly connected, leading to hard-to-detect errors.

Conversely, other things are merely convention that the Aviary team follows. Below is a list of the conventions that are not programmatically required:

  • Inner classes and variables are all organized alphabetically within a hierarchy. This is optional, but we follow this convention within the Aviary-core variable hierarchy to preserve cleanliness.

  • All variables in the hierarchy have a depth of 3. This is optional, but again we follow this convention within the Aviary-core variable hierarchy to preserve cleanliness and uniformity of code.

  • Including colons after all words in the string-valued variable name is optional. As stated above, it is a must after the first word for use in promotion statements, but after that it is purely a choice of convention to preserve clarity.

It is prudent at this point to pause and explain what is meant by hierarchy type. This is not a technical coding in term, instead type is an explanatory term that we use to describe the classification of a hierarchy. A hierarchy’s type is its high level category. For example, a hierarchy of the Aircraft type would be a hierarchy that houses the variables that have to do with the physical aspects of an aircraft, and a hierarchy of the Mission type would be a hierarchy that houses the variables which reference the mission or change in time. These are the only two types of hierarchies that are provided in Aviary-core, however, other types are possible, such as a Fleet type hierarchy describing the variables that affect an entire fleet of aircraft, an AirTrafficControl type hierarchy describing all the variables having to do with air traffic control, etc. The concept of the Aircraft and Mission type hierarchies will be used throughout the rest of this article.

Building Your Own Hierarchy#

The Aviary-core provides the pre-built variable hierarchies listed above. However, for the user that would like to add external subsystems to Aviary, the variables in the Aviary-core hierarchies may not be sufficient. In this case, there are three options:

  1. extend the existing variable hierarchies from Aviary-core

  2. create your own variable hierarchies and merge them with the existing hierarchies from Aviary-core

  3. do a combination of #1 and #2. Extending and creating your own variable hierarchies are addressed below.

Extend the Existing Aviary-core Hierarchies#

If you are just adding one external subsystem to an Aviary-core model, or if you are adding multiple subsystems all being developed in the same location by the same person, our suggested path is to create one extension of the Aviary-core hierarchies. The method to extend the Aviary-core variable hierarchies is to subclass those hierarchies (which preserves all the data from the original hierarchies) and add your own additional variables as necessary. To take a simple example, let’s say we wanted to add a little bit of detail to the existing Aircraft variable hierarchy for our external subsystem. The detail we would like to add is some information about the flaps on the wing as well as a jury strut and a center of gravity location. We would extend the existing variable hierarchy using the following code:

import aviary.api as av

AviaryAircraft = av.Aircraft


class Aircraft(AviaryAircraft):
    CG = 'aircraft:center_of_gravity'

    class Wing(AviaryAircraft.Wing):
        class Flap:
            AREA = 'aircraft:wing:flap:area'
            ROOT_CHORD = 'aircraft:wing:flap:root_chord'
            SPAN = 'aircraft:wing:flap:span'

    class Jury:
        MASS = 'aircraft:jury:mass'

There are a few things to notice about this code. The first is that, unlike the Aviary-core Aircraft variable hierarchy, this hierarchy has variables with a depth of two and a depth of four. When we extend the Aviary-core variable hierarchies we are not restricted to the depth of three that the core hierarchies have. The second thing to notice is that when we extend an inner class that already exists in the Aviary-core hierarchy (Wing) we subclass the inner class from the Aviary-core so that we can preserve all the information from that Aviary-core inner class. However, in the case of the inner class Jury which does not already exist in the Aviary-core hierarchy, there is nothing to subclass, and thus that inner class stands on its own.

When extending the Aviary-core variable hierarchies, you can create one extension of each type of hierarchy, or you can create multiple extensions of each type which will eventually be merged together. If you are developing only one external subsystem or all your subsystems are being developed in the same place by the same person, one extension of each Aviary-core hierarchy should suffice. However, if you have multiple developers working on different subsystems in different locations, each developer may want to create their own extension. To aid in this case, Aviary provides the capability to merge together multiple hierarchies of the same type into one hierarchy of that type. More information on this capability is shown at the bottom of this page.

Creating Your Own Variable Hierarchy#

It is possible to create your own variable hierarchy that is not an extension of the Aviary-core variable hierarchies, but there are specific things to know. The use case for this is mostly when you would like to create a third hierarchy that does not fall under either the Aircraft or the Mission categories. An example of this might be if you are doing fleet-level analyses and would like a Fleet variable hierarchy.

A new variable hierarchy can be created in exactly the same manner that Aviary-core creates its own variable hierarchies, illustrated above. For the case of creating a new Fleet variable hierarchy, it might look something like this:

class Fleet:
    class RegionalSingleAisle:
        NUM_AIRCRAFT = 'fleet:rejoinal_single_aisle:number_of_aircraft'
        COST_PER_AIRCRAFT = 'fleet:rejoinal_single_aisle:cost_per_aircraft'
        FLIGHTS_PER_DAY = 'fleet:rejoinal_single_aisle:flights_per_day'

    class JumboJet:
        NUM_AIRCRAFT = 'fleet:jumbo_jet:number_of_aircraft'
        COST_PER_AIRCRAFT = 'fleet:jumbo_jet:cost_per_aircraft'
        FLIGHTS_PER_DAY = 'fleet:jumbo_jet:flights_per_day'

Usually if you are creating your own variable hierarchy that is not an extension of the Aviary-core hierarchies it will be because you want a hierarchy that is not of the type Aircraft or Mission. In this case, your new hierarchy is relatively straightforward, you can create it and simply provide it to Aviary along with the core hierarchies or extensions thereof. However, if you are creating your own variable hierarchy that is of the type Aircraft or Mission but is not an extension of the Aviary-core hierarchies (which we do not recommend doing), there are a few things to keep in mind:

  • The newly created variable hierarchy does not have any of the information from the Aviary-core hierarchy. You must still provide Aviary with the input values and information from the Aviary-core hierarchy, or all the inputs will be set to their default values which are unlikely to suit your needs.

    • You can merge together all variable hierarchies that are of the same type (see below).

  • You should avoid adding variables to your created hierarchy that already exist in the Aviary-core hierarchy, as this may cause conflicts when merging hierarchies together.

In general, we recommend extending the Aviary-core variable hierarchies whenever possible, and only creating a new hierarchy from scratch when the categories of Aircraft and Mission do not fit your needs.

Merging Extended Hierarchies#

As briefly mentioned above, when there are multiple variable hierarchies of the same type we need the ability to merge them together into one hierarchy of that type which includes all the information from the different hierarchies. Aviary provides this capability through the merge_hierarchies() method. The goal of this method is to clean up all the user hierarchies so that Aviary can be provided with only one hierarchy of each type, and also to resolve any discrepancies between different hierarchies of the same type.

Using the merge_hierarchies() function is quite simple. It takes a list of all the hierarchies you would like to merge together and returns one hierarchy that has the merged information from all the input hierarchies, as in this snippet of code where we are merging together three notional Aircraft type hierarchies:

import aviary.api as av

FullAircraft = av.merge_hierarchies([Aircraft1, Aircraft2, Aircraft3])

When merging together variable hierarchies, make sure that all the hierarchies are of the same type. The merge_hierarchies() will throw an error if you attempt to merge multiple hierarchies subclassed from hierarchies of different types. Also ensure that the hierarchies you are merging don’t contain the same variable with a different value. That is an impossible situation to merge, and will raise an error. Also ensure that when merging hierarchies of the Aircraft or Mission type the variable information from the Aviary-core hierarchies is present in your final merged hierarchies. This is handled automatically if you have built your hierarchies by extending the Aviary-core hierarchies (which is the recommended behavior), but if you have instead made your hierarchies from scratch then you will have to include the Aviary-core hierarchy of the same type in the hierarchies to be merged.

Note

If even one of the hierarchies to be merged is an extension of the Aviary-core hierarchy of that type, then the Aviary core information will be included. You only need to include the Aviary-core hierarchy of that type in the list of hierarchies to merge if none of the other hierarchies are extensions.

More syntactical data on the merging functions can be found here.

Providing Aviary with Necessary Variable Hierarchies#

Need to add content here.