Understanding the Variable Metadata#

How Variable Metadata Works#

Every variable in an Aviary variable hierarchy must have metadata associated with it. This metadata is used for setting initial values, setting Aviary inputs and outputs, and various other functionalities throughout the code. It is also helpful information for the user to have regarding each variable and the metadata dictionary allows all that information to live in one organized location. Unlike variable hierarchies, which are broken up into different categories based on the type of information they contain, the variable metadata all lives in the same dictionary, regardless of which variable hierarchy its variables come from.

The variable metadata dictionary is exactly what it sounds like: a Python dictionary, or more explicitly a Python dictionary of dictionaries. The entire metadata is one dictionary, and within that metadata dictionary each variable has its own sub-dictionary including all the information relevant to that variable. The information included in each sub-dictionary is:

Information

Default Value

Key Name in Metadata

Units

unitless

units

Description

None

desc

Default Value

0.0

default_value

Is Option?

False

option

Type Restrictions

None

types

Historical Variable Name(s)

None

historical_name

The information in the metadata dictionary is accessed just like information in any other Python dictionary. For example, if you wanted to know the units of the Aircraft.Wing.SPAN variable from the Aviary-core Aircraft variable hierarchy along with whether or not the variable was an option, you would access those units using the following code:

import aviary.api as av

AviaryAircraft = av.Aircraft

wingspan_units = av.CoreMetaData[AviaryAircraft.Wing.SPAN]['units']
wingspan_is_option = av.CoreMetaData[AviaryAircraft.Wing.SPAN]['option']

print(wingspan_units)
print(wingspan_is_option)

In this example we use the variable hierarchy to provide the name of the variable we are seeking to Aviary’s CoreMetaData, and we use the keys from the metadata dictionary to provide the specific information that we would like to know. This would return

ft
False

which tells you that the units of the variable Aircraft.Wing.SPAN from the Aviary-core Aircraft variable hierarchy are feet, and that Aircraft.Wing.SPAN is not an option.

Note

Many of the weight and aerodynamic estimating relationships in Aviary originated from historical codes called GASP and FLOPS. For engineers who are familiar with GASP and FLOPS it is helpful to know what an Aviary variable was called in those historical codes.

The historical variable name portion of the metadata allows us to associate any names that an Aviary variable may have had in a previous code. This piece of the metadata is actually a dictionary within each subdictionary belonging to each variable. This dictionary is used by adding an entry for each historical code, where the key is the name of the historical code, and the value for that key is a string or list of strings illustrating the name(s) that variable held in the historic code. This is an optional feature, but can be helpful for users who are porting old codes into new formats. If a tilde (~) is attached to a historical variable, it is a local variable or parameter in GASP or FLOPS. More details about the naming convention is described in utils/develop_metadata.py.

The Aviary-core Metadata#

The Aviary code provides metadata for every variable in the Aviary-core variable hierarchies. As noted above, the metadata is not broken up into multiple dictionaries like the variable hierarchy, but instead the metadata for every variable lives in the same dictionary. As such there is only one Aviary-core metadata dictionary, which can be viewed here and accessed in the following way:

import aviary.api as av

MetaData = av.CoreMetaData

In the Aviary-core metadata dictionary, due to the size of the data we have adopted a structure of organizing the metadata alphabetically by variable hierarchy. Thus, while all the variables are part of the same metadata dictionary, you will notice that the organization structure of the file is the same alphabetical hierarchal organization structure as the Aviary-core variable hierarchy. This is a convention that we encourage to improve the cleanliness of code, but it is not strictly required.

Building Your Own Metadata#

Unlike the variable hierarchies, which are separated out into different hierarchies for different types of data, there is only one metadata dictionary for all variables in every variable hierarchy. Technically the user may build a metadata dictionary from scratch instead of extending the Aviary-core metadata, however, there is no real value to this as you will eventually have to merge back in the Aviary-core metadata anyway, so there are no normal circumstances under which this is the recommended practice. However, just like with variable hierarchies, you can have several different metadata dictionaries which will eventually be merged together. This may be necessary when there are multiple people developing different external subsystems in different locations.

There are two different ways to change the metadata in a metadata dictionary. The first is to add a new variable to the dictionary, and add that variable’s metadata along with it. This makes use of the add_meta_data() function. This function takes in the variable name of the variable to be added to the metadata dictionary be provided, as well as the dictionary itself that the variable should be added to. It also optionally takes in all of the metadata information listed at the beginning of this page. The function returns nothing, but it internally updates the provided metadata dictionary so that dictionary will contain the new variable and its metadata.

The second way to change the metadata in a metadata dictionary is by updating the metadata associated with a variable that is already in the dictionary. This is accomplished using the update_meta_data() function. This function behaves almost identically to the add_meta_data() function, the only difference being that instead of adding a new variable to the dictionary, it will take the input of metadata information that you provide and overwrite the old metadata of the given variable with the new metadata.

There are two pitfalls that may occur when using these functions. The first pitfall is attempting to call the add_meta_data() function for a variable that already exists in the metadata. This will throw an error, because the add_meta_data() function is only for new variables to the metadata. Conversely, attempting to update the metadata of a variable that is not in the metadata dictionary via update_meta_data() will throw an error because that function is only for variables that already exist in the metadata.

The methods outlined above for updating and adding to the variable metadata are the crux of how the variable metadata can be extended for new variables. The user will simply import the existing Aviary-core metadata and add to it as they see fit.

