4.1.4. Demo 4: Business Jet, Data Book, and Automated Reports

The following example uses a more complex geometry to demonstrate Cart3D’s capabilities and the ease with which complex geometries can be analyzed. To get started, clone this repo and run the following easy commands:

$ git clone https://github.com/nasa-ddalle/pycart04-bJet.git
$ cd pycart04-bJet
$ ./copy-files.py
$ cd work/

This will copy all of the files into a newly created work/ folder. Follow the instructions below by entering that work/ folder; the purpose is that you can easily delete the work/ folder and restart the tutorial at any time.

Let’s run the first case.

$ pycart -n 1
Case Config/Run Directory   Status  Iterations  Que CPU Time
---- ---------------------- ------- ----------- --- --------
0    poweroff/m0.84a0.0b0.0 ---     /           .
  Case name: 'poweroff/m0.84a0.0b0.0' (index 0)
  Preparing surface triangulation...
  Reading tri file(s) from root directory.
     Writing triangulation: 'Components.i.tri'
 > autoInputs -r 8 -t Components.i.tri -maxR 11 -nDiv 4
 > cubes -pre preSpec.c3d.cntl -maxR 11 -reorder -a 10 -b 2
 > mgPrep -n 3
     Starting case 'poweroff/m0.84a0.0b0.0'.
 > flowCart -his -clic -N 200 -y_is_spanwise -limiter 2 -T -cfl 1.1 -mg 3 -tm 0
 > flowCart -his -clic -restart -N 300 -y_is_spanwise -limiter 2 -T -cfl 1.1 -mg 3 -tm 1

Submitted or ran 1 job(s).

---=1,

A sample graphic of the surface pressure made with ParaView is shown below.

../../../_images/bJet01.png

Figure 4.4 Business jet triangulation colored by pressure coefficient from poweroff/m0.84a0.0b0.0 solution

4.1.4.1. Phase Control

This is an example with more complex geometry, obviously, but it also is an example of a two-phase solution procedure. This can be seen in the sample output above because there are two flowCart commands. The following is a snippet from the pyCart.json file.

"RunControl": {
    // Run sequence
    "PhaseSequence": [0, 1],
    "PhaseIters": [0, 300],
    // Number of threads
    "nProc": 4,

    // flowCart settings
    "flowCart": {
        "it_fc": [200, 100],
        "first_order": [1, 0],
        "cfl": 1.1,
        "mg_fc": 3,
        "limiter": 2,
        "tm": [0, 1],
        "y_is_spanwise": false,
        "binaryIO": false,
        "tecO": true
    },

    // Parameters for autoInputs
    "autoInputs": {
        "r": 8,
        "nDiv": 4
    },

    // Parameters for cubes
    "cubes": {
        "maxR": 11,
        "pre": "preSpec.c3d.cntl",
        "cubes_a": 10,
        "cubes_b": 2,
        "reorder": true
    }
},

In this "RunControl" section is the option "PhaseSequence": [0, 1], which tells pyCart to run phase 0 followed by phase 1. Phase 0 is run exactly once because PhaseIters[0] is 0, and phase 1 is repeated until at least PhaseIters[1] total (i.e., including previous phases) iterations have been completed.

The it_fc option inside the "flowCart" section specifies how many iterations in each call to flowCart. In this case, it_fc[0] is 200, so phase 0 runs for 200 iterations, and hence the flowCart -N 200 command above. Since it_fc[1] is 100, phase 1 runs flowCart -restart -N 300, where N is the total number of iterations at which flowCart exits. The dual nature of the first_order option means that phase 0 is run in first-order mode while subsequent phases will all be second-order. All the other options in the "flowCart" section that are not specified as a list use the same option for all phases.

4.1.4.2. Configuration

Let’s also look at the "Config" section of pyCart.json.

// Describe the reference values and config.
"Config": {
    // Defer to a file for most things.
    "File": "Config.xml",
    // Which forces should be reported
    "Force": ["fuselage", "wing", "htail", "vtail", "engines"],
    // Reference values
    "RefArea": 1005.3,
    "RefLength": 66.3,
    // The moment point can be specified as a dictionary of components.
    "Points": {"MRP": [0.0, 0.0, 0.0]},
    "RefPoint": {
        "fuselage": "MRP",
        "wing":     "MRP",
        "htail":    "MRP",
        "vtail":    "MRP",
        "engines":  "MRP"
    }
},

