FLASH User's Guide

FLASH User's Guide

Version 2.0




flash_blur1.gif


January 2002











uofc_logo.gif asci_med_logo.gif

(ASC) FLASH Center
University of Chicago

Contents

I   PRELIMINARIES
1  Introduction
    1.1  What's new in FLASH 2.0
    1.2  About the user's guide
2  Quick start
    2.1  System requirements
    2.2  Unpacking and configuring FLASH for quick start
    2.3  Running FLASH
II   STRUCTURE
3  Overview of FLASH architecture
    3.1  Structure of a FLASH module
        3.1.1  Configuration layer
        3.1.1.1  Configuration file syntax
        3.1.2  Interface layer and database module
        3.1.2.1  dBaseGetData/dBasePutData
        3.1.2.2  dBaseGetCoords/dBasePutCoords
        3.1.2.3  dBaseGetBoundaryFluxes/dBasePutBoundaryFluxes
        3.1.2.4  dBaseKeyNumber
        3.1.2.5  dBaseSpecies
        3.1.2.6  dBaseVarName
        3.1.2.7  dBasePropertyInteger
        3.1.2.8  dBasePropertyReal
        3.1.2.9  dBaseSetProperty
        3.1.2.10  dBaseVarIndex
        3.1.2.11  Various pointer-returning functions
        3.1.2.12  dBaseGetDataPtrAllBlocks()
        3.1.2.13  dBaseGetDataPtrSingleBlock(block_no)
        3.1.2.14  dBaseGetPtrToXCoords()
        3.1.2.15  dBaseGetPtrToYCoords()
        3.1.2.16  dBaseGetPtrToZCoords()
        3.1.2.17  dBaseGetScratchPtrAllBlocks()
        3.1.2.18  dBaseGetScratchPtrSingleBlock(block_no)
        3.1.2.19  AMR tree interface functions
        3.1.3  Algorithms
    3.2  The FLASH source tree
        3.2.1  Code infrastructure
    3.3  Modules included with FLASH: a brief overview
III   MODULES
4  Driver modules
    4.1  New driver modules euler1, rk3, and strang_delta
        4.1.1  The euler1 module
        4.1.2  The rk3 module
        4.1.3  strang_state and strang_delta modules
        4.1.3.1  New formulation modules
        4.1.3.1.1  State-Vector Instantiation
        4.1.3.1.2  Delta Instantiation
    4.2  Simulation services
        4.2.1  Runtime parameters
        4.2.2  Physical constants
        4.2.3  Monitoring performance
        4.2.4  Log file maintenance
5  FLASH I/O modules and output formats
    5.1  General parameters
        5.1.1  Output file names
    5.2  Restarting a simulation
    5.3  Output formats
        5.3.1  HDF
        5.3.2  HDF5
        5.3.2.1  Machine Compatibility
        5.3.2.2  Data Format
        5.3.3  Fortran 77 (f77)
    5.4  Working with output files
6  Mesh module
    6.1  Algorithm
    6.2  Usage
        6.2.1  Dividing the computational domain
        6.2.2  Message buffering
    6.3  Using cylindrical coordinates
    6.4  Using a uniform grid
7  Hydrodynamics modules
    7.1  The Piecewise-Parabolic Method (PPM)
        7.1.1  Algorithm
        7.1.2  Usage
        7.1.3  Diffusion
        7.1.3.1  Thermal Diffusion
        7.1.3.2  Viscosity
        7.1.3.3  Species Diffusion
    7.2  The Kurganov hydrodynamics module
        7.2.1  Algorithm
        7.2.2  Usage
        7.2.2.1  Interaction with delta and state-vector driver modules
        7.2.2.2  Caveats
8  The magnetohydrodynamics module
    8.1  Algorithm
9  Material properties modules
    9.1  The multifluid database
    9.2  Equations of state
        9.2.1  Algorithm
        9.2.2  Usage
        9.2.2.1  The block interface, eos3d
        9.2.2.2  The vector interface, eos1d
        9.2.2.3  The point interface, eos
        9.2.2.4  Runtime parameters
    9.3  Compositions
        9.3.1  aprox13
        9.3.2  aprox19
        9.3.3  fuel+ash
        9.3.4  iso7
        9.3.5  ppcno
    9.4  The stellar conductivity module
10  Local source terms
    10.1  The nuclear burning module
        10.1.1  Detecting shocks
        10.1.2  Algorithms
        10.1.2.1  Reaction networks
        10.1.2.2  Two linear algebra packages
        10.1.2.3  Two time integration methods
        10.1.2.4  Energy generation rates and reaction rates
        10.1.2.5  Temperature-based timestep limiting
    10.2  Stirring
11  The gravity module
    11.1  Algorithms
        11.1.1  Externally applied fields
        11.1.2  Self-gravity algorithms
        11.1.2.1  Multipole Poisson solver
        11.1.2.2  Multigrid Poisson solver
        11.1.3  Coupling of gravity with hydrodynamics
    11.2  Using the gravity modules
        11.2.1  Constant
        11.2.2  Plane parallel
        11.2.3  Point mass
        11.2.4  Poisson
        11.2.4.1  Multipole
        11.2.4.2  Multigrid
IV   TEST CASES
12  The supplied problems
    12.1  PPM hydro test problems
        12.1.1  The Sod shock-tube problem
        12.1.2  The Woodward-Colella interacting blast-wave problem
        12.1.3  The Sedov explosion problem
        12.1.4  The advection problem
        12.1.5  The problem of a wind tunnel with a step
    12.2  Kurganov hydro test problems
        12.2.1  The Shu-Osher problem
    12.3  MHD test problems
        12.3.1  The Brio-Wu MHD shock tube problem
    12.4  Gravity test problems
        12.4.1  The Jeans instability problem
        12.4.2  The homologous dust collapse problem
        12.4.3  The Huang-Greengard Poisson test problem
    12.5  Other test problems
        12.5.1  The sample_map problem
V   TOOLS
13  The FLASH configuration script (setup)
14  sfocu (Serial Flash Output Comparison Utility)
    14.1  Building sfocu
    14.2  Using sfocu
15  FLASH IDL routines (fidlr)
    15.1  Installing and running fidlr
        15.1.1  Setting up fidlr environment variables
        15.1.2  Setting up the HDF5 routines
        15.1.3  Running IDL
    15.2  fidlr data structures
    15.3  xflash: plotting two-dimensional datasets
    15.4  xflash3d: plotting slices of three-dimensional datasets
    15.5  The fidlr routines
    15.6  fidlr command line example
VI   FURTHER DEVELOPMENT
16  Creating new problems
    16.1  Creating a Config file
    16.2  Creating an init_block.F90
    16.3  The file flash.par
17  Adding new solvers
18  Porting FLASH to other machines
19  Contacting the authors of FLASH
VII   REFERENCES

Acknowledgments





The FLASH Code Group is supported by the (ASC) FLASH Center at the University of Chicago under U. S. Department of Energy contract B341495. Some of the test calculations described here were performed using the Origin 2000 computer at Argonne National Laboratory and the (ASC) Nirvana computer at Los Alamos National Laboratory.


Part 1
PRELIMINARIES


1  Introduction

FLASH is a modular, adaptive-mesh, parallel simulation code capable of handling general compressible flow problems found in many astrophysical environments. FLASH is designed to allow users to configure initial and boundary conditions, change algorithms, and add new physics modules with minimal effort. It uses the PARAMESH library to manage a block-structured adaptive grid, placing resolution elements only where they are needed most. FLASH uses the Message-Passing Interface (MPI) library to achieve portability and scalability on a variety of different parallel computers.

