.. _pycart-ex-lineload-arrow:

Demo 6: Line Loads on the Arrow Example
=======================================

.. note::

    This example requires `Chimera Grid Tools
    <https://www.nas.nasa.gov/publications/software/docs/chimera/index.html>`_
    to calculate sectional loads. Specifically, the `triload
    <https://www.nas.nasa.gov/publications/software/docs/chimera/pages/triload.html>`_
    command is used. To acquire Chimera Grid Tools, free software from NASA,
    use the `NASA Software Catalog
    <https://software.nasa.gov/software/ARC-16025-1A>`_.

Using the geometry from :ref:`Example 2 <pycart-ex-arrow>`, this case continues
the analysis and adds computation of sectional loads. To get started, clone
this repository and run the following easy commands:

    .. code-block:: console

        $ git clone https://github.com/nasa-ddalle/pycart05-adapt_bJet.git
        $ cd pycart06-lineload_arrow
        $ ./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.

The geometry used for this shape is a capped cylinder with four fins and 9216
faces and seven components.  The surface triangulation, ``arrow.tri``, is
shown below.

    .. figure:: ../02-arrow/arrow01.png
        :width: 4in
        
        Simple bullet shape triangulation with four fins
        
This example is set up with a small run matrix to demonstrate line loads on a
few related cases.

    .. code-block:: console
    
        $ pycart -c
        Case Config/Run Directory   Status  Iterations  Que CPU Time 
        ---- ---------------------- ------- ----------- --- --------
        0    poweroff/m1.25a0.0b0.0 ---     /           .            
        1    poweroff/m1.25a2.0b0.0 ---     /           .            
        2    poweroff/m1.25a0.0b2.0 ---     /           .            
        
Running Cases
-------------
When doing post-processing of Cart3D results, it is often desirable to perform
time-averaging or iteration-averaging before doing analysis.  When Cart3D exits
(either ``flowCart`` or ``mpix_flowCart`` called with the ``-clic`` option), it
writes a ``Components.i.triq`` file.  This is a surface triangulation with some
results from the last iteration.  It contains the pressure coefficient and the
five native Cart3D state variables at each node of the triangulation.

To get a ``triq`` file with averaged results, we have to run ``flowCart`` a few
iterations at a time and manually perform averaging.  The ``-stats`` option
performs a similar task, but it is not quite consistent with what's needed for
an averaged line load.  To get pyCart to perform this unusual task, we have the
following ``"RunControl"`` section in ``pyCart.json``.

    .. code-block:: javascript
    
        // Iteration control and command-line inputs
        "RunControl": {
            // Run sequence
            "PhaseSequece": [0],
            "PhaseIters": [200],
            // System configuration
            "nProc": 4,
            "MPI": 0,
            "Adaptive": 0,
            // Options for ``flowCart``
            "flowCart": {
                "it_fc": 200,
                "it_avg": 10,
                "it_start": 100,
                "cfl": 1.1,
                "mg_fc": 3,
                "y_is_spanwise": true
            },
            // Defines the flow domain automatically
            "autoInputs": {"r": 6},
            // Volume mesh options
            "cubes": {
                "maxR": 8,
                "pre": "preSpec.c3d.cntl",
                "cubes_a": 8,
                "cubes_b": 2,
                "reorder": true
            }
        }

As previously, the *RunControl>flowCart>it_fc* option controls how many
iterations ``flowCart`` runs for.  The *it_avg* and *it_start* are new options.
The idea is that Cart3D will be run for *it_avg* iterations at a time.  pyCart
then calculates a cumulative average ``triq`` file that updates after each
*it_avg* iterations.  However, it first runs *it_start* iterations before
initiating this start-stop behavior.  This prevents initial iterations from
corrupting the average.

If we run one case, there is a lot of output printed to STDOUT, and it looks
something like this.  The output has been truncated.  

