Overview of Flash-X architecture

Flash-X is a component based software system where different permutations and combinations of various components generate different applications. Some aspects of Flash-X architecture are adapted from FLASH , but it is fundamentally a new software with an architecture designed for use with heterogeneous platforms. Portability on heterogeneous platforms is achieved through a new orchestration system for applications (ORCHA) that is designed to be language agnostic and adaptable for future changes in the computing platforms. ORCHA has a collection of tools that address three main major concerns from the applications perspective described below.

As mentioned earlier Flash-X is not a monolithic application code; instead, it should be viewed as a collection of components that are selectively grouped to form various applications. Users specify which components should be included in a simulation, define a rough discretization/parallelization layout, and assign their own initial conditions, boundary conditions, and problem setup to create a unique application executable. In Flash-X terminology, a component that implements an exclusive portion of the code’s functionality is called a unit. A typical Flash-X simulation requires a proper subset of the units available in the code. Thus, it is important to distinguish between the entire Flash-X source code and a given Flash-X application.

Unit

A Flash-X unit provides well-defined functionality and publishes an Application Programming Interface (API), a collection of routines through which other units can interact with it. A unit can have multiple alternative implementations of varying complexity and for different purposes. A unit can have an arbitrary number of subunits that provide subsets of the unit’s functionality, though in practice the number of subunits remains low. Units must include a null implementation for every routine in their API at the top level of their hierarchy. This feature permits an application to easily exclude a unit without the need to modify code elsewhere. For example, the input/output unit can be easily turned on and off for testing purposes, by using the null implementations.

Flash-X implements its inheritance, extensibility, and modularity through its configuration layer. This layer consists of a collection of text Config files that reside at various levels of the code organization, and the setup tool which interprets the Config files. The two primary functions of this layer are to configure a single application from the Flash-X source tree, and to implement inheritance and customizability in the code.

Unit architecture abstracts the computational complexity of the unit from its public interfaces, and controls the scope of various data items owned by the unit. A unit’s API provides interfaces for modifying the state of the solution and for accessing and modifying data it owns that may be needed by other units. Units can have one or more subunits which are groupings of self-contained functionality. The concept subunits formalizes the selective use of a subset of a unit’s functionality, and the possibility of multiple alternative implementations of the same subset. Subunits implement disjoint subsets of a unit’s API, where none of the subsets can be a null set. The union of all subsets constituting various subunits must be exactly equal to the unit API. Every unit has at least a Main subunit that implements the bulk of the unit’s functionality, including its initialization. The Main subunit is also the custodian of all the unit-scope data. Subunits and other finer-grained components can have their own data modules that are only visible to the routines and functions within those components. In other words, a data module placed in a directory is only visible to routines in functions in that directory or its sub-directories, but not to its parent or ancestor directories.

Flash-X Inheritance

Flash-X inheritance is implemented through the Unix directory structure and the setup tool. When the setup tool parses the source tree, it treats each child or subdirectory as inheriting all of the Config and Makefile files in its parent’s directory. While source files at a given level of the directory hierarchy override files with the same name at higher levels, Makefiles and configuration files are cumulative. Since functions can have multiple implementations, selection for a specific application follows a few simple rules described in the following Figures.

overall_flowchart

Overview of the control flow during configuration

overall_inheritance

Overview of the inheritance in various components of the code

Inheritance as it applied to keys defining macros and runtime parameters

Overview of the control flow during configuration

Step_file_generation

Steps in arbitration on files to be included/generated

However, we must take care that this special use of the directory

structure for inheritance does not interfere with its traditional use for organization. We avoid any problems by means of a careful naming convention that allows clear distinction between organizational and namespace directories. See for naming conventions.

Customization

The Simulation unit in the code is treated differently from all other units because this is where the application is defined. The parsing of Config file begins from that of the application being configured. Additionally, this unit also provides the mechanism for customization. The inheritance implemented by the setup tool replaces any file or a macro definition assembled during the configuration of hte application if another file or macro of the same name is encountered in the Simulation unit. Thus a user desirous of customizing any part of the source code can do so by simply placing an identically named file or macro in a file with “.ini” extenstion in the directory that they created for their Simulation.

Unit Test Framework

In keeping with good software practice, Flash-X incorporates a unit test framework that allows for rigorous testing and easy isolation of errors. The components of the unit test show up in two different places in the Flash-X source tree. One is a dedicated path in the Simulation unit, Simulation/SimulationMain/unitTest/UnitTestName, where UnitTestName is the name of a specific unit test. The other place is a subdirectory called unitTest, somewhere in the hierarchy of the corresponding unit which implements a function Unit_unitTest and any helper functions it may need. The primary reason for organizing unit tests in this somewhat confusing way is that unit tests are special cases of simulation setups that also need extensive access to internal data of the unit being tested. By splitting the unit test into two places, it is possible to meet both requirements without violating unit encapsulation. We illustrate the functioning of the unit test framework with the unit test of the Eos unit. For more details please see . The Eos unit test needs its own version of the routine Driver/Driver_evolveAll which makes a call to its Eos_unitTest routine. The initial conditions specification and unit test specific Driver_evolveAll are placed in Simulation/SimulationMain/unitTest/Eos, since the Simulation unit allows any substitute Flash-X function to be placed in the specific simulation directory. The function Eos_unitTest resides in physics/Eos/unitTest, and therefore has access to all internal Eos data structures and helper functions.