The Center for Astrophysical Thermonuclear Flashes, or FLASH Center, was founded at the University of Chicago in 1997 under contract to the United States Department of Energy as part of its Accelerated Strategic Computing Initiative ((ASC)). The goal of the Center is to address several problems related to thermonuclear flashes on the surfaces of compact stars (neutron stars and white dwarfs), in particular X-ray bursts, Type Ia supernovae, and novae. To solve these problems requires the participants in the Center to develop new simulation tools capable of handling the extreme resolution and physical requirements imposed by conditions in these explosions, and to do so while making efficient use of the parallel supercomputers developed by the ASC project, the most powerful constructed to date.

1.1  What's new in FLASH 2.0

The FLASH 2.0 code has been greatly expanded from the original FLASH 1.0 (Fryxell et al. 2000) and demonstrates significant progress toward the (ASC) FLASH Center's goal in the form of increased problem-solving capability, increased modularization, and further development of the code. FLASH 2.0 includes the following new features:

1.2  About the user's guide

This user's guide is designed to enable individuals unfamiliar with the FLASH code to quickly get acquainted with its structure and to move beyond the simple test problems distributed with FLASH, customizing it to suit their own needs. Section 2 discusses how to get started quickly with FLASH, describing how to configure, build, and run the code with one of the included test problems, then examine the resulting output. Users familiar with the capabilities of FLASH who wish to quickly `get their feet wet' with the code should begin with this section.

Part II begins with an overview of the FLASH code architecture. It also includes a brief overview of the modules which are described individually and in more detail in Part III. Part II also explains how to use the driver-supplied and simulated services.

Part III describes in detail each of the modules included with the code, along with their submodules, runtime parameters, use with included solvers, and the equations and algorithms they use. Important note: We assume that the reader has some familiarity both with the basic physics involved and with numerical methods for solving partial differential equations. This familiarity is absolutely essential in using FLASH (or any other simulation code) to arrive at meaningful solutions to physical problems. The novice reader is directed to an introductory text, examples of which include

       Fletcher, C. A. J.  Computational Techniques for Fluid Dynamics (Springer-Verlag, 1991)
       Laney, C. B. Computational Gasdynamics (Cambridge UP, 1998)
       LeVeque, R. J., Mihalas, D., Dorfi, E. A., and Müller, E., eds. Computational Methods for Astrophysical Fluid Flow (Springer, 1998)
       Roache, P. Fundamentals of Computational Fluid Dynamics (Hermosa, 1998)
       Toro, E. F.  Riemann Solvers and Numerical Methods for Fluid Dynamics, 2nd Edition (Springer, 1999)

The advanced reader who wishes to know more specific information about a given module's algorithm is directed to the literature referenced in the algorithm section of the chapter in question.

Part IV describes the different test problems distributed with FLASH. Part V describes in more detail the use of the configuration and analysis tools distributed with FLASH. Finally, Part VI gives detailed instructions for extending FLASH's capabilities by adding new problem setups, describes how new solvers may be integrated into the code, and Part VII lists publication references.

2  Quick start

This section describes how to quickly get up and running with FLASH, showing how to configure and build it to solve the Sedov explosion problem, how to run it, and how to examine the output using IDL.

2.1  System requirements

You should verify that you have the following:

FLASH has been tested on the following Unix-based platforms. In addition, it may work with others not listed (see Section ).

2.2  Unpacking and configuring FLASH for quick start

To begin, unpack the FLASH source code distribution. If you have a Unix tar file, type `tar xvf FLASHX.Y.tar' (without the quotes), where X.Y is the FLASH version number (for example, use FLASH 2.0.tar and FLASH 2.0/ for FLASH version 2.0). If you are working with a CVS source tree, use `cvs checkout FLASHX.Y' to obtain a personal copy of the tree. You may need to obtain permission from the local CVS administrator to do this. In either case you will create a directory called FLASHX.Y/. Type `cd FLASHX.Y' to enter this directory.

Next, configure the FLASH source tree for the Sedov explosion problem. Type

./setup sedov -auto
This configures FLASH for the sedov problem, using the default hydrodynamic solver, equation of state, mesh package, and I/O format defined for this problem. For the purpose of this quick start example, we will use the default I/O format, HDF. The source tree is configured to create a two-dimensional code by default.

From the FLASH root directory (i.e. the directory from which you ran setup), execute gmake. This will compile the FLASH code. If you should have problems and need to recompile, `gmake clean' will remove all object files from the object/ directory, leaving the source configuration intact; `gmake realclean' will remove all files and links from object/. After `gmake realclean,' a new invocation of setup is required before the code can be built.

Assuming compilation and linking were successful, you should now find an executable named flashX in the object/ directory, where X is the major version number (e.g., 2 for X.Y = 2.0). You may wish to check that this is the case.

FLASH expects to find a flat text file named flash.par in the directory from which it is run. This file sets the values of various runtime parameters which determine the behavior of FLASH. If it is not present, FLASH will abort; flash.par must be created in order for the program to run. Here we will create a simple flash.par which sets a few parameters and allows the rest to take on default values. With your text editor, create flash.par in the main FLASH directory with the contents of Figure 1.

# runtime parameters

lrefine_max = 4
basenm = ßedov_4_"
restart = .false.
trstrt = 0.005
nend = 1000
tmax = 0.02
gamma = 1.4
xl_boundary_type = öutflow"
xr_boundary_type = öutflow"
yl_boundary_type = öutflow"
yr_boundary_type = öutflow"
plot_var_1 = "dens"
plot_var_2 = "temp"
plot_var_3 = "pres"


Figure 1: FLASH parameter file contents for the quick start example.

