CSDMS Basic Modeling Interface (version 1.0)

  • In order to simplify conversion of an existing model to a reusable, plug-and-play model component, CSDMS has developed a simple interface called the Basic Model Interface or BMI. Recall that in this context an interface is a named set of functions with prescribed function names, argument types and return types.
  • By design, the BMI functions are straightforward to implement in any of the languages supported by CSDMS, which include C, C++, Fortran (all years), Java and Python. Even though some of these languages are object-oriented and support user-defined types, the BMI functions use only simple (universal) data types.
  • Also by design, the BMI functions are noninvasive. A BMI-compliant model is not required to use CSDMS data structures and does not make any calls to CSDMS components or tools. BMI therefore introduces no dependencies into a model and the model can still be used in a "stand-alone" manner.
  • Any model that provides the BMI functions can be easily be converted to a CSDMS plug-and-play component with a CSDMS Component Model Interface or CMI. The BMI functions are called by the CMI, by the framework and by service components. It is not necessary for a developer to learn anything about the CMI unless they're just curious.
  • Once a BMI-compliant model has been wrapped with the CMI interface to become a CSDMS component, it automatically gains many new capabilities. This includes the ability to be coupled to other models even if their (1) programming language, (2) variable names, (3) variable units, (4) time-stepping scheme or (5) computational grid is different. It also gains (1) the ability to write output variables to standardized NetCDF files, (2) a "tabbed-dialog" graphical user interface (GUI) (this requires a corresponding XML file) (3) a standardized HTML help page and (4) the ability to run within the CSDMS Modeling Tool (CMT).
  • The CMI wrapping does not have a significant impact on performance. This is due to the use of Babel for language interoperability and the fact that CSDMS components pass values by reference instead of by copy whenever possible.


Fine-grained Control Functions