The Force section lists out the components for which iterative force histories are reported while running flowCart. Similarly, the RefPoint section specifies which components will also have aerodynamic moments reported. An interesting feature demonstrated in this example is how the moment reference point is not defined directly for each component. Instead, a common reference point is defined in the Points variable, and pyCart automatically refers to this point when creating Cart3D’s standard input.cntl input file. This saves a little bit of effort if a reference point happens to move a little bit, but it is also useful in cases where reference points may shift from case to case—for example when studying a separation problem or moving fins.

4.1.4.3. Database Management

Let’s also look at some of pyCart’s database management capabilities. In particular, we’ll look at automated calculation of mean values and standard deviations of aerodynamic forces and moments.

Much like the "Config", section, the data book, which is controlled by the "DataBook" section of pyCart.json, needs a list of components to keep track of. In the JSON file snippet below taken from the pyCart.json file from the business jet example, we’re tracking five components, and we are recording both the forces and moments for each.

"DataBook": {
    // List of components to place in data book
    "Components": ["fuselage", "wing", "htail", "vtail", "engines"],
    // Number of iterations to use for statistics.
    "nStats": 50,
    "nMin": 200,
    // Place to put the data book
    "Folder": "data",
    // Information about each component.
    "fuselage": {"Type": "FM"},
    "wing":     {"Type": "FM"},
    "htail":    {"Type": "FM"},
    "vtail":    {"Type": "FM"},
    "engines":  {"Type": "FM"}
},

The {"Type": "FM"} specifier just means that its a default force & moment component. Another common value of Type is "Force", which just ignores any moment histories. These are pretty vanilla data book component definitions; it is also possible to specify a transformation if you want to resolve the forces and/or moments in a different coordinate system or scale some of the results.

Two other important parameters are nStats and nMin. The nMin parameter in this case means that only iterations after iteration 200 can be used to compute the mean value and standard deviation in the database. Using this nMin parameter is a good error-prevention technique because it automatically leaves holes in the database for cases that have not run sufficiently far. The nStats parameter means that pyCart will use the last 50 iterations available to compute the mean.

To create or update the data book, run the following command.

$ pycart --aero
poweroff/m0.84a0.0b0.0
  Adding new databook entry at iteration 300.
poweroff/m0.84a2.0b0.0
poweroff/m0.88a0.0b0.0
poweroff/m0.88a2.0b0.0

In this case, pycart runs through the run matrix (it is possible to restrict this command to a subset of cases just like any pycart command) and checks if any case meets the criteria to be entered into the databook. Every case must be run at least nMin + nStats iterations. This creates a few files in the data/ folder. Specifically, there is a aero_$COMP.csv file for each COMP in the "Components" field. As an example, the contents of aero_fuselage.csv are the following.

# aero data for 'fuselage' extracted on 2016-01-27 16:38:05
#
# Reference Area = 1.005300E+03
# Reference Length = 6.630000E+01
# Nominal moment reference point:
# XMRP = 0.000000E+00
# YMRP = 0.000000E+00
# ZMRP = 0.000000E+00
#
# Mach,alpha,beta,config,Label,CA,CY,CN,CLL,CLM,CLN,CA_min,CA_max,
    CA_std,CA_err,CY_min,CY_max,CY_std,CY_err,CN_min,CN_max,CN_std,
    CN_err,CLL_min,CLL_max,CLL_std,CLL_err,CLM_min,CLM_max,CLM_std,
    CLM_err,CLN_min,CLN_max,CLN_std,CLN_err,nOrders,nIter,nStats
0.84,0.0,0.0,poweroff,,8.93902000E-03,-4.91405000E-03,9.77648294E-06,
    1.94313000E-06,-4.68098922E-06,-1.51877000E-03,8.93902000E-03,
    8.93902000E-03,6.93889390E-18,0.00000000E+00,-4.91405000E-03,
    -4.91405000E-03,2.60208521E-18,0.00000000E+00,9.77640000E-06,
    9.77653000E-06,3.80553837E-11,1.36840069E-11,1.94313000E-06,
    1.94313000E-06,0.00000000E+00,0.00000000E+00,-4.68100000E-06,
    -4.68098000E-06,6.52089771E-12,2.16772288E-12,-1.51877000E-03,
    -1.51877000E-03,1.30104261E-18,8.03348895E-20,6.7302,300,50

