5.1.2. Demo 2: Inviscid Bullet with Reports

This is a second CAPE/pyfun demo using a bullet shape and demonstrating how to use the inviscid solver in FUN3D.

To get started, clone the repo and run a few short commands:

$ git clone https://github.com/nasa-ddalle/pyfun02-bullet.git
$ cd pyfun02-bullet
$ ./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.

To keep computation time low for the purposes of running examples. The example seeks to introduce the pyFun user to data books and automated reports, including sweep plots. It should be noted that the Cart3D examples are more descriptive, and users are encouraged to consider reading those examples since most of the process is the same for each solver.

The geometry used for this shape is a capped cylinder and little or nothing else. An inviscid volume mesh was created using AFLR3. The surface triangulation, bullet.tri, is shown below.

../../../_images/bullet011.png

Figure 5.2 Simple bullet shape triangulation with four fins

The files in this folder are listed below with a short description. In this case, the run matrix is defined within the pyFun.json file.

  • pyFun.json: Master input control file for pyFun

  • matrix.csv: Run matrix

  • fun3d.nml: Template namelist file

  • bullet-inviscid.ugrid: Volume grid, ASCII AFLR3 format

  • bullet-inviscid.mapbc: Boundary conditions file

  • bullet-far.tri: (Not used) Cart3D surface triangulation

  • bullet.xml: XML files used to name each numbered component

  • slice-y0.py: Python script for use with Paraview

5.1.2.1. Running Cases

Assuming the present working directory is in this demo folder, i.e. pyfun02_bullet, a good first test command is the following, which checks the status of each case in the matrix.

$ pyfun -c
Case Config/Run Directory  Status  Iterations  Que CPU Time
---- --------------------- ------- ----------- --- --------
0    bullet/m0.80a0.0b0.0  ---     /           .
1    bullet/m0.80a4.0b0.0  ---     /           .
...
23   bullet/m1.75a30.0b0.0 ---     /           .

---=24,

This example contains 24 cases in the run matrix, and the computation time is kept low in order to run each case within a few minutes (using the serial version of FUN3D).

Running case number 3 (note zero-based indexing) has the following output.

$ pyfun -I 3
Case Config/Run Directory  Status  Iterations  Que CPU Time
---- --------------------- ------- ----------- --- --------
3    bullet/m0.80a30.0b0.0 ---     /           .
  Case name: 'bullet/m0.80a30.0b0.0' (index 3)
     Starting case 'bullet/m0.80a30.0b0.0'
 > nodet --animation_freq 100
     (PWD = 'bullet/m0.80a30.0b0.0')
     (STDOUT = 'fun3d.out')
 > nodet --animation_freq 100
     (PWD = 'bullet/m0.80a30.0b0.0')
     (STDOUT = 'fun3d.out')

Submitted or ran 1 job(s).

---=1,

We can then check how much CPU time that used.

$ pyfun -I 3 -c
Case Config/Run Directory  Status  Iterations  Que CPU Time
---- --------------------- ------- ----------- --- --------
3    bullet/m0.80a30.0b0.0 DONE    200/200     .        0.1

DONE=1,

In the master input file pyFun.json, the key section is the "Fun3D" section, which modifies the template namelist fun3d.nml. The example is set up to run two phases. The first phase has a starting CFL number of 0.1 which ramps up to 100.0. The second phase has a constant CFL number of 100.0.

"Fun3D": {
    "nonlinear_solver_parameters": {
        "schedule_cfl": [[0.1, 100.0], [100.0, 100.0]],
        "schedule_iteration": [[1, 100], [1, 50]]
    },
    "global": {
        "volume_animation_freq": -1
    },
    "code_run_control": {
        "restart_read": ["off", "on"]
    },
    "inviscid_flux_method": {
        "first_order_iterations": [50, 0],
        "flux_construction": "roe",
        "flux_construction_lhs": "vanleer",
        "flux_limiter": "hvanalbada",
        "freeze_limiter_iteration": [150, 0]
    },
    "special_parameters": {
        "large_angle_fix": "on"
    },
    "boundary_output_variables": {
        "boundary_list": "7-9",
        "cp": true,
        "ptot": true
    }
}

Another interesting parameter is the Config>File, which is set to "bullet.xml". This is an XML file that prescribes a name for each component and furthermore can be used to define groups of components. While this is not a recognized FUN3D file format, it is used by pyFun to make some of the setup easier. Some of the text from the XML file are shown below.

<?xml version="1.0" encoding="ISO-8859-1"?>

<Configuration Name="arrow sample" Source="arrow-far.tri">