void initialize (in string config_file) 
void update (in double dt) //  Advance model variables by time interval, dt (dt=-1 means use model time step)
void finalize () 
void run_model (in string config_file) //  Do a complete model run. Not needed for CMI.
  • These BMI functions are critical to plug-and-play modeling because they allow a calling component to bypass a model's own time loop. They also provide the caller with fine-grained control over the model, similar to a TV remote control.
  • The initialize() function accepts a string argument that gives the name (and path) of its "main input file", called a configuration file. This function should perform all tasks that are to take place before entering the model's time loop.
  • The update() function accepts a time step argument, "dt". If (dt == -1), then the model should use its own (internal) timestep; otherwise it should use the value provided. This function should perform all task that take place during one pass through the model's time loop. This typically includes incrementing all of the model's state variables.
  • The finalize() function should perform all tasks that tkae place after exiting the model's time loop. This typically includes deallocating memory, closing files and printing reports.
  • The run_model() function is not needed by CSDMS but provides a simple method to run the model in "stand-alone mode". (Often used by the developer; basically the model's "main".) It would simply call "initialize()", start a time loop that only calls "update()" and then calls "finalize()".


Model Information Functions

array<string> get_input_var_names()
array<string> get_output_var_names()
string get_attribute( in string att_name ) // (for model_name, mesh_type, time_step_type, etc.)
  • These BMI functions are called by the CSDMS framework in order to determine what input variables each model component needs and what output variables it can provide to other components.
  • Note that "long variable name" and "long_var_name" refer to standardized variable names from the CSDMS Standard Names.
  • The get_input_var_names() function returns a string array of the model's input variable names as "long variable names". Similarly, the get_output_var_names() function returns a string array of the models output variable names.
  • The get_attribute() function is passed an attribute name from the following list:
model_name
author_name
mesh_type
time_step_type
and returns a corresponding string. For the "mesh_type" attribute, the allowed return values are:
uniform, rectilinear, s_mesh and u_mesh
as described below. For the "time_step_type" attribute, the allowed return values are:
fixed, adaptive, local


Variable Information Functions

string get_var_type( in string long_var_name ) // ( returns type_string, e.g. ‘double’)
string get_var_units( in string long_var_name ) // ( returns unit_string, e.g. ‘meters’ )
int get_var_rank( in string long_var_name ) // ( returns array rank or 0 for scalar)
string get_var_name( in string long_var_name ) // ( returns model’s internal, short name )
 
double get_time_step() // (returns the model’s current timestep;  adaptive or fixed.)
string get_time_units() // (returns unit string for model time, e.g. ‘seconds’, ‘years’)
double get_start_time()
double get_current_time()
double get_end_time()
  • These BMI functions are called by the CSDMS framework to obtain information about a particular input or output variable. Based on this information, the framework can apply type or unit conversion when necessary.
  • Note that "long variable name" and "long_var_name" refer to standardized variable names from the CSDMS Standard Names.
  • For the get_var_units() and get_time_units() functions, standard unit names (in lower case) should be provided, such as "meters" or "feet". Standard abbreviations, like "m" for "meters" and "mi" for "miles" are also supported. For variables with "compound units", each primitive unit name or abbreviation is separated by a single space character and exponents other than 1 are placed immediately after the name, as in "m s-1" for velocity, or "W m-2" for an energy flux.
  • For the get_var_type() function, the returned data type should be a string from the first column of the following table.
  BMI datatype C datatype NumPy datatype
  BMI_CHAR char int8
  BMI_UNSIGNED_CHAR unsigned char uint8
  BMI_INT signed int int16
  BMI_LONG signed long int int32
  BMI_UNSIGNED_INT unsigned int uint16
  BMI_UNSIGNED_LONG unsigned long int uint32
  BMI_FLOAT float float32
  BMI_DOUBLE double float64


Variable Getter and Setter Functions

double get_0d_double( in string long_var_name )
array<double> get_1d_double( in string long_var_name  )
array<double,2> get_2d_double( in string long_var_name )
array<double> get_2d_double_at_indices( in string long_var_name, array<int> indices )

void set_0d_double( in string long_var_name, in double scalar )
void set_1d_double( in string long_var_name, in array<double> array)
void set_2d_double( in string long_var_name, in array<double,2> array)
void set_2d_double_at_indices( in string long_var_name, in array<int> indices, in array<double,2> array)
  • Note that there is a different setter and getter function for scalars (0d), 1D arrays (1d), 2D arrays (2d) and 3D arrays (3d). Since most of the programming languages supported by CSDMS require static vs. dynamic data types, this simplifies implementation. (However, other approaches are possible and may also be supported later.)
  • Although not listed above, BMI functions to get and set integer data are also supported. They have names like: "get_2d_int()" instead of "get_2d_double()".
  • There is no problem if a model uses arrays with a dimension greater than 3. In that case, BMI functions with names like "get_4d_double()" would simply be provided, following the same naming pattern.
  • The BMI functions get_2d_double_at_indices() and set_2d_double_at_indices() allow a (possibly much smaller) subset of values to be obtained from an array. This can dramatically reduce the amount of data that is passed, which can be important when components are coupled across a network.
  • Note that "long variable name" and "long_var_name" refer to standardized variable names from the CSDMS Standard Names.


Grid Information Functions

  • The BMI function call get_attribute( "mesh_type" ) should return one of the following strings:
uniform       (for uniform rectilinear)
rectilinear   (for rectilinear)
s_mesh        (for structured mesh)
u_mesh        (for unstructured mesh)
  • Each of these strings corresponds to a particular type of model grid or mesh. In order to provide a complete and standardized description of a model's grid, there is a different set of BMI functions that are required for each model "mesh_type" as described in this section.
  • Note that an orthogonal curvilinear coordinate system is a special case of a "structured mesh".
  • Note that "uniform rectilinear", "rectilinear" and "structured mesh" all have the topology of a two-dimensional array.

  Uniform Rectilinear

wrap

array<double, 1> get_grid_spacing (in string long_var_name)
array<double, 1> get_grid_lower_left_corner (in string long_var_name)
array<int, 1> get_grid_shape (in string long_var_name)

  Rectilinear

wrap

array<double, 1> get_grid_x (in string long_var_name)
array<double, 1> get_grid_y (in string long_var_name)
array<double, 1> get_grid_z (in string long_var_name)
array<int, 1> get_grid_shape (in string long_var_name)

  Structured Mesh

wrap

array<double, 1> get_grid_x (in string long_var_name)
array<double, 1> get_grid_y (in string long_var_name)
array<int, 1> get_grid_shape (in string long_var_name)

  Unstructured Mesh

wrap

array<double, 1> get_grid_x (in string long_var_name)
array<double, 1> get_grid_y (in string long_var_name)
array<int, 1> get_grid_connectivity (in string long_var_name)
array<int, 1> get_grid_offset (in string long_var_name)