This instructs FLASH to use up to four levels of adaptive mesh refinement (AMR) and to name the output files appropriately. We will not be starting from a checkpoint file (this is the default, but here it is explicitly set for purposes of illustration). Output files are to be written every 0.005 time units and will be created until t=0.02 or 1000 timesteps have been taken, whichever comes first. The ratio of specific heats for the gas (g) is taken to be 1.4, and all four boundaries of the two-dimensional grid have outflow (zero-gradient or Neumann) boundary conditions. Note the format of the file: each line is a comment (denoted by a hash mark, #), blank, or of the form variable = value. String values are enclosed in double quotes ("). Boolean values are indicated in the Fortran style, .true. or .false. Be sure to insert a carriage return after the last line of text. A full list of the parameters available for your current setup is contained in paramFile.html, which also includes brief comments for each parameter.

2.3  Running FLASH

We are now ready to run FLASH. To run FLASH on N processors, type

mpirun -np N object/flashX
remembering to replace N and X with the appropriate values. Some systems may require you to start MPI programs with a different command; use whichever command is appropriate to your system. The FLASH executable can take one command-line argument, the name of the runtime parameter file. The default parameter file name is flash.par. This is system-dependent and is not permitted by some machines (or MPI versions).

You should see a number of lines of output indicating that FLASH is initializing the Sedov problem, listing the initial parameters, and giving the timestep chosen at each step. After the run is finished, in the current directory you should find several files:

We will use the xflash routine under IDL to examine the output. Before doing so, we need to set the values of two environment variables, IDL_PATH and XFLASH_DIR. Under csh this can be done using the commands
setenv XFLASH_DIR "$PWD/tools/idl"
setenv IDL_PATH "${XFLASH_DIR}:$IDL_PATH"
If you get a message indicating that IDL_PATH is not defined, enter
setenv IDL_PATH "$XFLASH_DIR":idl-root-path
where idl-root-path points to the directory in which IDL is installed. Now run IDL (idl) and enter xflash at the IDL> prompt. You should see a control panel widget as shown in Figure 2. The path entry should be filled in for you with the current directory. Enter sedov_4_hdf_chk_ as the base filename and enter 4 as the suffix. (xflash can generate output for a number of consecutive files, but if you fill in only the beginning suffix, only one file is read.) Click the `Discover Variables' button to scan the file and generate the variable list. Choose the image format (screen, Postscript, GIF) and the problem type (in our case, Sedov). Selecting the problem type is only important for choosing default ranges for our plot; plots for other problems can be generated by ignoring this setting and overriding the default values for the data range and the coordinate ranges. Select the desired plotting variable and colormap. Under `Options,' select whether to plot the logarithm of the desired quantity, and select whether to plot the outlines of the AMR blocks. For very highly refined grids the block outlines can obscure the data, but they are useful for verifying that FLASH is putting resolution elements where they are needed. Finally, click `Velocity Options' to overlay the velocity field. The `xskip' and `yskip' parameters enable you plot only a fraction of the vectors so that they do not obscure the background plot.

When the control panel settings are to your satisfaction, click the `Plot' button to generate the plot. For Postscript and GIF output, a file is created in the current directory. The result should look something like Figure 2, although this figure was generated from a run with eight levels of refinement rather than the four used in the quick start example run. With fewer levels of refinement the Cartesian grid causes the explosion to appear somewhat diamond-shaped.

xflash_output.gif
Figure 2: Example of xflash output for the Sedov problem with eight levels of refinement.

FLASH is intended to be customized by the user to work with interesting initial and boundary conditions. In the following sections we will cover in more detail the algorithms and structure of FLASH and the sample problems and tools distributed with it.


Part 2
STRUCTURE


3  Overview of FLASH architecture

The FLASH source code is a collection of components called FLASH modules. FLASH modules can be combined in a variety of ways to form specific FLASH applications. Of course, not all available FLASH modules are necessarily used when solving any one particular problem. Thus, it is important to distinguish between the entire FLASH source code and a given FLASH application.

3.1  Structure of a FLASH module

Most generally, a FLASH module represents some well-defined, top-level unit of functionality useful for a given class of problems. Its structure conforms to a small set of rules that facilitate its interactions with other modules in the creation of an application. Primary among these are the rules governing the retrieval and modification of data on the solution grid. A module must also announce a general set of requirements to the framework as well as publish a public interface of its services. Here we focus on the internal structure of a FLASH module appropriate for users wishing to extend the current FLASH functionality.

First, it is important to recall how a selected group of FLASH modules is combined to form a particular application. This process is carried out entirely by the FLASH setup tool, which uses configuration information provided by the modules and problem setup to properly parse the source tree and isolate the source files needed to carry set-up a specific problem. For performance reasons, setup ties modules together statically before the application is compiled.

Each FLASH module is divided into three principal components:

a) Configuration layer
b) ``Wrapper'' or ``interface'' layer
c) Algorithm

Additionally, a module may contain sub-modules which inherit from and override the functionality in the parent module. Each of these components is discussed in detail in the following sections.

3.1.1  Configuration layer

Information about module dependencies, default sub-modules, runtime parameter definitions, library requirements, and so on is stored in plain text files named Config in the different module directories. These are parsed by setup when configuring the source tree and are used to create the code needed to register module variables, implement the runtime parameters, choose sub-modules when only a generic module has been specified, prevent mutually exclusive modules from being included together, and to flag problems when dependencies are not resolved by some included module. In the future they may contain additional information about module interrelationships.

3.1.1.1  Configuration file syntax  

The syntax of the configuration files is as follows. Arbitrarily many spaces and/or tabs may be used, but all keywords must be in uppercase. Lines not matching an admissible pattern are ignored. (Someday soon they will generate a syntax error.)

Config files also support the inclusion of special parameter comments. Any line in a Config file is considered a parameter comment line if it begins with #!. The first token after the comment line is taken to be the parameter name. The remaining tokens are taken to be the parameter's comment. A token is delineated by one or more white spaces. For example,
#! SOME_PARAMETER The purpose of this parameter is whatever

If the parameter comment requires additional lines the & is used as:
#! SOME_PARAMETER The purpose of this parameter is whatever
#! &              This is a second line

Parameter comment lines are special because they are used by setup to build a formatted list of commented runtime parameters for a particular problem setup. This information is generated in the file paramFile.html in the $FLASH_HOME directory. A file paramFile.txt is also generated.

3.1.2  Interface layer and database module

After the module Config and Makefile are written, the source code files that carry out the specific work of the modules must be added. These source files can be separated into two broad categories: what we term ``wrapper functions'' and ``algorithms.'' In this section we discuss how to construct wrapper functions.

When constructing a FLASH module the designer must define a public interface of procedures that the module exposes to clients (ie other modules in an application). This is true regardless of the specific development language or syntactic features chosen to organize the procedures. These public functions are then defined in one or more source code files that form what we refer to as the interface layer.

Currently, there is no language-level formality in FLASH for enforcing the distinction between the public interface and private module functions that the interface harnesses. The developer is certainly encouraged to implement this within the chosen development language - static functions in C; private class functions in C++; private subroutines in a Fortran module, etc. However, nothing in FLASH will force this distinction and carry out the associated name-hiding within an application.

The most important aspect of the interface/algorithm distinction is related to the rules for data access. Wrapper functions communicate directly with the FLASH database module to access grid data (see below). However, algorithms are not permitted to query the database module directly. Instead, they must receive all data via a formal function argument list. Thus, when a module A wishes to request the services of module B, A calls one of B's public wrapper functions. Rather than being required to pass all necessary data to B through a procedure argument list, B may ``pull'' data it needs access to from the Database, marshal it as necessary, call the module algorithm(s), receive the updated data, and update the database.

The following subsections describe the methods provided by the database module in more detail.

3.1.2.1  dBaseGetData/dBasePutData   



Usage 



  call dBaseGetData([variable, [direction, [q1, [q2, [q3,]]]]] block, storage)
  call dBasePutData([variable, [direction, [q1, [q2, [q3,]]]]] block, storage)



Description 



Data exchange with grid variables. All variables registered with the framework via the VARIABLE keywords within a module Config file can be read/written with this pair of functions. The data is assumed to be composed of one or more structured blocks each with an integer block id = [1,num_blocks], where num_blocks is the total number of blocks on a given processor.



Example 



Given a Config file with the following variable registration specification:

  VARIABLE dens

the variable dens can be accessed from within FLASH as, for example:

  real, dimension(nxb,nyb,nzb) :: density
  do this_block = 1, total_blocks
    call dBaseGetData("dens", this_block, density)
    call foo(density)
  end do



Arguments 



character integer variable Variable name; if given as string it should match Config description; if not present all variables will be exchanged
character integer direction Specifies the shape of the data and how q1, q2, q3 should be interpreted; if not present whole variable will be exchanged
integer q1, q2, q3 Coordinated of data exchanged in order i-j-k; for vectors (q1,q2) = (i,j), (j,k), or (i,k)
integer block Integer block ID on a given processor specifying the patch of data to access
real
storage
storage(:)
storage(:,:)
storage(:,:,:)
Allocated storage to receive result. Rank and shape of the storage array should match the rank and shape of data taken or put



Strings 



direction = {``xyPlane¢¢
``xzPlane¢¢
``yzPlane¢¢
``yxPlane¢¢
``zxPlane¢¢
``zyPlane¢¢
``xVector¢¢
``yVector¢¢
``zVector¢¢
``Point¢¢



Integers 



Integers for variables and directions are not publicly available, but can be accessed through dBaseKeyNumber().



Note 



The ``xyzCube'' keyword is obsolete. When direction keyword is not specified, whole variable will be exchanged. When, in addition, variable keyword is omitted all variables for the block will be exchanged.

3.1.2.2  dBaseGetCoords/dBasePutCoords   



Usage 



  call dBaseGetCoords(variable, direction, [q,] block, storage)
  call dBasePutCoords(variable, direction, [q,] block, storage)



Description 



Access global coordinate information for a given block, including ghost points.



Example 



  real, DIMENSION(block_size) :: xCoords, data
  do i = 1, lnblocks
    call dBaseGetCoords("zn", "xCoord", i, xCoords)
    call dBaseGetData("dens", "xVector", 0, 0, i, data)
    call foo(data,xCoords)
  enddo



Arguments 



character integer variable Specifies position of coord relative to block: left, right, or center (see below)
character integer directionSpecifies x-, y-, or z-coordinate
integer q Allows to get/put a single point
integer block Integer block ID on a given processor specifying the patch of data to access
real
storage
storage(:)
Allocated storage to receive result



Strings 



direction = { ``xCoord¢¢
``yCoord¢¢
``zCoord¢¢ coord position = { ``znl¢¢: left block boundary
``zn¢¢: block center
``znr¢¢: right block boundary
``znl0¢¢: ??
``znr0¢¢: ??
``ugrid¢¢: ??



Integers 



Integers for variables and directions are not publicly available, but can be accessed through dBaseKeyNumber().

3.1.2.3  dBaseGetBoundaryFluxes/dBasePutBoundaryFluxes   



Usage 



  call dBaseGetBoundaryFluxes(position, direction, block, storage)
  call dBasePutBoundaryFluxes(position, direction, block, storage)



Description 



Access boundary fluxes for all flux variables on a specified block associated with a given time-level. Currently, only the current and previous time-step are supported.



Example 



  real, dimension(nfluxes,ny,nz): xl_bound_fluxes, xr_bound_fluxes
  do this_block = 1, num_blocks
    call dBaseGetBoundaryFluxes(0,0,"xCoord", this_block, xl_bound_fluxes)
    call dBaseGetBoundaryFluxes(0,1,"xCoord", this_block, xr_bound_fluxes)
    call foo(xl_bound_fluxes, xr_bound_fluxes)
    call dBasePutBoundaryFluxes(0,0,"xCoord",this_block,xl_bound_fluxes)
    call dBasePutBoundaryFluxes(0,1,"xCoord",this_block,xl_bound_fluxes)
  end do



Arguments 



integer time_context Specifies fluxes stored at current or previous time-step
integer position Specifies left or right boundary in a given direction
characterdirection Specifies x-, y-, or z-coordinate
integer block Integer block ID on a given processor specifying the patch of data to access
real storage(:,:,:)Return buffer of size nFluxes * dim1 * dim2



Strings 



direction = { ``xCoord¢¢
``yCoord¢¢
``zCoord¢¢



Integers 



time_context = { -1 (previous time-step)
0 (current time-step) position = {0 (left)
1 (right)

3.1.2.4  dBaseKeyNumber   



Usage 



  result = dBaseKeyNumber(keyname)



Description 



For faster performance, dBase{Get,Put}{Data,Coords} can be called with integer arguments instead of strings. Each of the string arguments accepted by the Get/Put methods can be replaced by a corresponding integer. However, these integers are not publicly available. To obtain them, one must call dBaseKeyNumber().



Example 



  integer :: idens, ixCoord
  idens   = dBaseKeyNumber("dens")
  ixCoord = dBaseKeyNumber("xCoord")
  call dBasePutData(idens, ixCoord, block_no, data)



Arguments and return type 



character keyname String with ``variable'' or ``direction'' name, as in get/put data/coords; names of variables must match Config description
integer dBaseKeyNumber Integer assigned for the string key name



Strings 

keyname = { ``xyzCube¢¢
``xyPlane¢¢
``xzPlane¢¢
``yzPlane¢¢
``yxPlane¢¢
``zxPlane¢¢
``zyPlane¢¢
``xVector¢¢
``yVector¢¢
``zVector¢¢
``Point¢¢
``RefineVariable1''
``RefineVariable2''
``RefineVariable3''
``RefineVariable4''
``xCoord''
``yCoord''
``zCoord''

``OldTemp''
``Shock''
``znl''
``zn''
``znr''
``znl0''
``znr0''
``ugrid''

``rhoflx''
``uflx''
``utflx''
``uttflx''
``pflx''
``eflx''
``eintflx''
``nucflx_begin''
Typically, the call to dBaseKeyNumber is performed once, in a firstcall block at the top of a routine. The integer that stores the result will be declared with the FORTRAN save keyword, so the key value is valid on subsequent entries to the routine.

3.1.2.5  dBaseSpecies    



Usage 



  result = dBaseSpecies(index)



Description 



Maps species number (from one to maximum number of species) to variable number (actual index in ``unk'' array).



Arguments and return type 



integer index Species number from one to maximum number of species
integer dBaseSpecies Actual index in ``unk'' array

At present, all of the species are stored with adjacent indices in the solution array, thus one can find the index of the first isotope with a call to dBaseSpecies(1), and increment this value by 1 to get the next species.

3.1.2.6  dBaseVarName    



Usage 



  result = dBaseVarName(keynumber)



Description 



Given a key number, return the associated variable name.



Example 



  integer       :: idens
  char(len = 4) :: name
  idens = dBaseKeyNumber("dens")
  name  = dBaseVarName(idens)     ! name now = "dens"



Arguments and return type 



integer keynumber Variable keynumber obtained with call to dBaseKeyNumber
character(len = 4) dBaseVarName String name of variable as defined in Config; if variable does not exist returns ``null''

3.1.2.7  dBasePropertyInteger   



Usage 



  result = dBasePropertyInteger(property)



Description 



Accessor methods for integer-valued scalar variables.



Arguments and return type 



character property String with variable name, see below
integer dBasePropertyInteger Property value



Strings 



property = {
``Dimensionality¢¢
Dimensionality of problem defined at setup
``NumberOfVariables¢¢
Total number of solution variables defined
``NumberOfSpecies¢¢
Number of nuclear species defined
``NumberOfGuardCells¢¢
Width of ghost-cell region on each boundary of a block
``NumberOfFluxes¢¢
Total number of fluxes defined
``NumberOfNamedVariables¢¢
Total number of solution variables excluding nuclear abundances
``NumberOfAdvectVariables¢¢
Total number of variables with the ADVECT attribute
``NumberOfRenormVariables¢¢
Total number of variables with the RENORM attribute
``NumberOfConserveVariables¢¢
Total number of variables with the CONSERVE attribute for a given problem
``MaxNumberOfBlocks¢¢
Total number of allocated blocks on a given processor. May exceed the number of blocks currently defined in the AMR hierarchy, since block memory is allocated statically.
``LocalNumberOfBlocks¢¢
Total number of blocks on a given processor
``MaxBlocks_tr¢¢
Statically allocated buffer size for work arrays
``NumberOfGuards_work¢¢
Guardcells for scratch array
``xDimensionExists¢¢
Value of 1 if x-dimension is defined for given problem, 0 otherwise
``yDimensionExists¢¢
Value of 1 if y-dimension is defined for given problem, 0 otherwise
``zDimensionExists¢¢
Value of 1 if z-dimension is defined for given problem, 0 otherwise
``xBlockSize¢¢
Number of zones in x-direction for AMR blocks, excluding ghost zones
``yBlockSize¢¢
Number of zones in y-direction for AMR blocks, excluding ghost zones
``zBlocksize¢¢
Number of zones in z-direction for AMR blocks, excluding ghost zones
``xLowerBound¢¢
Beginning x-index of a block (including ghost zones)
``yLowerBound¢¢
Beginning y-index of a block (including ghost zones)
``zLowerBound¢¢
Beginning z-index of a block (including ghost zones)
``xUpperBound¢¢
Ending x-index of a block (including ghost zones)
``yUpperBound¢¢
Ending y-index of a block (including ghost zones)
``zUpperBound¢¢
Ending z-index of a block (including ghost zones)
``CurrentStepNumber¢¢
Current time-step number
``BeginStepNumber"
Initial time-step number
``MyProcessor¢¢
Local processor ID assigned by MPI
``MasterProcessor¢¢
Master processor ID
``NumberOfProcessors¢¢
Total number of processors

3.1.2.8  dBasePropertyReal   



Usage 



  result = dBasePropertyReal(property)



Description 



Accessor methods for real-valued scalar variables.



Arguments and return type 



character property String with variable name, see below
integer dBasePropertyReal Property value



Strings 



property = {
``Time¢¢
Current value of the simulation time
``TimeStep¢¢
Current value of the simulation timestep

3.1.2.9  dBaseSetProperty   



Usage 



  call dBaseSetProperty(property, value)



Description



Mutator methods for writeable scalar variables. See dBasePropertyInteger/Real for documentation on property names.



Arguments



character property String with variable name
integer real value New property value



Strings



property = { ``CurrentStepNumber¢¢ ``BeginStepNumber¢¢ ``MyProcessor¢¢ ``MasterProcessor¢¢ ``NumberOfProsessors¢¢ ``Time¢¢ ``TimeStep¢¢

3.1.2.10  dBaseVarIndex   



Usage



  result = dBaseVarIndex(property)



Description



Returns pointer to array of integer keys of variables with specified property.



Arguments and return type



character property String with property name, see below
integer, POINTER, DIMENSION(:) dBaseVarIndex Pointer to array of unk indices of variables with given property



Strings



property = { ``advect¢¢ ``renorm¢¢ ``conserve¢¢

3.1.2.11  Various pointer-returning functions   

Each of these functions allows FLASH developers to hook directly into an internal data structure in the database. In general these functions will offer better performance then their corresponding dBaseGet/Put counterparts, and will require less memory overhead. However, the interfaces are more complicated and the functions are less flexible, and less safe, so it is suggested that developers strongly consider using dBaseGet/PutData when performance differences are small.

Each function returns a Fortran 90 pointer to the solution vector on the specified block. If no block is specified, a pointer is returned to all blocks on the calling processor. Currently the array index layout is assumed to be (var,nx,ny,nz,block) in row-major ordering. The scratch (unksm) array stores variables with no guardcells; this name should probably be changed in the future.



Argument and return type



integer block
real, DIMENSION( :,:,:,:,: ), POINTER dBaseGetDataPtrAllBlocks
real, DIMENSION( :,:,:,: ), POINTER dBaseGetDataPtrSingleBlock
real, DIMENSION( :,:,: ), POINTERdBaseGetPtrToXCoords
real, DIMENSION( :,:,: ), POINTERdBaseGetPtrToYCoords
real, DIMENSION( :,:,: ), POINTERdBaseGetPtrToZCoords
real, DIMENSION( :,:,:,:,: ), POINTER dBaseGetScratchPtrAllBlocks
real, DIMENSION( :,:,:,: ), POINTER dBaseGetScratchPtrSingleBlock

3.1.2.12  dBaseGetDataPtrAllBlocks()   



Return an F90 pointer to the left-hand-side solution vector for all blocks on a given processor, arranged in row-major order as: (var,nx,ny,nz,block). dBaseKeyNumber must still be called to access the elements of the array.

3.1.2.13  dBaseGetDataPtrSingleBlock(block_no)   



Return an F90 pointer to the left-hand-side solution vector on a specified block, arranged as (var,nx,ny,nz).

3.1.2.14  dBaseGetPtrToXCoords()   



Return an F90 pointer to an array containing information on the x-coordinates of the AMR blocks. The array returned is arranged as (block_position, i, block_number), where block_position values denote center, left, or right coordinates, and are obtained by calling dBaseKeyNumber with ``zn'', ``znl'', ``znr'' and using the corresponding index to access the approriate row in the array. For example:

  real, pointer, dimension(:,:,:) :: xCoords
  real                            :: x, xl, xr
  integer                         :: izn, iznl, iznr
  izn  = dBaseKeyNumber("izn")
  iznl = dBaseKeyNumber("iznl")
  iznr = dBaseKeyNumber("iznr")
  xCoord => dBaseGetPtrToXCoords()
  do this_block = 1, num_blocks
    do i = 1, blocksize
      x  = xCoord(izn, i, this_block)     ! get first center coord
      xl = xCoord(iznl, i, this_block)    ! get first left coord
      xr = xCoord(iznr, i, this_block)    ! get first right coord
      ...
    enddo
  enddo

3.1.2.15  dBaseGetPtrToYCoords()   



See dBaseGetPtrToXCoords().

3.1.2.16  dBaseGetPtrToZCoords()   



See dBaseGetPtrToXCoords().

3.1.2.17  dBaseGetScratchPtrAllBlocks()   



Return an F90 pointer to a scratch array of size (2, nxb, nyb, nzb, maxblocks).

3.1.2.18  dBaseGetScratchPtrSingleBlock(block_no)   



Return an F90 pointer to a scratch array of size (2, nxb, nyb, nzb).

3.1.2.19  AMR tree interface functions    These functions enable FLASH developers to directly access the data structures used by PARAMESH to describe the adaptive mesh. In general they should not be needed by developers of physics modules. Also, they may not be available in future versions of FLASH.



Arguments and return types



integer block
real, DIMENSION (mfaces) dBaseNeighborBlockList
real, DIMENSION (mfaces) dbaseNeighborBlockProcList
real, DIMENSION (mchild) dBaseChildBlockList
real, DIMENSION (mchild) dBaseChildBlockProcList
real dBaseParentBlockList
real dBaseParentBlockProcList
integer dBaseRefinementLevel
integer, DIMENSION (nfaces)dbaseNeighborType
real, DIMENSION (mdim) dBaseBlockCoord
real, DIMENSION (mdim) dBaseBlockSize
integer dBaseNodeType
logical dBaseRefine
logical dBaseDeRefine



dBaseNeighborBlockList (block)

Given a block ID, return an array of block ID's which are the neighbors of the specified block. The returned array is of size max_faces = 6, but not all of the six elements will have meaningful values if the problem is run in fewer than three dimensions. Assuming the function is called as NEIGH = dBaseNeighborBlockList(), the ordering is as follows. The neighbor on the lower x face of block L is at NEIGH(1,L), the neighbor on the upper x face at NEIGH(2,L), the lower y face at NEIGH(3,L), the upper y face at NEIGH(4,L), the lower z face at NEIGH(5,L), and the upper z face at NEIGH(6,L). If any of these values are set to -1 or lower, there is no neighbor to this block at its refinement level. However there may be a neighbor to this block's parent. If the value is -20 or lower then this face represents an external boundary, and the user is required to apply some boundary condition on this face. The exact value below -20 can be used to distinguish between the different boundary conditions which the user may wish to implement.



dbaseNeighborBlockProcList (block)

Given a block ID, return an array of size max_faces = 6 elements containing processor ID's identifying the processor that a given neighbor resides on. Ordering is identical to dBaseNeighborBlockList().



dBaseChildBlockList (block)

Given a block ID, return an array of size max_child = 2 * max_dim elements containing the block ID's of the child blocks of the specified block. The children of a parent are numbered according to the Fortran array ordering convention, ie. child 1 is at the lower x, y, and z corner of the parent, child 2 at the higher x coordinate but lower y and z, child 3 at lower x, higher y and lower z, child 4 at higher x and y and lower z, and so on.



dBaseChildBlockProcList (block)

Given a block ID, return an array of size max_child elements containing processor ID's of the children of the pecified block. Ordering is identical to dBaseChildBlockList().



dBaseParentBlockList (block)

Given a block ID, return the ID of the block's parent block.



dBaseParentBlockProcList (block)

Given a block ID, return the processor ID upon which the block's parent resides.



dBaseRefinementLevel (block)

Given a block ID, return that block's integer level of refinement.



dBaseNodeType (block)

Given a block ID, return the block's node type. If 1 then the node is a leaf node, if 2 then the node is a parent but with at least 1 leaf child, otherwise it is set to 3 and it does not have any up-to-date data.



dbaseNeighborType (block)

Given a block ID, return an array of size (mfaces, maxblocks_tr), containing the type ID's of the neighbors of the specified block. mfaces = mdim * 2, where mdim is the maximum possible dimensionality (3).



dBaseBlockCoord (block)

Given a block ID, return an array of size ndim containing the x,y,z coordinates of the center of the block.



dBaseBlockSize (block)

Given a block ID, return an array of size ndim containing the block size in the x, y, and z directions.



dBaseRefine (block)

Given a block ID, return .true. if that block is set for refinement in the next call to amr_refine_derefine(), and .false. otherwise.



dBaseDeRefine (block)

Given a block ID, return .true. if that block is set for refinement in the next call to amr_refine_derefine(), and .false. otherwise.

3.1.3  Algorithms

Within each module are one or more procedures which perform the bulk of the computational work for the module. A principal strategy behind the FLASH architecture is to decouple these procedures as much as possible from the details of the framework in which they are embedded. This is accomplished by requiring that all module algorithms communicate data only through function argument lists. That is, algorithms may not query the database directly nor may they depend on the existence of externally defined or global variables. This design ensures that algorithms can be tested, developed, and interchanged in complete isolation from the larger, more complicated framework.

Thus, each algorithm in a module should have a well defined argument list. It is up to the algorithm developer to make this as general or restrictive as he/she sees fit. However, it is important to keep in mind that, the more rigid the argument list, the less chance that another algorithm can share its interface. The consequence is that the developer would have to add an entirely new wrapper function for just slightly different functionality.

3.2  The FLASH source tree

An abstract representation of the FLASH architecture appears in Figure 3. Each box in this figure represents a component (FLASH module), which publishes a small set of public methods to its clients. These public methods are expressed through virtual function definitions (stubs under Fortran 90), which are implemented by real functions supplied by sub-modules. Typically each component represents a different class of solver. For time-dependent problems, the driver uses time-splitting techniques to compose the different solvers. The solvers are divided into different classes on the basis of their ability to be composed in this fashion and upon natural differences in solution method (e.g., hyperbolic solvers for hydrodynamics, elliptic solvers for radiation and gravity, ODE solvers for source etc.).

flash_arch_3.png
Figure 3: Abstract representation of the FLASH architecture.

The adaptive mesh refinement module is treated in the same way as the solvers. The means by which the driver shares data with the solver objects is the primary way in which the architecture affects the overall performance of the code. Choices here, in order of decreasing performance and increasing flexibility, include global memory, argument-passing, and messaging. FLASH 2.0 has eliminated global variable access in favor of a well-defined set of accessor and mutator methods managed by the centralized database module. When done with an eye toward optimization, the effects on performance are tolerable, and the benefits for maintainability and extensibility are significant. This is discussed in greater detail below.

3.2.1  Code infrastructure

The structure of the FLASH source tree reflects the module structure of the code, as shown in Figure 4 for an older version of FLASH. The general plan is that source code is organized into one set of directories, while the code is built in a separate directory using links to the appropriate source files. The links are created by a source configuration script called setup, which makes the links using options selected by the user and then creates an appropriate makefile in the build directory. The user then builds the executable with a single invocation of gmake.

flash_dirs_3.gif
Figure 4: Directory structure of FLASH 1.62. The directory structure for FLASH 2.0 is similar.

Source code for each of the different code modules is stored in subdirectories under source/. The code modules implement different physics, such as hydrodynamics, nuclear burning, and gravity, or different major program components, such as the main driver code and the input/output code. Each module directory contains source code files, makefile fragments indicating how to build the module, and a configuration file (see Section 6.1.2).

Each module subdirectory may also have additional sub-module directories underneath it. These contain code, makefiles, and configuration files specific to different variants of the module. For example, the hydro/ module directory can contain files which are generic to hydrodynamical solvers, while its explicit/ subdirectory contains files specific to explicit hydro schemes and its implicit/ subdirectory contains files specific to implicit solvers. Configuration files for other modules which need hydrodynamics can specify hydro as a requirement without mentioning a specific solver; the user can then choose one solver or the other when building the code (via the modules file; Section 6.1.3). When setup configures the source tree it treats each sub-module as inheriting all of the source code, configuration files, and makefiles in its parent module's directory, so generic code does not have to be duplicated. Sub-modules can themselves have sub-modules, so for example one might have hydro/explicit/split/ppm and hydro/implicit/ppm. Source files at a given level of the directory hierarchy override files with the same name at higher levels, whereas makefiles and configuration files are cumulative. This permits modules to supply stub routines that are treated as `virtual functions' to be overridden by specific sub-modules, and it permits sub-module directories to be self-contained.

When a module is not explicitly included by Modules, only one thing is done differently by setup: sub-modules are not included, except for a null sub-module, if it is present. Most top-level modules should contain only stub files to be overridden by sub-modules, so this behavior allows the module to be `not included' without extra machinery (such as the special stub files and makefiles required by earlier versions of FLASH). In those cases in which the module's files are not appropriate for the `not included' case, the null sub-module allows one to override them with appropriate versions.

New solvers and new physics can be added. At the current stage of development of FLASH it is probably best to consult the authors of FLASH (see Section 7) for assistance in this. Some general guidelines for adding solvers to FLASH 2.0 may be found in Section 17.

The setups/ directory has a structure similar to that of source/. In this case, however, each of the "modules" represents a different initial model or problem, and the problems are mutually exclusive; only one is included in the code at a time. Also, the problem directories have no equivalent of sub-modules. A makefile fragment specific to a problem need not be present, but if it is, it is called Makefile. Section 16 describes how to add new problem directories.

The setup script creates a directory called object/ in which the executable is built. In this directory setup creates links to all of the source code files found in the specified module and sub-module directories as well as the specified problem directory. (A source code file has the extension .c, .C, .f, .f90, .F90, .F, .fh, or .h.) Because the problem setup directory and the machine-dependent directory are scanned last, links to files in these directories override the ``defaults'' taken from the source/ tree. Hence special variants of routines needed for a particular problem can be used in place of the standard versions by simply giving the files containing them the same names.

Using information from the configuration files in the specified module and problem directories, setup creates a file named init_global_parms.F90 to parse the runtime parameter file and initialize the runtime parameter database. It also creates a file named rt_parms.txt, which concatenates all of the PARAMETER statements found in the appropriate configuration files and so can be used as a ``master list'' of all of the runtime parameters available to the executable.

setup also creates makefiles in object/ for each of the included modules. Each copy is named Makefile.module, where module is driver, hydro, gravity, and so forth. Each of these files is constructed by concatenating the makefiles found in each included module path. So, for example, including hydro/explicit/split/ppm causes Makefile.hydro to be generated from files named Makefile in hydro/, hydro/explicit/, hydro/explicit/split/, and hydro/explicit/split/ppm/. If the module is not explicitly included, then only hydro/Makefile is used, under the assumption that the subroutines at this level are to be used when the module is not included. The setup script creates a master makefile (Makefile) in object/ which includes all of the different modules' makefile fragments together with the site- or operating system-dependent Makefile.h.

The master Makefile created by setup creates a temporary subroutine, buildstamp.F90, which echoes the date, time, and location of the build to the FLASH log file when FLASH is run. To ensure that this subroutine is regenerated each time the executable is linked, the Makefile deletes buildstamp.F90 immediately after compiling it.

The setup script can be run with the -portable option to create a directory with real files which can be collected together with tar and moved elsewhere for building. In this case the build directory is assigned the name object_problem/. Further information on the options available with setup may be found in Section 13. .

Additional directories included with FLASH are tools/, which contains tools for working with FLASH and its output (Sec:FLASH output comparison utility), and docs/, which contains documentation for FLASH (including this user's guide) and the PARAMESH library.

3.3  Modules included with FLASH: a brief overview

The current FLASH distribution comes with a set of core components that form the backbone of many common problems, namely: database, driver, hydro, io, mesh, particles, source_terms, gravity, and materials. A detailed discussion of the role of each of these modules is presented in Part IV. Here we give a brief overview of each.

Section 4 describes in detail the various driver modules which may be implemented with FLASH. In addition to the default driver, which controls the initialization, evolution, and output of a FLASH simulation, four new driver modules have been written to implement different explicit time advancement algorithms. Three are written in the delta formulation: euler1, rk3, and strang_delta. The fourth, strang_state, is written in the state-vector formulation. A subsection concerning simulation services, runtime parameters, and logfiles is also included in this section.

Section 5 describe the FLASH I/O modules, which control how FLASH data structures are stored on different platforms and in different formats. Discussed in this section are the main I/O module hdf4, which uses the Hierarchical Data Format (HDF) for storing simulation data, two major HDF5 modules (serial and parallel versions), and Fortran 77 (f77) modules.

Section 6 describes the mesh module, together with the PARAMESH package of subroutines for the parallelization and adaptive mesh refinement (AMR) portion of FLASH.

Section 7 describes the two hydrodynamic modules included in FLASH 2.x. The first is based on the PROMETHEUS code (Fryxell, Müller, and Arnett 1989); the second is based on Kurganov numerical methods.

Section 8 describes the magnetohydrodynamics module included with the FLASH code, which solves the equations of ideal MHD.

Section 9 discusses the material properties module, which handles the tracking of multiple fluids in FLASH simulations. It includes the equation of state module, which implements the EOS for the hydrodynamical and nuclear burning solvers; the composition submodule, which sets up the different compositions needed by FLASH; and the stellar conductivity module, which may be used for computing the opacity of stellar material. Section describes source terms, including the nuclear burning module, which calculates the nuclear burning rate of a hydrodynamical simulation, and the stirring module, which adds a divergence-free, time-correlated `stirring' velocity at selected modes in a given hydrodynamical simulation.

Section 11 describes the gravity module, which computes gravitational potential or gravitational acceleration source terms for the code. It includes several sub-modules: the constant submodule, the plane parallel sub-module, the ptmass submodule, and the Poisson submodules.


Part 3
MODULES


4  Driver modules

The driver module controls the initialization, evolution, and output of a FLASH simulation. Initialization can be from scratch or from a stored checkpoint file. Evolution can use any of several different operator-splitting techniques to combine different physics operators and integrate them in time, or call a single operator if the problem of interest is not time-dependent. Output involves the production of checkpoint files, plot files, analysis data, and log file time stamps. In addition to these functions, the driver supplies important simulation services to the rest of the FLASH framework, including Fortran modules to handle runtime parameters, physical constants, memory usage reports, and log file management (these are discussed further in Section ).

The initialization and termination routines and simulation services modules are common to both time-dependent and time-independent drivers and thus are included at the highest level of driver. The file flash.F90 contains the main FLASH program (equivalent to main() in C) and calls these routines as needed. The default flash.F90 is empty and is intended to be overridden by submodules of driver. At this time only time-dependent drivers are supplied with FLASH; these are submodules of the driver/time_dep module. The time_dep version of flash.F90 calls the FLASH initialization routine, loops over timesteps, and then calls the FLASH termination routine. During the time loop it computes new timesteps, calls an evolution routine (evolve()), and calls output routines as necessary.

The details of each available time integration method are completely determined by the version of evolve() supplied by that method. The default time update method is to call each physics module's update routine for two equal timesteps - thus, hydro, source terms, gravity, hydro, source terms, gravity. The hydrodynamics update routines take a ``sweep order'' argument in case they are directionally split; in this case, the first call uses the ordering x-y-z, and the second call uses z-y-x. Each of the update routines is assumed to directly modify the solution variables. At the end of each pair of timesteps, the condition for updating the mesh refinement pattern is tested, and a refinement update is carried out if required.

The alternative ``delta formulation'' drivers (driver/time_dep/delta_form) modify a set of variables containing the change in the solution during the timestep. The change is only applied to the solution variables after all operators have been invoked. This technique permits more general time integration methods, such as Runge-Kutta methods, to be employed, and it provides a more flexible method for composing operators. However, only a few physics modules can make use of it as yet. More details on the delta formulation drivers appear in Section 4.1.

The driver module supplies certain runtime parameters regardless of which type of driver is chosen. These are described in Table 1.

Table 1: driver module parameters.
Parameter Type Default Description
Table 2: driver module parameters (continued).
Parameter Type Default Description
nend integer 100 Maximum number of timesteps to take before halting the simulation
restart boolean .false. Set to .true. to restart the simulation from a checkpoint file
run_number string ``'' Identification number for run
run_commentstring ``'' Identifying comment for run
log_file string ``flash.log'' Name of log file
tmax real 1 Maximum simulation time to advance before halting the simulation
dtini real 10-10 Initial timestep
dtmin real 10-10 Minimum timestep
dtmax real 105 Maximum timestep
small real 10-10 Generic small cutoff value for dimensionless positive definite quantities
smlrho real 10-10 Cutoff value for density
smallp/e/t/u/x real 10-10 Cutoff values for pressure, energy, temperature, velocity, and advected abundances
x/y/zmin real 0 Minimum x, y, and z coordinates for grid
x/y/zmax real 1 Maximum x, y, and z coordinates for grid
igeomx/y/zinteger 0 Grid geometry in x, y, and z directions: 0=Cartesian/planar; 1=radial (cylindrical); 2=radial (spherical); 3=polar (cylindrical); 4=polar (spherical); 5=azimuthal (spherical). Types 3, 4, 5 are not yet supported in FLASH.
igrav integer 0 If set to 1, use gravity
iburn integer 0 If set to 1, use nuclear burning
iheat integer 0 If set to 1, use heating processes
icool integer 0 If set to 1, use cooling processes

4.1  New driver modules euler1, rk3, and strang_delta

New driver modules have been written to implement different explicit time advancement algorithms. This usage of the driver modules is slightly different than that of the default driver module, which does not directly implement a time advancement algorithm; the default driver and hydro modules each implement parts of the Strang splitting time advancement. First, a listing of the time advancement tasks common to all of the new drivers will be given. In following subsections, the details of each time advancement method will be described.

The three driver modules written in the delta formulation are euler1, rk3, and strang_delta. They make appropriate calls to the physics modules, and update the solution by calling functions provided by the formulation module. The strang_state driver is written in the state-vector formulation; it also calls the physics modules, but does not update the solution. To use the new modules, first choose the driver by including one of the following lines into the Modules file.

/driver/time_dep/delta_form/euler1
/driver/time_dep/delta_form/rk3
/driver/time_dep/delta_form/strang_delta
/driver/time_dep/delta_form/strang_state
The time advancement module determines which formulation module should be used; two instantiations are possible. For euler1, rk3, or strang_delta, specify
/formulation/delta_form
but for strang_state specify
/formulation
The services provided by the formulation module for the delta formulation are a superset of those provided for the state-vector formulation, which explains the directory structure used. For both instantiations, the formulation module contains (i) subroutines for updating the conserved and auxiliary variables locally (on a block or face of a block), given a local Lphysics(U), and (ii) a parameter which declares which formulation is being used. For the delta formulation, the module also (iii) declares the global DU array and contains subroutines for accessing it, and (iv) provides a subroutine to update the variables globally.

For delta formulation time advancements, the new driver modules use the formulation module to hold and access the global DU array, and to update the solution. In the state-vector formulation, the formulation module is not directly used by the driver; instead, the physics modules call the update subroutines the formulation module provides.

The new driver modules discretize the left-hand side of
 V

t
= (spatial difference terms)+ (source terms).
(3)
The time advancement algorithm is contained in a subroutine named evolve. Each call to evolve advances the solution through one time step, Dt. Each time advancement algorithm begins with a vector of primary variables, Vn at time tn, and an associated set of auxiliary variables, Wn. Primarily through calls to other physics modules, evolve applies a set of operations to the variables to produce an updated vector, Vn+1 at time tn+1 = tn + Dt. Depending on the formulation, the time advancement may or may not update the auxiliary variables - in the state-vector formulation, the other physics modules update them.

The distinction between V and W is that time-dependent differential equations are solved to determine the primary variables. The auxiliary variables are obtained from the primary variables through algebraic relations. Often the primary variables are the conserved variables, U, and in the rest of this section U will replace V. However, the time advancement algorithms implemented do not require this correspondence.

The time advancement algorithms are written generally, in that each differential equation is treated in the same way. The distinction between the equations (for example, between the x-momentum equation and the total energy equation) is expressed in the other physics modules. The time advancement algorithm does not need to know the identity of the variables on which it operates, except possibly to update the auxiliary variables from the primary variables; but this update is handled by a call to a subroutine provided by the formulation module.

4.1.1  The euler1 module

The euler1 module implements the first-order, Euler explicit scheme:
Un+1 = Un + Dt L(Un)
(4)
where L(U) represents all of the physics modules. The euler explicit method is implemented in the delta formulation. No runtime parameters are defined for this module.

At the beginning of a time step, DU is set to zero. Each of the physics modules is called, with Un as the initial state, and adds its contribution to DU. After all the physics modules have been called, the global DU array holds L(Un). Equation (4) yields Un+1. Finally, the auxiliary variables are updated from the conserved variables with a call to the global update subroutine provided by the formulation module.

Note that because all the physics modules start with the same initial state, the order in which the physics modules are called does not affect the results (except possibly through floating point roundoff differences when contributing to DU.)

The set of steps, consisting of calls to physics modules, updating the conserved variables, and updating the auxiliary variables, is often called a stage. The majority of the computational cost of a stage is the in the calls to the other physics modules; this component corresponds to a ``function evaluation'' for ordinary differential equation solvers. In the Euler explicit algorithm, there is one stage per time step.

4.1.2  The rk3 module

Runge-Kutta schemes are a class ordinary differential equation solvers which are appreciated for their higher order of accuracy, ease of implementation, and relatively low storage requirements. There are many third-order Runge-Kutta methods; all require at least three stages. Most require at least three storage locations per primary variable, but the one implemented in the delta formulation in FLASH, derived by Williamson (J. Comp. Phys. 35:48, 1980) requires only two.

The two storage registers will be referred to as U and DU. The global solution vector, U, holds Un at the beginning of the time step, then intermediate solutions U(·) at the end of each stage. The manipulation of the global DU array is more complicated. DU accumulates contributions from the physics modules during a stage, but it also holds results from previous stages; it is important to distinguish between the results of the physics modules, L(U), and the quantity held in the global DU array. First the algorithm will be shown; then the usage of the global DU array will be discussed. For the equation
 U

t
= L(U),
(5)
Williamson's algorithm is, starting with Un,
U(1)
=
Un +  1

3
Dt é
ë
L(Un) ù
û
(6)
U(2)
=
U(1) +  15

16
Dt é
ë
L(U(1)) -  5

9
L(Un) ù
û
(7)
Un+1 = U(3)
=
U(2) +  8

15
Dt é
ë
L(U(2)) -  153

128
æ
è
L(U(1)) -  5

9
L(Un) ö
ø
ù
û
.
(8)
U(m) is the result of the m-th stage, and the auxiliary variables are updated each time a new U(m) is computed.

The algorithm is implemented using the following steps to attain the low storage. At the beginning of the time step, DU is set to zero. During the first stage each physics module contributes to DU, so after all have contributed, DU holds the bracketed term in eq. (6), L(Un). U(1) is then computed using eq. (6). Stage 1 is completed by multiplying DU by -5/9, which is required for the following stages. The process is repeated for stage 2: after the physics modules have contributed, DU holds the bracketed term in eq. (7); U(2) is computed by eq. (7) and stored in U; then DU is multiplied by -153/128. Stage 3 is similar, but ends after U(3) = Un+1 is computed and stored. It is critical that the only changes made to the DU array are those just listed; no physics module should change the value of DU, except to add its contribution, and since DU holds information from previous stages, it should not be reset to zero except at the beginning of the time step.

No runtime parameters are defined for this module.

4.1.3  strang_state and strang_delta modules

The second-order accurate splitting method (Strang 1968) is attractive because of its low memory requirements. The algorithm is based on the operator splitting approach, in which a set of subproblems is solved rather a single complicated problem. Each subproblem typically accounts for one term in a system of partial differential equations, representing a particular type of physics and for which an appropriate (specialized) numerical method is available. The basic operator splitting method is first-order accurate, but the Strang splitting scheme is second-order accurate over two time steps. In the first time step, the subproblems are solved in a given sequence. Second-order accuracy is obtained by reversing the sequence in the second time step.

A key feature of the operator splitting approach is that the output of one subproblem is the input to the next subproblem. This allows an implementation that, globally, stores only th