<!-- triangulated components -->
 <Component Name="cap" Parent="bullet_no_base" Type="tri">
  <Data> Face Label=1 </Data>
 </Component>

 <Component Name="body" Parent="bullet_no_base" Type="tri">
  <Data> Face Label=2 </Data>
 </Component>

 <Component Name="base" Parent="bullet_total" Type="tri">
  <Data> Face Label=3 </Data>
 </Component>

<!-- Containers -->
 <Component Name="fins" Type="container" Parent="bullet_no_base">
 </Component>
 <Component Name="bullet_no_base" Type="container" Parent="bullet_total">
 </Component>
 <Component Name="bullet_total"   Type="container">
 </Component>

</Configuration>

In particular, this allows pyFun to set the correct namelist parameters to track the forces and moments on each component. This is important because FUN3D internally renumbers all the components 1,2,…,*N* according to the lines of the .mapbc file. The present setup in the Config section of pyFun.json prevents the need to figure out the component number(s) for each component.

Before moving on to the next session, let’s also run case 17 so we can complete the rest of the tutorial. Some of the aerodynamic data book is already in place, but cases 3 and 17 are missing. Users may wish to run all 24 cases or just a few more in order to do more experimenting.

5.1.2.2. Automated Single-Case Report

This example is set up to create a report called report-case.pdf in the report/ folder. It includes a couple of summary tables, 8 iterative history plots, and a flow visualization slide that works with Paraview. Figure 5.3 shows an example of this Paraview image from case 17 (bullet/m1.50a4.0b0.0).

../../../_images/slice-y0.png

Figure 5.3 Surface \(c_p\) and \(y{=}0\) Mach slice

Note about Paraview figure: This example requires ParaView with VisIt Bridge since it reads binary Tecplot (.plt) files. Installation can be tricky, and prepackaged ParaView modules often do not have the VisIt bridge. One relatively easy workaround is to install the free and open-source software SALOME, which does include the appropriate version. It is fairly simple to download a version of SALOME and then use the included ParaView binaries within that installation.

The report also includes axial force coefficient (CA), side force coefficient (CY), and normal force (CY) coefficient on both bullet_no_base and cap. The bullet_no_base component includes bot the rounded nose cap and the cylindrical portion. Figure 5.4 shows one of these plots.

../../../_images/bullet_CN.png

Figure 5.4 Iterative history on bullet (not including base) normal force coefficient (CN) for bullet/m1.50a4.0b0.0

In addition, there is a plot of overall pitching moment coefficient, and a residual plot. Both Figure 5.4 and Figure 5.5 show a big change of behavior at iteration 50, when the first-order iterations end. The residual history also shows a change of behavior at iteration 75; the residual stops dropping for a while while the fluxes are frozen.

../../../_images/L2.png

Figure 5.5 Overall \(L_2\) residual for bullet/m1.50a4.0b0.0

The Paraview subfigure settings from the JSON file are shown below.

"slice-y0": {
    "Type": "Paraview",
    "Caption": "Surface $c_p$ and $y{=}0$ Mach slice",
    "Width": 0.33,
    "Layout": "slice-y0.py",
    "ImageFile": "slice-y0.png"
}

This points pyFun to the Python script slice-y0.py. The image is created by the system command pvpython slice-y0.py in each case folder. This slice-y0.py was created by recording a Python script in ParaView interactively and then modifying the resulting script later. At the time of writing, this is found in the Tools menu under Tools>Start Trace.

The header of this script contains some helper functions that were added in order to provide a solution for users who do not have a version of FUN3D compiled with the TecIO library. It does require the user to use Tecplot’s preplot tool, which can be downloaded from the Tecplot TecIO library website. The first few lines of slice-y0.py are shown below.

#### import the simple module from the paraview
from paraview.simple import *
#### disable automatic camera reset on 'Show'
paraview.simple._DisableFirstRenderCameraReset()

# System interface
import os
# Check for DAT instead of PLT file
for f in ['arrow_tec_boundary', 'arrow_plane-y0']:
    # Name of DAT and PLT files
    fdat = '%s.dat' % f
    fplt = '%s.plt' % f
    # Check for DAT file
    if os.path.isfile(fdat):
        # Delete any PLT file
        if os.path.isfile(fplt): os.remove(fplt)
        # Create new PLT file
        os.system('preplot %s %s' % (fdat, fplt))

Most of the rest of the contents of the Python script come from the ParaView API, but the command at the end is relevant.

# save screenshot
SaveScreenshot('slice-y0.png',
    magnification=1, quality=100, view=renderView1)