**Note:** This is set up to run on four threads and take
less than one minute.

    .. code-block:: console
    
        $ pycart -I 0
        Case Config/Run Directory   Status  Iterations  Que CPU Time 
        ---- ---------------------- ------- ----------- --- --------
        0    poweroff/m1.25a0.0b0.0 ---     /           .            
          Group name: 'poweroff' (index 0)
          Preparing surface triangulation...
          Reading tri file(s) from root directory.
         > autoInputs -r 6 -t Components.i.tri -maxR 8 -nDiv 4
         > cubes -pre preSpec.c3d.cntl -maxR 8 -reorder -a 8 -b 2
         > mgPrep -n 3
             Starting case 'poweroff/m1.25a0.0b0.0'
         > flowCart -his -clic -N 100 ...
         > flowCart -his -clic -restart -N 110 ...
         > flowCart -his -clic -restart -N 120 ...
         > flowCart -his -clic -restart -N 130 ...
         > flowCart -his -clic -restart -N 140 ...
         > flowCart -his -clic -restart -N 150 ...
         > flowCart -his -clic -restart -N 160 ...
         > flowCart -his -clic -restart -N 170 ...
         > flowCart -his -clic -restart -N 180 ...
         > flowCart -his -clic -restart -N 190 ...
         > flowCart -his -clic -restart -N 200 ...
             Writing triangulation: 'Components.11.100.200.triq'
        
        Submitted or ran 1 job(s).
        
        ---=1, 
        
This lengthy output explains more clearly what is meant by running ``flowCart``
10 iterations at a time.  The iteration-averaged surface file that gets created
at the end, ``Components.11.100.200.triq``, explains the contents of the file. 
Specifically, it says that the file contains input from 11 iterations between
100 and 200.

Let's run the last two cases in the run matrix, too.

    .. code-block:: console
    
        $ pycart -n 2
        Case Config/Run Directory   Status  Iterations  Que CPU Time 
        ---- ---------------------- ------- ----------- --- --------
        0    poweroff/m1.25a0.0b0.0 DONE    200/200     .        0.0 
        1    poweroff/m1.25a2.0b0.0 ---     /           .            
             Starting case 'poweroff/m1.25a2.0b0.0'
         > flowCart -his -clic -N 100 ...
         > flowCart -his -clic -restart -N 110 ...
         ...
         > flowCart -his -clic -restart -N 200 ...
             Writing triangulation: 'Components.11.100.200.triq'
        2    poweroff/m1.25a0.0b2.0 ---     /           .            
             Starting case 'poweroff/m1.25a0.0b2.0'
         > flowCart -his -clic -N 100 ...
         > flowCart -his -clic -restart -N 110 ...
         ...
         > flowCart -his -clic -restart -N 200 ...
             Writing triangulation: 'Components.11.100.200.triq'
        
        Submitted or ran 2 job(s).
        
        ---=2, DONE=1, 
        
Calculating Line Loads
----------------------
The purpose of this example was to create line loads, so let's investigate that
part.  To instruct pyCart which components on which to compute line loads, we
go to the ``"DataBook"`` section of ``pyCart.json``.

    .. code-block:: javascript
    
        // Database info
        "DataBook": {
            // List of data book components
            "Components": ["arrow_no_base", "ll_arrow"],
            // Location of data book
            "Folder": "data/",
            // Parameters for collecting data
            "nFirst": 0,
            "nStats": 100,
            "nMin": 100,
            // Basic component
            "bullet_no_base": {
                "Type": "FM"
            },
            // Line load
            "ll_arrow": {
                "Type": "LineLoad",
                "CompID": "arrow_no_base",
                "nCut": 100
            }
        }

This specifies that the databook contains two "Components".  One of them is the
the statistically averaged forces and moments on the ``arrow_no_base`` CompID,
and the other is the sectional load on the same.  Recall from :ref:`Example 2
<pycart-ex-arrow>` that the ``arrow_no_base`` component includes all the
surfaces except the base.

The ``"ll_arrow"`` databook component is defined as a ``"LineLoad"`` component
on the ``arrow_no_base`` CompID, and it is instructed to calculate the
sectional loads on 100 slices of that component.  By default, these slices will
be at constant-*x* planes.

This ``"CompID"`` option allows users to calculate line loads on parts of the
vehicle (for example a wing) and also have multiple line load databooks for the
same vehicle.

Adding this little section to the ``"DataBook"`` is all that's needed to set up
a line load computation.  To actually calculate the line loads, run the
following commands.

