Interfaces and naming scheme
Standard component interface
For inclusion in the FACETS framework, components must implement the following interface methods (described in C++). The return value for all calls is the error state, with 0 indicating no error. Look at how to bring in an external component for a step-by-step guide to componentizing a new component for FACETS.
Startup phase
The following interface methods are called in the order shown. They return error status (0 is all is OK and 1 otherwise).
| C++ | Actions and description of variables |
| int setLogFile(const std::string& lf); | lf is the name of the file for component messages and component per-rank messages. Component messages should go to the file named lf + ".out". Per-rank messages should go to the file named lf + "_" + rankNo + ".log" . Returns error value. 0 means success. |
| int setMpiComm(long comm); | comm is the communicator handle. Te framework needs to set it up to integrate components in one executable. |
| int readParams(const std::string& infile); | Read input file. infile is the name of a file that contains parameters needed by the component. |
| int buildData(); | Instructs the component to allocate needed memory (fields, particles, ...). |
| int initialize(); | Called for a new run (not a restart) to instruct component to initialize fields. Used when restore is not used. |
The interfaces for dumping restart files and restoring are described below.
After the initialization phase, the component should be in a valid dynamical state, ready to be advanced.
Data access interfaces
For all set/get methods listed, there are a set of similar methods for getting and setting ints (setInt/getInt) and strings (setString/getString). Methods that require interpolation do not support String interface methods.
General dimension-independent accessors
| C++ | Description of variables |
| int getRankOfInterface(const std::string& ifc, size_t& ret) const; | ifc is the name of the interface. ret is the rank on which that interface lives |
0-D accessors
| C++ desired interface | Description of variables |
| int set0dDouble(const std::string& name, double data); | name is the name of the variable. datais the value. |
| int get0dDouble(const std::string& name, double& data) const; | name is the name of the variable. data is the value. |
| int set0dDoubleAtLoc(const std::string& name, const std::vector<size_t>& loc, double data); | name is the name of the variable. loc is the physical location. data is the value. |
| int geti0dDoubleAtLoc(const std::string& name, const std::vector<size_t>& loc, double& data) const; | name is the name of the variable. loc is the physical location. data is the value. |
The interface has similar methods for integer and string variables.
| C++ actual interface | Description of variables |
| int set0dDouble(const std::string& name, double data); | name is the name of the variable. datais the value. |
| int get0dDouble(const std::string& name, double& data) const; | name is the name of the variable. data is the value. |
| int set0dDoubleAtLoc(const std::string& name, size_t ndims, const double* loc, double data); | name is the name of the variable. loc is the physical location. data is the value. |
| int geti0dDoubleAtLoc(const std::string& name, size_t ndims, const double* loc, double& data) const; | name is the name of the variable. loc is the physical location. data is the value. |
The interface has similar methods for integer and string variables.
1-D accessors
| C++ desired interface | Description of variables |
| int set1dDouble(const std::string& name, const std::vector<double>& data); | name is the name of the variable. data is the array of values. |
| int get1dDouble(const std::string& name, std::vector<double>& data) const; | name is the name of the variable. data is the array of values. |
The interface has similar methods for integer and string variables.
| C++ actual interface | Description of variables |
| int set1dDouble(const std::string& name, size_t len, const double* data); | name is the name of the variable. data is the array of values. |
| int get1dDouble(const std::string& name, size_t len, double* data) const; | name is the name of the variable. data is the array of values. |
The interface has similar methods for integer and string variables.
n-D accessors: not implemented yet
| C++ | Description of variables |
| int setndDouble(const std::string& name, const std::vector<size_t>& shape, const std::vector<double>& data); | name is the name of the variable. shape is the shape of the multidimensional array. data is the array of data, linearly packed in row major ordering. |
| int getndDouble(const std::string& name, std::vector<size_t>& shape, std::vector<double>& data) const; | name is the name of the variable. shape is the shape of the multidimensional array. data is the array of data, linearly packed in row major ordering. |
Update phase
These methods return error status (0 is all is OK and 1 otherwise).
| int update(double t); | The component should save its current state in case reset is needed and then advance to time. t. |
| int revert(); | The component should revert to the last saved state. |
Dump and restore phase
There are two methods for the framework to tell a component to dump its data. The first is for the framework to specify not only the filename, but also the location within an HDF5 (or other hierarchial) file. The latter is to provide a label that can be used to namespace multiply instantiated codes like GYRO and WallPSI.
These methods return error status (0 is all is OK and 1 otherwise).
| C++ | Actions and description of variables |
| int dumpToFile(const std::string& file) const; | file is the file to dump to. It can also be used to provide labels to label all of the files that a component will use. |
The associated restore functions are:
| C++ | Actions and description of variables |
| int restoreFromFile(const std::string& file); | file is the file to restore to. It can also be used to provide labels to label all of the files that a component will use. |
Complete interface
These methods return error status (0 is all is OK and 1 otherwise).
| C++ | Actions and description of variables |
| int complete(); | Whatever needs to be done before destruction |
FacetsIfs.sidl and Facets0dIfc.sidl
We use Babel to communicate between the framework and UEDGE. Babel has the following sidl definitions.
package facets version 0.1 {
interface FacetsIfc {
int readParams(in string inFile);
int setMpiComm(in long comm);
int setLogFile(in string logFile);
int getRankOfInterface(in string ifcName, out int rank);
int initialize();
int update (in double tnew);
int dumpToFile(in string fname);
int restoreFromFile(in string fname);
}
}
package facets version 0.1 {
interface Facets0dIfc {
int get0dDouble (in string varname, out double value);
int set0dDouble (in string varname, in double value);
int get0dDoubleAtLocation (in string varname, in rarray<double> location(dim), in int dim, out double value);
int set0dDoubleAtLocation (in string varname, in rarray<double> location(dim), in int dim, in double value);
int get0dInt (in string varname, out int value);
int set0dInt (in string varname, in int value);
int get0dIntAtLocation (in string varname, in rarray<double> location (dim), in int dim, out int value);
int set0dIntAtLocation (in string varname, in rarray<double> location (dim), in int dim, in int value);
int get0dString (in string varname, out string value);
int set0dString (in string varname, in string value);
}
}
Python mappings
Python is used in UEDGE and we use Babel to communicate between C++ and Python. The server Python bindings come from Facets0dIfc.sidl and FacetsIfc?.sidl files shown above. Since Babel generates server skeletons and the implementation is supposed to be inserted in the generated code, we currently do the following.
Upon any change in sidl interfaces, we generate Python bindings. Next we edit and add implementation and disable bindings regeneration using particular Babel flags. For example, for uedge we do the following.
1. Define uedge to implement the desired interfaces:
package ue version 0.2 {
class Uedge implements-all facets.FacetsIfc, facets.Facets0dIfc { }
}
2. Generate Python server stubs
<babel_location>/bin/babel --server=python uedge.sidl
This will create Uedge_Impl.py.
3. Modify impl file: get rid of _getStub method and make the impl to inherit from ue.Uedge_Aux.Uedge and modify _init so that the class looks like:
class Uedge(ue.Uedge_Aux.Uedge):
def __init__(self, IORself = None):
ue.Uedge_Aux.Uedge.__init__(self, IORself)
# other methods
4. Implement Python methods. The key here is to remember that Python does not allow out variables, so the out variable should be packages in the return tuple consisting of the original sidl return and all out variables. For example, get0dDouble should look like:
def get0dDouble(self, varname):
value = (0, self.uedge.getDouble(varname))
return value
Naming scheme
The general particle variable label has the form:
quantity_Interface_ElementsymbolMassnumberpIonizationstate_class
Underscores are not allowed in any other parts of the name. A string name should ultimately be a C or python allowed variable name to allow use in arithmetic expressions.
Examples::
density_CE_C12p5 density_CS_He4p2_fusionprod density_CS_neutron_fusionprod ptclFlux_EW_H2p1 energyInFlux_electron
Quantity strings with [units] and (comments):
- density [m^-3]
- ptclIntegratedFlux [1/s] (like current, i.e., crossing a surface)
- ptclFlux [1/m^2/s]
- ptclInFlux (that part of the Flux into the wall)
- ptclOutFlux (that part of the Flux out of the wall)
- ptclIntegratedSource [1/s]
- ptclSource [1/m^3/s]
- energyDensity [J/m^3]
- energyIntegratedSource [J/s]
- energySource [J/m^3/s]
- energyIntegratedFlux [J/s] (crossing a surface)
- energyFlux [J/m^2/s]
- energyInFlux [J/m^2/s]
- energyOutFlux [J/m^2/s]
- avgEnergyInFlux
- avgEnergyOutFlux
- temperature [eV]
- heatIntegratedFlux not used. Instead use energyIntegratedFlux
- rotationFrequency [s^-1]
- angularMomentum [kg m^2/s]
- angularMomentumDensity [kg/m/s]
- angularMomentumIntegratedFlux [kg m^2/s^2]
- angularMomentumFlux [kg/m/s^2]
- angularMomentumSource [kg /m^2/s^2]
- parallelMomentum [kg m/s]
- parallelMomentumDensity [kg/m^2/s]
- parallelMomentumIntegratedFlux [kg m/s^2]
- parallelMomentumFlux [kg/m^2/s^2]
This is more complicated than the original proposal, but is meant to be more accurate to the types of fluxes and quantities that are to be passed.
Interface strings:
- CE: Core-Edge
- EW: Edge-Wall
- CS: Core-Source
Notice, along with EW, the WE (Wall-Edge) string can be used. The names EW and WE are equivalent.
Species strings:
There are several special names determining elementary particles:
- electron
- photon
- neutron
For specifying other species, one generally needs to know the element number (# of protons), isotope of the element (or mass number, and the charge state. We use the standard symbols from the Mendeleev periodic table of elements, the integer value of the atomic mass, and the charge. Examples:
- O16p8 -- fully-ionized oxygen
- H2p1 -- deuterium
- C12p3 -- Carbon-12 with 3rd ionization state
- H2 -- neutral deterium gas
Class strings:
The class is an optional specification that used to distinguish the types of particles. Examples are:
- thermal
- plasma
- rf
- neutral beam
- fusion products
- other?
An importance of class specifications is illustrated by radiation :
- photon_thermal --- thermal (Black-Body) radiation of material surfaces
- photon_plasma --- radiation emitted by plasma (line+continuum)
These quantities are calculated by diffrenet components.
For plasma diagnostic purposes, one can use the class to distinguish specific lines or continua:
- photon_Dalpha --- Deuterium Balmer-alpha
- photon_VBS --- Visual Bremssrahlung
Provenance strings:
There is also a set of provenance strings that may be used to set up certain key runtime parameters that are not associated with any physical quantity, but rather are required for the base functionality of the component. Note that these strings will not be decorated by any tokens denoting component interface, particle type, class subtype, etc.
- dataDirectory
Detailed specification of names at each interface
Comments
* The string structure is fairly complicated as seen above. The advantage is that the signature of the get/set interfaces do not change and it is unlikely that the string parsing code in the individual components will need to be updated if the structure needs to be further extended.
* Another advantage is that by having a unique name, each species will more easily be tracked within the visualization packages; i.e., if these names are used to dump to HDF5, then visualization of them is obvious.
* The primary disadvantage is that each component will need to beable to parse the string and map onto their internal data. At present, any data structures will require remapping since no common naming scheme exists, and currently the schemes are inadequate for specifying the type of interface being utilized (as originally pointed out by Ron Cohen).
* The interfaces will deal with values of density, temperature etc. However, for fluxes we want averaged particle flux, averaged heat flux, angular moment and angular momentum flux.
| Quantity | Flux | Source |
| Number density | Particle flux | Number density |
| Temperature | Energy density flux (flux for 3/2nT) | Energy density |
| Angular Momentum | Angular momentum flux | Angular momentum density |