This is the command that actually saves the image, and it is relevant to explain here that the name of the image, 'slice-y0.png', must line up with the ImageFile option from the JSON subfigure definition.

5.1.2.3. Aerodynamic Data Book and Sweep Plots

The provided example in $PYCART/examples/pyfun/02_bullet/ includes an aerodynamic database for all but two of the 24 conditions in the data/bullet folder. The contents of an aero data book file are the same here as for Cart3D, and a selection of text from the main bullet_no_base file can be seen below. These aero data book files have the file name aero_$COMP.csv for an arbitrary component COMP.

# Database statistics for 'bullet_no_base' extracted on 2017-04-09 19:35:55
#
#mach,alpha,beta,q,T,config,Label,CA,CY,CN,...,nOrders,nIter,nStats
0.8,0,0,1250,475.33,bullet,,0.1293,-0.0036,-0.0001,...,6.7889,200,50
0.8,4,0,1250,475.33,bullet,,0.1260,-0.0046,0.1854,...,6.8890,200,50
...
1.75,30,0,1250,475.33,bullet,,0.6291,-0.0010,2.8408,...,4.5099,200,50

This is a relatively simple data book definition, as shown in the DataBook section of pyFun.json, reproduced below. We include five data book components here, and all are restricted to be just forces to make some of the files smaller. Normally, a user would not include the lines such as "cap": {"Type": "Force"}. Without a user-specified type, components have the type "FM", which stand for “Force & Moment” (except for Cart3D data books, which are by default "Force"). The DataBook>nStats component means that at least 50 iterations must be included in the averaging window for each coefficient of each component, and nMin states that only iterations after iteration 150 are allowed to be included.

"DataBook": {
    // List of components
    "Components": [
        "bullet_no_base", "bullet_total",
        "cap", "body", "base"
    ],
    // Location
    "Folder": "data/bullet",
    // Overall statistic inputs
    "nStats": 50,
    "nMin": 150,
    // Definitions
    "bullet_no_base": {"Type": "Force"},
    "bullet_total": {"Type": "Force"},
    "cap": {"Type": "Force"},
    "body": {"Type": "Force"},
    "base": {"Type": "Force"}
}

Running the command pyfun --aero will fill in the other two cases.

$ pyfun -I :3 --aero
bullet/m0.80a0.0b0.0
bullet/m0.80a4.0b0.0
bullet/m0.80a10.0b0.0
bullet/m0.80a30.0b0.0
  Adding new databook entry at iteration 200.
bullet/m0.95a0.0b0.0
bullet/m0.95a4.0b0.0
bullet/m0.95a10.0b0.0
bullet/m0.95a30.0b0.0
bullet/m1.10a0.0b0.0
bullet/m1.10a4.0b0.0
bullet/m1.10a10.0b0.0
bullet/m1.10a30.0b0.0
bullet/m1.25a0.0b0.0
bullet/m1.25a4.0b0.0
bullet/m1.25a10.0b0.0
bullet/m1.25a30.0b0.0
bullet/m1.50a0.0b0.0
bullet/m1.50a4.0b0.0
  Adding new databook entry at iteration 200.
bullet/m1.50a10.0b0.0
bullet/m1.50a30.0b0.0
bullet/m1.75a0.0b0.0
bullet/m1.75a4.0b0.0
bullet/m1.75a10.0b0.0
bullet/m1.75a30.0b0.0

The pyFun.json "Report" section also includes a Mach sweep figure. Details of the Mach sweep (with an angle of attack carpet plot) are the same as in the Cart3D example Demo 7: Data Book Plots and Reports, but Figure 5.6 gives an example of one of the plots from the resulting report-mach.pdf.

../../../_images/mach_cap_CN.png

Figure 5.6 Mach sweep of CN on cap for various angles of attacks.

To generate this report, issue the following command:

$ pyfun --report mach
mach/bullet/m0.80a0.0b0.0
  SweepConds: New subfig
  SweepList: New subfig
  mach_bullet_CA: New subfig
  mach_bullet_CY: New subfig
  mach_bullet_CN: New subfig
  mach_total_CA: New subfig
  mach_total_CY: New subfig
  mach_total_CN: New subfig
  mach_cap_CA: New subfig
  mach_cap_CY: New subfig
  mach_cap_CN: New subfig
Compiling...
Compiling...
Cleaning up...

Actually, Figure 5.6 is missing two data points (one of these is obvious while the other is somewhat hidden). If the user has run the suggested pyfun --aero command from earlier, the resulting plots will include these two missing points.