Input Files#

Aviary can read input files for a few different purposes. The main purpose is to load information from a .csv file about the aircraft to be designed. Other input files might be necessary if you’re loading in tabulated aerodynamic or propulsion data. This doc page goes into more details about the different types of input files and how to use them.

Aviary Aircraft Input Files#

Aviary can use a .csv file to load in information about the aircraft to be designed. The file format is straightforward and follows the convention of name, value, units for each row. The names of the variables are detailed in the Understanding Variable Metadata doc page.

Here are the first few lines of an example input file:

Hide code cell source
from aviary.api import Aircraft
import aviary.api as av

file_path = av.get_path('models/test_aircraft/aircraft_for_bench_FwFm.csv')

with open(file_path, 'r') as file:
    for i, line in enumerate(file):
        if i < 20:
            print(line.strip('\n'))
        else:
            break
aircraft:air_conditioning:mass_scaler,1.0,unitless
aircraft:anti_icing:mass_scaler,1.0,unitless
aircraft:apu:mass_scaler,1.1,unitless
aircraft:avionics:mass_scaler,1.2,unitless
aircraft:canard:area,0.0,ft**2
aircraft:canard:aspect_ratio,0.0,unitless
aircraft:canard:thickness_to_chord,0.0,unitless
aircraft:crew_and_payload:baggage_mass_per_passenger,45.0,lbm
aircraft:crew_and_payload:cargo_container_mass_scaler,1.0,unitless
aircraft:crew_and_payload:flight_crew_mass_scaler,1.0,unitless
aircraft:crew_and_payload:mass_per_passenger,180.0,lbm
aircraft:crew_and_payload:misc_cargo,0.0,lbm
aircraft:crew_and_payload:non_flight_crew_mass_scaler,1.0,unitless
aircraft:crew_and_payload:num_business_class,0,unitless
aircraft:crew_and_payload:num_first_class,11,unitless
aircraft:crew_and_payload:num_flight_attendants,3,unitless
aircraft:crew_and_payload:num_flight_crew,2,unitless
aircraft:crew_and_payload:num_galley_crew,0,unitless
aircraft:crew_and_payload:num_passengers,169,unitless
aircraft:crew_and_payload:num_tourist_class,158,unitless
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/pyoptsparse/pyOpt_MPI.py:68: UserWarning: mpi4py could not be imported. mpi4py is required to use the parallel gradient analysis and parallel objective analysis for non-gradient based optimizers. Continuing using a dummy MPI module from pyOptSparse.
  warnings.warn(warn)

External Data Files#

Several subsystems, including propulsion and aerodynamics, support loading existing tabular engine performance data and drag polars respectively from text files. Aviary has a specific format that data files are required to be in to ensure both human and machine readability.

Most arbitrary file extensions will work, however it is recommended to use a basic text-based file format (such as .txt or .csv) so the data file is compatible for viewing with other programs.

Aviary’s data table format consists of three parts: comments, headers, and data. Comments are any text on a line following the # character. Comments may be placed anywhere in the file, including in-line.

Headers are information on variable name, and optionally units. Only one header can be present, and it must appear before the numerical performance data begins. The header consists of a comma separated list of variable names in the order they appear in the data table, with units optionally provided in parentheses after the variable name. Aviary supports the same list of units supported by OpenMDAO. If units are not specified, a default of ‘unitless’ is assumed, unless the user provides variable metadata when using the csv reading utility function. In that case, the default units of that variable in the metadata is used. This functionality is demonstrated below.

The data in an external data file must be in column format, delimited by commas. Only numerical data that can be cast to type float is compatible with Aviary data tables at this time. An error will be raised if non-numerical data is present in the data file that is not a comment or a correctly formatted header.

Reading and writing Aviary data files#

Aviary includes a pair of utility functions, read_data_file and write_data_file, to assist reading and writing files in Aviary data format. Here we will demonstrate writing data to a csv file, then reading it back to retrieve the data.

# generate fake data set with units using NamedValues
data = av.NamedValues()
data.set_val(Aircraft.Wing.SPAN, [79, 118, 171], 'ft')
data.set_val('Scale Factor', [0.5, 0.75, 0.8], 'unitless')
# add these comments to the file, added to the top. Demonstrate how comments do not
# require inclusion of a '#' symbol, and will work either way
comments = ['This is test data generated using write_data_file',
            '# Aviary data tables can support multiple comments']
# the name of the file we will write to
filename = 'example.csv'

av.write_data_file(filename, data, comments)

The .csv file that is created looks like this:

Hide code cell source
with open('example.csv', 'r') as file:
    for line in file:
        print(line.strip('\n'))