**Note:** This command should take less than five seconds to run.

    .. code-block:: console
    
        $ pycart --ll
        Updating line load data book 'll_arrow' ...
        poweroff/m1.25a0.0b0.0
          Adding new databook entry at iteration 200.
            triloadCmd < triload.ll_arrow.i > triload.ll_arrow.o
        poweroff/m1.25a2.0b0.0
          Adding new databook entry at iteration 200.
            triloadCmd < triload.ll_arrow.i > triload.ll_arrow.o
        poweroff/m1.25a0.0b2.0
          Adding new databook entry at iteration 200.
            triloadCmd < triload.ll_arrow.i > triload.ll_arrow.o

This command creates a collection of files.  First, we will note the creation
of a ``lineload`` folder in each case directory.  In the
``poweroff/m1.25a0.0b0.0/lineload`` folder, there are several files used in the
raw computation of line loads created by the Chimera Grid Tools utility
``triloadCmd``.

The file ``triload.ll_arrow.i`` is the input to ``triloadCmd`` that is
automatically created by pyCart.  The main output file is
``LineLoad_ll_arrow.slds``, which contains the non-dimensionalized forces
on each of the 100 slices.

These raw files are then read by pyCart and processed into a databook in the
``data/`` folder (locations specified by the *DataBook>Folder* option in
``pyCart.json``).  Below is a file tree of the ``06_lineload_arrow/data``
folder.

    .. code-block:: none
    
        data/
            ll_ll_arrow.csv
            lineload/
                LineLoad_ll_arrow.smy
                LineLoad_ll_arrow.smz
                poweroff/
                    m1.25a0.0b0.0/
                        LineLoad_ll_arrow.csv
                    m1.25a2.0b0.0/
                        LineLoad_ll_arrow.csv
                    m1.25a0.0b2.0/
                        LineLoad_ll_arrow.csv