Note

The variable metadata dictionary that is imported from the Aviary API is actually a copy of the original Aviary metadata dictionary to avoid mutating the original dictionary. That being said, it functions just as a metadata dictionary that you would input to an Aviary model and you can extend it or input it to a model as-is depending on your needs.

Lets examine how we would extend the variable metadata dictionary in practice. Say we have just extended the Aviary-core Aircraft variable hierarchy to add some center of gravity, flap, and jury strut information using the extension below:

import aviary.api as av

AviaryAircraft = av.Aircraft

class ExtendedAircraft(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'

Now we want to extend the Aviary-core metadata into our own metadata that includes metadata for each one of these variables in the same code:

ExtendedMetaData = av.CoreMetaData

av.add_meta_data(
    ExtendedAircraft.CG,
    meta_data=av.CoreMetaData,
    units='ft',
    desc='Center of gravity',
    default_value=0,
    option=False,
)

av.add_meta_data(
    ExtendedAircraft.Wing.Flap.AREA,
    meta_data=ExtendedMetaData,
    units='ft**2',
    desc='planform area of flap',
    default_value=10,
    option=False
)

av.add_meta_data(
    ExtendedAircraft.Wing.Flap.ROOT_CHORD,
    meta_data=ExtendedMetaData,
    units='ft',
    desc='chord of flap at root of wing',
    default_value=1,
    option=False
)

av.add_meta_data(
    ExtendedAircraft.Wing.Flap.SPAN,
    meta_data=ExtendedMetaData,
    units='ft',
    desc='span of flap',
    default_value=60,
    option=False
)

av.add_meta_data(
    ExtendedAircraft.Jury.MASS,
    meta_data=ExtendedMetaData,
    units='kg',
    desc='mass of jury strut',
    default_value=50,
    option=False
)

ExtendedMetaData now contains the metadata of all the Aviary-core variables along with the metadata information that we just added.

Merging Independent Metadata#

Extending the metadata is great, but sometimes users will end up with multiple metadata dictionaries because different subsystem developers extended the metadata (and created associated variable hierarchies) to suit their own needs. Aviary needs to be given one single metadata dictionary which contains metadata of all the variables it has been given, so we need to be able to merge together multiple metadata dictionaries into one. The merge_meta_data() function has been provided to combine all the different metadata into one. The merge_meta_data() function behaves quite similarly to the merge_variable_hierarchies() function. It takes in a string of metadata dictionaries that need to be merged together, and it returns a single metadata dictionary containing the metadata from all the individual dictionaries.

Let’s say that we have created our ExtendedAircraft and ExtendedMetaData from above, and that elsewhere we have a subsystem that requires information about engine cooling system mass as well as whether the aircraft has winglets. Below is the buildup of the Aircraft type hierarchy and the metadata for our new subsystem:

import aviary.api as av

class ExtendedAircraft2(av.Aircraft):

    class Engine(av.Aircraft.Engine):

        class Cooling:
            MASS = 'aircraft:engine:cooling:mass'

    class Wing(av.Aircraft.Wing):
        WINGLETS = 'aircraft:wing:winglets'

ExtendedMetaData2 = av.CoreMetaData

av.add_meta_data(
    ExtendedAircraft2.Engine.Cooling.MASS,
    units='kg',
    desc='mass of cooling system for one engine',
    default_value=100,
    meta_data=ExtendedMetaData2,
    historical_name=None,
)

av.add_meta_data(
    ExtendedAircraft2.Wing.WINGLETS,
    units=None,
    desc='Tells whether the aircraft has winglets',
    default_value=True,
    option=True,
    types=bool,
    meta_data=ExtendedMetaData2,
    historical_name=None,
)

We can see from the above code that we have an Aircraft type variable hierarchy named ExtendedAircraft2 and that we have created our own metadata dictionary ExtendedMetaData2 which is an extension of the CoreMetaData dictionary in Aviary-core. Now we have two different Aircraft type variable hierarchy extensions, ExtendedAircraft and ExtendedAircraft2. We also have two different metadata extensions, ExtendedMetaData and ExtendedMetaData2. We need a single Aircraft type variable hierarchy, and single metadata dictionary. Thus, we will use the merging functions built into Aviary:

FinalAircraft = av.merge_hierarchies([ExtendedAircraft, ExtendedAircraft2])
FinalMetaData = av.merge_meta_data([ExtendedMetaData, ExtendedMetaData2])

Above we merged together our hierarchy and metadata extensions, and now we have one single Aircraft type hierarchy FinalAircraft and one single metadata dictionary FinalMetaData which we can provide to the Aviary model.

There is one situation when an attempt to merge together multiple metadata dictionaries will cause errors, and that situation is if more than one metadata dictionary contains the same variable with different metadata. If multiple dictionaries contain the same variable with identical metadata the merge will proceed, but if the metadata differs at all the merge will halt and force the user to rectify the discrepancy.

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

Providing Aviary with Necessary Variable Metadata#

This section is under development.

Searchable Metadata Table#

The table below contains all the metadata for every variable in the Aviary-core variable hierarchies. The table is searchable and sortable and is created automatically from the Aviary core metadata dictionary.

This is the init_notebook_mode cell from ITables v2.1.5
(you should not see this message - is your notebook trusted?)
variable name units desc option default_value types historical_name
Loading ITables v2.1.5 from the init_notebook_mode cell... (need help?)