This is a fairly self-explanatory file in which lines starting with # are comments. The indentations shown in the sample are line continuations; the actual contents of the file contains two very long lines.

4.1.4.4. Automated Reports

This business jet also contains a demo of pyCart’s automated report capability. Calling pyCart --report results in a multi-page PDF created using LaTeX. There are two modes for these reports: one creates various figures for each case in the run matrix, and the other creates various plots for groups of cases. The example below shows the set of plots for the one case we’ve run in this example.

../../../_images/report-case.png

Example report page for case poweroff/m0.84a0.0b0.0

This is the second page of the report generated from the command below. Unfortunately, this command relies on having a relatively up-to-date and complete PDFLaTeX compiler; without these dependencies, the following command will fail (although it will still generate the individual figures as separate files).

$ pycart -I 0 --report

It contains two tables; one of these summarizes the run conditions (i.e., the values of the run matrix input variables), and the other presents selected force and moment results. Then there is a set of nine plots that show selected quantities at each iteration. A higher-resolution view of the residual history plot is below.

../../../_images/L1.png

L1 density residual history for poweroff/m0.84a0.0b0.0

The settings for this automated report are specified in the "Report" section of pyCart.json.

"Report": {
    // Definition of the report
    "case": {
        "Title": "Cart3D Force, Moment, \\& Residual Report",
        "Author": "pyCart User Manual",
        "Figures": ["Summary", "History"]
    },
    // Definitions of figures
    "Figures": {
        "Summary": {
            "Subfigures": ["Conditions", "Forces"],
            "Alignment": "left"
        },
        // Force convergence figure
        "History": {
            "Subfigures": [
                "wing_CA",  "wing_CY",  "wing_CN",
                "wing_CLL", "wing_CLN", "wing_CLM",
                "L1",       "htail_CY", "htail_CLN"
            ],
            "Header": "Force, moment, and residual histories",
            "Alignment": "center"
        }
    },
    // Set options for specific subfigures
    "Subfigures": {
        ...
    }
}

The logic for this section is split into definitions for one or several types of report that contains at least a title and list of figures, a list of figure definitions, and a list of subfigure definitions. Any key of the parent "Report" that is not either "Reports", "Figures", "Subfigures", "Sweeps", or "Archive" is interpreted as a definition for a type of report. In this case, there is one report type called "case" (using report names that start with a lower-case letter is a good convention). The "case" report has two figures, titled "Summary" and "History".

Then scrolling down to the "Figures" section, we see the list of subfigures in each. A subfigure is an individual table or plot along with some formatting options and a caption. The following example shows a selection of these subfigure definitions that give an idea of their format.

"Subfigures": {
    // Iterative history of component "wing"
    "wing": {
        "Type": "PlotCoeff",
        "Component": "wing",
        "Width": 0.33,
        "Delta": 0.02,
        "Format": "png"
    },
    "wing_CA": {"Type": "wing", "Coefficient": "CA", "Delta": 0.005},
    "wing_CY": {"Type": "wing", "Coefficient": "CY"},
    ...
    // Residual plot
    "L1": {
        "Type": "PlotL1",
        "Caption": "Total L1 density residual",
        "Width": 0.33,
        "Format": "png"
    },
    // Conditions table
    "Conditions": {
        "Type": "Conditions",
        "Header": "Conditions",
        "Position": "t"
    },
    // Force and moment results table
    "Forces": {
        "Type": "Summary",
        "Header": "Force \\& moment summary",
        "Position": "t",
        "Iteration": 0,
        "Components": ["wing", "htail", "fuselage"],
        "Coefficients": ["CA", "CY", "CN"],
        "CA": ["mu", "std"],
        "CY": ["mu", "std"],
        "CN": ["mu", "std"]
    }
}

There are several predefined types of subfigures, including "PlotCoeff", "PlotL1", "Conditions", and "Summary". The main subfigure type is "PlotCoeff", which plots the iterative history of one of the six force or moment coefficients on a specified component. Another useful feature is the ability to cascade options by using a previous subfigure definition as the "Type" of a later one. This reduces the number of lines required to define groups of plots that have similar options.

The "Conditions" subfigure type makes a table listing the values of each trajectory key for the case in question, The "SkipVars" option allows the user to omit any subset of these variables from the table. The "Summary" type makes a table of force & moment statistics. Each value in the "Summary" table is computed according to the statistics options from the "DataBook" section described above.