The top-level ``ll_ll_arrow.csv`` file is a status file that stores which cases
have computed line loads and what iteration at which they have been computed.
It looks a lot like a force and moment databook file (e.g.
``aero_arrow_no_base.csv``) except that there are no data columns (since
those are stored in the line load folders.

In the ``data/lineload/`` directory, there are two files with unusual file
extensions.  These are just text files that give the outline of the body
intersected by the :math:`y{=}0` plane (``.smy``) and :math:`z{=}0` plane
(``.smz``).  They are used to make the line load plots more convenient, and
which will make more sense in the next subsection.

Within the ``data/lineload/`` folder, there is a whole file tree that mirrors
that of the run cases.  The actual sectional loads from
``poweroff/m1.25a.0.b0.0`` are stored in
``data/lineload/poweroff/m1.25a0.0b0.0``, etc.  In this case, each line load
case folder contains only one file, but if there were more line load
components, there would be one for each line load. Each is a very simple file
containing seven columns: *x/Lref*, and then one for each of the six
coefficients (*CA*, *CY*, *CN*, *CLL*, *CLM*, *CLN*).  The coefficient data is
stored in a seemingly strange format of
:math:`\mathrm{d}C_A/\mathrm{d}(x/L_\mathit{ref})`.  Using this form keeps
results nondimensional but also removes dependence on the number of cuts.

Creating Plots and Automated Reports
------------------------------------
Line load plots are fairly easy to set up.  First let's just create the report
and then describe the ``"Report"`` section of ``pyCart.json``.  

    .. code-block:: console
    
        $ pycart --report
        poweroff/m1.25a0.0b0.0
          CaseConds: New subfig at iteration 200.0
          FMTable: New subfig at iteration 200.0
          x = um.multiply(x, x, out=x)
          arrow_CA: New subfig at iteration 200.0
          arrow_CY: New subfig at iteration 200.0
          arrow_CN: New subfig at iteration 200.0
          arrow_CLL: New subfig at iteration 200.0
          arrow_CLN: New subfig at iteration 200.0
          arrow_CLM: New subfig at iteration 200.0
          L1: New subfig at iteration 200.0
          LL_CY: New subfig at iteration 200.0
          LL_CN: New subfig at iteration 200.0
        poweroff/m1.25a2.0b0.0
          CaseConds: New subfig at iteration 200.0
          FMTable: New subfig at iteration 200.0
          arrow_CA: New subfig at iteration 200.0
          arrow_CY: New subfig at iteration 200.0
          arrow_CN: New subfig at iteration 200.0
          arrow_CLL: New subfig at iteration 200.0
          arrow_CLN: New subfig at iteration 200.0
          arrow_CLM: New subfig at iteration 200.0
          L1: New subfig at iteration 200.0
          LL_CY: New subfig at iteration 200.0
          LL_CN: New subfig at iteration 200.0
        poweroff/m1.25a0.0b2.0
          CaseConds: New subfig at iteration 200.0
          FMTable: New subfig at iteration 200.0
          arrow_CA: New subfig at iteration 200.0
          arrow_CY: New subfig at iteration 200.0
          arrow_CN: New subfig at iteration 200.0
          arrow_CLL: New subfig at iteration 200.0
          arrow_CLN: New subfig at iteration 200.0
          arrow_CLM: New subfig at iteration 200.0
          L1: New subfig at iteration 200.0
          LL_CY: New subfig at iteration 200.0
          LL_CN: New subfig at iteration 200.0
        Compiling...
        Compiling...
        Cleaning up...
        
This creates a multipage PDF (in this case one title page and three more pages
with one page dedicated to each case) that contains selected analysis tables
and plots.  In this case we have set up the report to show one table
identifying the case in more detail, one table of basic force coefficient
results, and nine plots.

    .. figure:: report-case-p3.*
        :width: 5.5in
        
        Automatically generated report for ``poweroff/m1.25a2.0b0.0``
        
The first six plots are of each force or moment coefficient on the
``arrow_no_base`` component.  There is an obvious problem with the *CLL* and
*CLN* plots, which has to do with some confusion due to the symmetry of the
arrow shape.  (This bug may go away in future versions of Cart3D).  We will
discuss how to make these two figures look a little better shortly, but let's
move on to the other three plots.  The first is a plot of the global
:math:`L_1` norm of density residuals (which is the main residual reported by
Cart3D).

The last two plots are line load plots.  Let's discuss the JSON syntax to set
up each of these plots and also how these subfigures are assembled into a
report.  The basic skeleton of the ``"Report"`` section of ``pyCart.json``
is shown below.

    .. code-block:: javascript
    
        "Report": {
            // List of reports
            "Reports": ["case"],
            // Define the report
            "case": {
                "Title": "Automated Cart3D Report with Line Load Plots",
                "Subtitle": "Example \\texttt{06\\_lineload\\_arrow}",
                "Restriction": "pyCart Example - Distribution Unlimited",
                "Figures": ["CaseTables", "CasePlots"]
            },
            // Define the figures
            "Figures": {
                "CaseTables": {
                    "Alignment": "left",
                    "Subfigures": ["CaseConds", "FMTable"]
                },
                "CasePlots": {
                    "Header": "Iterative analysis and sectional loads",
                    "Alignment": "center",
                    "Subfigures": [
                        "arrow_CA",  "arrow_CY",  "arrow_CN",
                        "arrow_CLL", "arrow_CLN", "arrow_CLM",
                        "L1",        "LL_CY",     "LL_CN"
                    ]
                }
            },
            // Definitions for subfigures
            "Subfigures" {
                ...
            }
        }

The overall structure is relatively simple: there is a list of reports (the
same JSON file can have many different reports defined), an overall definition
for the report including a list of figures, a section defining each figure, and
a section defining the subfigures.  A figure is a collection of subfigures plus
an alignment option and optional header.

Creating this report creates a file called ``report-case.pdf` in the
``report/`` folder.  The individual plots created for the report are stored in
folders such as ``report/poweroff/m1.25a2.0/a0.0/``, with each subfigure having
a file name corresponding to the title of the subfigure (e.g.
``arrow_CA.pdf``).

Line Load Subfigures
^^^^^^^^^^^^^^^^^^^^
The focus of this section is on the subfigures, and in particular the plots.
To learn more about the two tables, the actual example ``pyCart.json`` file
is relatively easy to understand.  Defining syntax for the line load plots is
shown below.

    .. code-block:: javascript
    
        "Subfigures": {
            ...
            "LL_arrow": {
                "Type": "PlotLineLoad",
                "Component": "ll_arrow",
                "FigWidth": 5.5,
                "FigHeight": 6,
                "Width": 0.33,
                "SeamCurves": "smy",
                "SeamLocation": "bottom"
            },
            "LL_CY": {
                "Type": "LL_arrow",
                "Caption": "arrow\\_no\\_base/CY",
                "Coefficient": "CY"
            },
            "LL_CN": {
                "Type": "LL_arrow",
                "Caption": "arrow\\_no\\_base/CN",
                "Coefficient": "CN"
            }
        }

We have two line load plots that share many common options defined in
``"LL_arrow"``.  This demonstrates the concept of cascading options and can
save time, effort, and number of lines in the JSON file.  The *LL_arrow>Type*
option is set to ``"PlotLineLoad"``, which is the basic pyCart line load
subfigure type.  The *Component* is set to the name of the line load component
as listed in the ``"DataBook"`` section, and the *Width* setting determines
what percentage of the available text width in the final PDF document is taken
up by the figure.

The *FigWidth* and *FigHeight* obviously set an aspect ratio for the figure,
but the absolute scale of *FigWidth* also determines the size at which the
figure is rendered.  A larger *FigWidth* will make the labels appear to be in a
smaller font size since the size in the document is set by *Width*.

Finally, the *SeamCurves* option list which slice of the geometry (if any) to
plot to help the reader anchor what part of the line load corresponds to what
geometrical features.  The *SeamLocation* plot sets where to put this slice;
``"bottom"`` is the usual choice.

**Waring**: The seam curve plots have automatically adjusted aspect ratio to
avoid distorting the seam curve. As a result, geometry with inconvenient actual
aspect ratios will lead to problematic seam curve plots.

    .. figure:: LL_CN.*
        :width: 4in
        
        Normal sectional loads at 2 degrees angle of attack

Residual History Subfigure
---------------------------
Cart3D residual plots almost always have the same JSON inputs.  The version for
this plot uses a different *FigHeight* in order to match the aspect ratio of
the neighboring line load plots.

    .. code-block:: javascript
    
        "Subfigures": {
            ...
            "L1": {
                "Type": "PlotL1",
                "FigWidth": 5.5,
                "FigHeight": 6,
                "Width": 0.33,
                "Caption": "$L_1$ Density Residual"
            },
            ...
        }
        
Force & Moment Plots
--------------------
The iterative history plots are relatively simple for this case since we are
only plotting one component.

    .. code-block:: javascript
    
        "Subfigures": {
            ...
            "arrow": {
                "Type": "PlotCoeff",
                "Component": "arrow_no_base",
                "FigWidth": 5.5,
                "FigHeight": 4.2,
                "Width": 0.33
            },
            "arrow_CA": {"Type": "arrow", "Coefficient": "CA"},
            "arrow_CY": {"Type": "arrow", "Coefficient": "CY"},
            "arrow_CN": {"Type": "arrow", "Coefficient": "CN"},
            "arrow_CLL": {"Type": "arrow", "Coefficient": "CLL"},
            "arrow_CLM": {"Type": "arrow", "Coefficient": "CLM"},
            "arrow_CLN": {"Type": "arrow", "Coefficient": "CLN"},
            ...
        }
        
As we saw above, this simulation results in very poor results for *CLL* and
*CLN* due to the symmetry of the configuration (among other things).  We can at
least make the figures look readable by using scientific notation for the mean
value and removing the standard deviation.

    .. code-block:: javascript
    
        "Subfigures": {
            ...
            "arrow_CLL": {
                "Type": "arrow",
                "Coefficient": "CLL",
                "MuFormat": "%.2e",
                "ShowSigma": false
            },
            "arrow_CLN": {
                "Type": "arrow",
                "Coefficient": "CLN",
                "MuFormat": "%.2e",
                "ShowSigma": false
            },
            ...
        }
        
The updated *CLN* plot is shown below.

    .. figure:: arrow_CLN.*
        :width: 3.5 in
        
        Problematic yawing moment coefficient with slightly improved formatting

There are also many different options for each of these plots, and it is also
possible to plot line loads from other databases on top of those of the most
recent case for comparison.  See the :ref:`JSON page <pycart-json-Report>` for
a thorough description of options.