Adaptor API’s

SENSEI makes heavy use of the adaptor design pattern. This pattern is used to abstract away the details of complex and diverse systems exposing them through a single API. SENSEI has 2 types of adaptor. The DataAdaptor abstracts away the details of accessing simulation data. This let’s analysis back-ends access any simulation’s data through a single API. The AnalysisAdaptor abstarcts away the details of the analysis back-ends. This let’s the simulation invoke all of the various analysis back-ends through a single API. When a simulation invokes an analysis back-end it passes it a DataAdaptor that can be used to access simulation data.

DataAdaptor API

SENSEI’s data adaptor API abstracts away the differences between simulations allowing SENSEI’s transports and analysis back ends to access data from any simulation in the same way. A simulation must implement the data adaptor API and pass an instance when it wishes to trigger in situ processing.

Through the data adaptor API the analysis back end can get metadata about what the simulation can provide. This metadata is examined and then the analysis can use the API to fetch only the data it needs to accomplish the tasks it has been configured to do.

Finally the data adaptor is a key piece of SENSEI’s in transit system. The analysis back end can be run in a different parallel job and be given an in transit data adaptor in place of the simulation’s data adaptor. In this scenario the in transit data adaptor helps move data needed by the analysis back end. The data adaptor API enables this scenario to appear the same to the simulation and the analysis back end. Neither simulation nor analysis need be modified for in transit processing.

Core API

Simulations need to implement the core API.

In transit API

In transit transports need to implement the in transit API.

AnalysisAdaptor API

Extending SENSEI for customized Analysis capabilities requires implementing a sensei::AnalysisAdaptor .

At a minimum one must implement the sensei::AnalysisAdaptor::Execute method. In your implementation you will make use of the passed sensei::DataAdaptor instance to fetch the necessary simulation data.

The following template can be used to add a new C++ based analysis capability.

class MyAnalysis : public sensei::AnalysisAdaptor
{
public:

    virtual bool Execute(DataAdaptor* dataIn, DataAdaptor** dataOut)
    {
        // YOUR ANALYSIS CODE HERE. USE THE PASSED DATA ADAPTOR TO ACCESS
        // SIMULATION DATA

        if (dataOut)
        {
            // IF YOUR CODE CAN RETURN DATA, CREATE AND RETURN A DATA
            // ADAPTOR HERE THAT CAN BE USED TO ACCESS IT
            *dataOut = nullptr;
        }

        return true;
    }

};

Python API

The sensei::PythonAnalysis adaptor enables the use of a Python scripts as an analysis back end in C,C++, and Fortran based simulation codes. It accomplishes this by embedding a Python interpreter and includes a minimal set of the sensei python bindings. To author a new python analysis one must provide a python script that implements three functions in a user provided Python script that is loaded at run time. The three functions are: Inititalize, Execute and Finalize. These functions implement the sensei::AnalysisAdaptor API.

The Execute function is required while Initialize and Finalize functions are optional. The Execute function is passed a sensei::DataAdaptor instance from which one has access to simulation data structures. If an error occurs during processing one should raise an exception. If the analysis required MPI communication, one must make use of the adaptor’s MPI communicator which is stored in the global variable comm. Additionally one can provide a secondary script that is executed prior to the API functions. This script can set global variables that control runtime behavior.

End users will make use of the sensei::ConfigurableAnalysis and point to the python script containing the three functions described above. The script can be loaded in one of two ways: via python’s import machinery or via a customized mechanism that reads the file on MPI rank 0 and broadcasts it to the other ranks. The latter is the recommended approach.

def Initialize():
    """ Initialization code here """
    return

def Execute(dataAdaptor):
    """ Use sensei::DataAdaptor API to process data here """
    return

def Finalize():
    """ Finalization code here """
    return