# This is test data generated using write_data_file
# Aviary data tables can support multiple comments

aircraft:wing:span (ft), Scale Factor
                     79,          0.5
                    118,         0.75
                    171,          0.8

Now, let’s read this file back into memory and confirm everything was read correctly. Note that Scale Factor does not have units explicitly listed. Variables without specified units, or units of ‘unitless’ do not require units to be listed in the header to reduce clutter. When reading this csv back, Aviary will know to add units of ‘unitless’ to any variables without specified units. The exception is when using metadata to filter what data will be read, which will be demonstrated later on this page. Also, it can be seen both comments have the # as the first character, even though it was not included in the first comment given to the csv writer. Aviary handles comment formatting, so including a # character with comments is optional.

# read the csv file that was just created
read_data, read_comments = av.read_data_file(filename, save_comments=True)
# print out comments
print(read_comments)
# print out variable name, units, and values
items = av.get_items(read_data)
for item in items:
    print(f'{item[0]}, units: {item[1][1]}')
    print(item[1][0])
['This is test data generated using write_data_file', 'Aviary data tables can support multiple comments']
aircraft:wing:span, units: ft
[ 79. 118. 171.]
Scale_Factor, units: unitless
[0.5  0.75 0.8 ]

Running this code shows our comments were correctly retrieved (stripped of leading #). We also have both our variables with their correct units and values. The write_data_file function has added back in units of ‘unitless’ for Mach Number. Scale Factor was also modified to Scale_Factor. This is because it is assumed these names will feed into openMDAO variables, and spaces are not allowed.

Now let’s explore some optional arguments for csv_reader.

The first optional argument for csv_reader is variable metadata. When provided, read_data_file checks variable names in the header against the metadata and skips reading any variables not found. In addition, units specified in the data file are checked for compatibility with the default units for that variable. If units are not provided for a variable, default units are applied instead of always applying ‘unitless’. Let’s re-run the same code as before, but this time provide Aviary’s core metadata to the reader. The expected behavior is for Scale Factor to be skipped, since it isn’t in the variable hierarchy.

# call read_data_file again, but this time provide variable metadata
read_data, read_comments = av.read_data_file(filename, av.CoreMetaData, save_comments=True)
# print out comments
print(read_comments)
# print out variable name, units, and values
items = av.get_items(read_data)
for item in items:
    print(f'{item[0]}, units: {item[1][1]}')
    print(item[1][0])
['This is test data generated using write_data_file', 'Aviary data tables can support multiple comments']
aircraft:wing:span, units: ft
[ 79. 118. 171.]
/home/runner/work/Aviary/Aviary/aviary/utils/csv_data_file.py:109: UserWarning: Header <Scale_Factor> was not recognized, and will be skipped
  warnings.warn(f'Header <{name}> was not recognized, and '

We can see that only aircraft:wing:span was read from file this time, and is the only variable present in the data loaded to memory. Additionally, a warning was created informing us that Scale Factor was skipped.

A second optional argument is aliases. This argument is used to map multiple possible header names to the same openMDAO variable. This is useful if your data files do not use Aviary variable names, or could contain multiple variants of names that all mean the same thing (such as ‘height’, ‘alt’, and ‘altitude’). In this example, our data file has a header labeled Scale Factor, but we would like to map it to the more precise aircraft:wing:mass_scaler. The allowable header name matching is not case-sensitive and Aviary will treat spaces and underscores as identical, so scale_factor will match with Scale Factor. This improves ease-of-use. However, the variable name you want headers mapped to are case-sensitive, in case you are connecting to an external component that doesn’t follow Aviary’s variable naming standards. So if your alias dict contains Final_Name: example_var, any case combination of example_var will always return Final_Name capitalized as specified.

# keys are desired openMDAO variable name, values are header names that we want to match
# values can also be a list of multiple header names that map to the same key
alias_dict = {Aircraft.Wing.MASS_SCALER: 'Scale Factor'}

# call read_data_file again, but this time provide variable alias dictionary
read_data, read_comments = av.read_data_file(filename, aliases=alias_dict, save_comments=True)
# print out comments
print(read_comments)
# print out variable name, units, and values
items = av.get_items(read_data)
for item in items:
    print(f'{item[0]}, units: {item[1][1]}')
    print(item[1][0])
['This is test data generated using write_data_file', 'Aviary data tables can support multiple comments']
aircraft:wing:span, units: ft
[ 79. 118. 171.]
aircraft:wing:mass_scaler, units: unitless
[0.5  0.75 0.8 ]

We can see that instead of returning Scale Factor, we have our values listed under aircraft:wing:mass_scaler, as desired.