diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 51cbe85..0000000 --- a/.gitignore +++ /dev/null @@ -1,54 +0,0 @@ -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] - -# C extensions -*.so - -# Distribution / packaging -.Python -env/ -bin/ -build/ -develop-eggs/ -dist/ -eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -*.egg-info/ -.installed.cfg -*.egg - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.coverage -.cache -nosetests.xml -coverage.xml - -# Translations -*.mo - -# Mr Developer -.mr.developer.cfg -.project -.pydevproject - -# Rope -.ropeproject - -# Django stuff: -*.log -*.pot - -# Sphinx documentation -docs/_build/ - diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index d7a9733..0000000 --- a/.gitmodules +++ /dev/null @@ -1,24 +0,0 @@ -[submodule "bindings/c"] - path = bindings/c - url = https://github.com/csdms/bmi-c -[submodule "bindings/cxx"] - path = bindings/cxx - url = https://github.com/csdms/bmi-cxx -[submodule "bindings/fortran"] - path = bindings/fortran - url = https://github.com/csdms/bmi-fortran -[submodule "bindings/python"] - path = bindings/python - url = https://github.com/csdms/bmi-python -[submodule "examples/python"] - path = examples/python - url = https://github.com/csdms/bmi-example-python -[submodule "examples/fortran"] - path = examples/fortran - url = https://github.com/csdms/bmi-example-fortran -[submodule "examples/c"] - path = examples/c - url = https://github.com/csdms/bmi-example-c -[submodule "examples/cxx"] - path = examples/cxx - url = https://github.com/csdms/bmi-example-cxx diff --git a/AUTHORS.rst b/AUTHORS.rst index 9a8f201..bc1f45d 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -12,6 +12,8 @@ Contributors ------------ * Richard Barnes +* Michael Galloy +* Julian Hofer * Eric Hutton * Boyana Norris * Scott Peckham diff --git a/README.rst b/README.rst index 80d8158..3d4e81d 100644 --- a/README.rst +++ b/README.rst @@ -29,38 +29,84 @@

- The Basic Model Interface (BMI) is a library specification to - simplify the coupling of models. + The Basic Model Interface (BMI) is a standardized set of functions + that allows coupling of models to models and models to data.

-In order to simplify conversion of an existing model to a reusable, -plug-and-play model component, the -`Community Surface Dynamics Modeling System `_ -(CSDMS) has developed a simple -interface called the *Basic Model Interface* or *BMI* that model -developers are asked to implement. Recall that in this -context an *interface* is a named set of functions with prescribed -function names, argument types and return types. The BMI functions -make the model *self-describing* and fully *controllable* by a -modeling framework or application. - +The *Basic Model Interface* (BMI) is a library specification +created by the `Community Surface Dynamics Modeling System`_ (CSDMS) +to facilitate the conversion of a model or dataset +into a reusable, plug-and-play component. +Recall that, in this context, an interface is a named set of functions +with prescribed arguments and return values. +The BMI functions make a model self-describing and fully controllable +by a modeling framework or application. By design, the BMI functions are straightforward to implement in -any language and use only simple (universal) data types. While the -CSDMS model coupling framework supports C, C++, Fortran, Java, -and Python, a BMI can described for any language. CSDMS -provides example bindings for BMI in each of the above languages. - -Also by design, the BMI functions are *noninvasive*. This means -that a BMI-compliant model does not make any calls to other +any language, using only simple data types from standard language libraries. +Also by design, the BMI functions are noninvasive. +This means that a model's BMI does not make calls to other components or tools and is not modified to use any -framework-specific data structures. BMI therefore introduces no -dependencies into a model and the model can still be used -in a *stand-alone* manner. - -The most current development version is always available from our git repository: -http://github.com/csdms/bmi. - -Please note that this project is released with a -`Contributor Code of Conduct <./CODE-OF-CONDUCT.rst>`_. -By participating in this project you agree to abide by its terms. +framework-specific data structures. A BMI, therefore, introduces no +dependencies into a model, so the model can still be used +in a stand-alone manner. + +The BMI is expressed +in the `Scientific Interface Definition Language`_ (SIDL) +in the file `bmi.sidl <./bmi.sidl>`_. +BMI specifications for four languages -- C, C++, +Fortran (77, 90/95, 2003, 2008), +and Python -- are derived from this SIDL file. +For each language, +links to the specification and an example implementation +are listed in the table below. + +.. table:: + :align: center + :widths: 10, 10, 15 + + ======== ============== ====================== + Language Specification Example implementation + ======== ============== ====================== + C `bmi-c`_ `bmi-example-c`_ + C++ `bmi-cxx`_ `bmi-example-cxx`_ + Fortran `bmi-fortran`_ `bmi-example-fortran`_ + Python `bmi-python`_ `bmi-example-python`_ + ======== ============== ====================== + +Detailed instructions for building the specifications and examples +are given at each link above. +The specifications can also be installed through `conda`. + +.. code-block:: bash + + $ conda install -c conda-forge bmi-c + $ conda install -c conda-forge bmi-cxx + $ conda install -c conda-forge bmi-fortran + $ conda install -c conda-forge bmipy + +While CSDMS currently supports the four languages listed above, +a BMI can be written for any language. +BMI is a community-driven standard; +`contributions `_ +that follow the `contributor code of conduct <./CODE-OF-CONDUCT.rst>`_ +are welcomed, +and are `acknowledged <./AUTHORS.rst>`_. +BMI is open source software released under the `MIT License <./LICENSE>`_. + +*The Community Surface Dynamics Modeling System +is supported by the National Science Foundation.* + + +.. Links + +.. _Community Surface Dynamics Modeling System: https://csdms.colorado.edu +.. _Scientific Interface Definition Language: http://dx.doi.org/10.1177/1094342011414036 +.. _bmi-c: https://github.com/csdms/bmi-c +.. _bmi-cxx: https://github.com/csdms/bmi-cxx +.. _bmi-fortran: https://github.com/csdms/bmi-fortran +.. _bmi-python: https://github.com/csdms/bmi-python +.. _bmi-example-c: https://github.com/csdms/bmi-example-c +.. _bmi-example-cxx: https://github.com/csdms/bmi-example-cxx +.. _bmi-example-fortran: https://github.com/csdms/bmi-example-fortran +.. _bmi-example-python: https://github.com/csdms/bmi-example-python diff --git a/bindings/c b/bindings/c deleted file mode 160000 index 970010e..0000000 --- a/bindings/c +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 970010e3f4660d095d50d3dae755debbf7f4dabb diff --git a/bindings/cxx b/bindings/cxx deleted file mode 160000 index 912a381..0000000 --- a/bindings/cxx +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 912a3812a26e92a04962eb7d8cddec66b170f2cc diff --git a/bindings/fortran b/bindings/fortran deleted file mode 160000 index 02d98c9..0000000 --- a/bindings/fortran +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 02d98c9f769b5b7b86aaf707740b610b30e7165c diff --git a/bindings/python b/bindings/python deleted file mode 160000 index 7f534c0..0000000 --- a/bindings/python +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 7f534c0a039246dbac9083c1d7280334d4e3fd7d diff --git a/bmi.f90 b/bmi.f90 deleted file mode 120000 index 71c27ae..0000000 --- a/bmi.f90 +++ /dev/null @@ -1 +0,0 @@ -bindings/fortran/bmi.f90 \ No newline at end of file diff --git a/bmi.h b/bmi.h deleted file mode 120000 index b78dfb7..0000000 --- a/bmi.h +++ /dev/null @@ -1 +0,0 @@ -bindings/c/bmi.h \ No newline at end of file diff --git a/bmi.hxx b/bmi.hxx deleted file mode 120000 index ceaf89f..0000000 --- a/bmi.hxx +++ /dev/null @@ -1 +0,0 @@ -bindings/cxx/bmi.hxx \ No newline at end of file diff --git a/bmi.py b/bmi.py deleted file mode 120000 index fdf6a78..0000000 --- a/bmi.py +++ /dev/null @@ -1 +0,0 @@ -bindings/python/bmipy/bmi.py \ No newline at end of file diff --git a/bmi.sidl b/bmi.sidl index 86cf34c..9023196 100644 --- a/bmi.sidl +++ b/bmi.sidl @@ -1,7 +1,7 @@ // // The Basic Model Interface (BMI) // -package csdms version 2.0b0 { +package csdms version 2.0 { interface bmi { // Initialize, run, finalize (IRF) diff --git a/docs/source/_templates/links.html b/docs/source/_templates/links.html index b747de0..8dedb42 100644 --- a/docs/source/_templates/links.html +++ b/docs/source/_templates/links.html @@ -1,7 +1,7 @@

Useful Links

diff --git a/docs/source/bmi.control_funcs.rst b/docs/source/bmi.control_funcs.rst index b0ff237..e6f7798 100644 --- a/docs/source/bmi.control_funcs.rst +++ b/docs/source/bmi.control_funcs.rst @@ -1,124 +1,125 @@ -Model Control Functions -======================= +.. _control_funcs: + +Model control functions +----------------------- 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 - a calling application is able to, for instance, update a +They also provide the caller with fine-grained control over the +model -- a calling application is able to, for instance, update a model one time step at a time, change its state, and then continue updating. -Initialization --------------- +.. _initialize: + +*initialize* +............ .. code-block:: java /* SIDL */ - void initialize(in string config_file); - -.. code-block:: c - - /* C */ - int initialize(const char * config_file, void** handle); - -.. code-block:: c++ - - /* C++ */ - void Initialize (const char *config_file); - -.. code-block:: fortran - - ! Fortran (>=2003) - integer function initialize(this, config_file) - class (*), intent(out) :: this - character (len=*), intent(in) :: config_file + int initialize(in string config_file); The `initialize` function accepts a string argument that gives the -name (and path) of its "main input file", or *configuration file*. +path to its :term:`configuration file`. This function should perform all tasks that are to take place before entering the model's time loop. Models should be refactored, if necessary, to read their inputs (which could include filenames for -other input files) from a configuration file (a text file). -CSDMS does not impose any constraint on how configuration files are -formatted, but a "template" of your model's config file (with -placeholder values) is needed when the BMI model is imported into -a framework such as the CSDMS PyMT. This is considered part of the -model's BMI metadata. +other input files) from a configuration file. +BMI does not impose any constraint on how configuration files are +formatted. +**Implementation notes** -Time stepping -------------- +* Models should be refactored, if necessary, to use a configuration + file. +* While no constraints are placed on how configuration files are + formatted, `YAML `_ is preferred. +* In C and Fortran, the *config_file* argument is passed as + a character array, whereas in C++ and Python, it's passed as + a string -- a basic type in these languages. +* In C and Fortran, an integer status code indicating success or failure + is returned. In C++ and Python, an exception is raised on failure. -.. code-block:: java - - /* SIDL */ - void update(); - void update_until(in double then); - -.. code-block:: c +[:ref:`control_funcs` | :ref:`basic_model_interface`] - /* C */ - int update(void *handle); - int update_until(void *handle, double then); -.. code-block:: c++ +.. _update: - /* C++ */ - void Update(void); - void UpdateUntil(double then); +*update* +........ -.. code-block:: fortran - - ! Fortran (>=2003) - integer function update(this) - class (*), intent(inout) :: this - integer function update_until(this, then) - class (*), intent(inout) :: this - double precision, intent(in) :: then +.. code-block:: java + /* SIDL */ + int update(); -The `update` function advances the model by a single timestep. This -is the model's own internal timestep (as returned by the BMI -`get_time_step` function) - not the timestep of a controlling application. +The `update` function advances the model by a single time step. This +is the model's own internal time step (as returned by the BMI +:ref:`get_time_step` function), not the time step +of a controlling application. This function should perform all tasks that take place during one pass through the model's time loop. It does not contain the time -loop. This typically includes incrementing all of the model's state +loop. This typically involves incrementing all of the model's state variables. If the model's state variables don't change in time, -then they can be computed by the `initialize` function and this +then they can be computed by the :ref:`initialize` function and this function can just return without doing anything. -The `update_until` function updates the model to a particular time, -as provided by its *time* argument. Once called, the value returned -by the BMI `get_current_time` function must return the provided time -to reflect that the model was updated to the requested time. +**Implementation notes** + +* In C and Fortran, an integer status code indicating success or failure + is returned. In C++ and Python, an exception is raised on failure. + +[:ref:`control_funcs` | :ref:`basic_model_interface`] + -.. note:: `update_until` is part of the BMI++ +.. _update_until: -Finalization ------------- +*update_until* +.............. .. code-block:: java /* SIDL */ - void finalize(); + int update_until(in double time); -.. code-block:: c +The `update_until` function updates the model to a particular time, +as provided by its *time* argument. +If the model permits, +the *time* argument can be a non-integral multiple of time steps, +and even negative. +Once called, the value returned +by the BMI :ref:`get_current_time` function must return the provided time +to reflect that the model was updated to the requested time. - /* C */ - int finalize(void *handle); +**Implementation notes** -.. code-block:: c++ +* Time is always a double-precision value. +* In C and Fortran, an integer status code indicating success or failure + is returned. In C++ and Python, an exception is raised on failure. - /* C++ */ - void Finalize(void); +[:ref:`control_funcs` | :ref:`basic_model_interface`] -.. code-block:: fortran - ! Fortran (>=2003) - integer function finalize(this) - class (*), intent(inout) :: this +.. _finalize: + +*finalize* +.......... + +.. code-block:: java + + /* SIDL */ + int finalize(); + The `finalize` function should perform all tasks that take place after exiting the model's time loop. This typically includes deallocating memory, closing files and printing reports. + +**Implementation notes** + +* In C and Fortran, an integer status code indicating success or failure + is returned. In C++ and Python, an exception is raised on failure. + +[:ref:`control_funcs` | :ref:`basic_model_interface`] diff --git a/docs/source/bmi.getter_setter.rst b/docs/source/bmi.getter_setter.rst index 1110df3..9a832f8 100644 --- a/docs/source/bmi.getter_setter.rst +++ b/docs/source/bmi.getter_setter.rst @@ -1,25 +1,155 @@ -Variable Getter and Setter Functions -==================================== +.. _getter_setter_funcs: -.. code-block:: java - - void get_value(in string name, array<> buffer) - void set_value(in string name, array<> value) +Variable getter and setter functions +------------------------------------ +These functions are used to access and modify the variables +that a model exposes through its BMI +(see :ref:`get_input_var_names` and :ref:`get_output_var_names`). -A *getter* is a function that your model provides that other -entities can call in order to get a variable from your model's -*state* (often as a reference). Often a model's state variables -are changing with each time step, so getters are called to get -current values. +A *getter* is a function called to get a variable from your model's *state*. +A model's state variables typically change with each time step, +so getters are called to get current values. -A *setter* is a function that your model provides that other -entities can call in order to change/overwrite a variable in +A *setter* is a function called to change/overwrite a variable in your model's state. A setter may impose restrictions on how a state variable can be changed or check the new data for validity. -``get_value`` takes a variable name and copies values into a + +.. _get_value: + +*get_value* +........... + +.. code-block:: java + + /* SIDL */ + int get_value(in string name, in array<> dest); + +The `get_value` function takes a variable name and copies values into a provided buffer. +The type and size of the buffer depend on the variable, +and can be determined through +:ref:`get_var_type`, :ref:`get_var_nbytes`, etc. +Recall that arrays are always flattened in BMI, +even if the model uses dimensional variables. + +**Implementation notes** + +* The *dest* argument must be defined and allocated before calling + `get_value`. Whatever values it contains are overwritten in the call + to `get_value`. +* In Python, the buffer is a :term:`numpy` array. +* In C++, `get_value` is a void function. +* Depending on how a model is written, a variable may not be + accessible until after the call to :ref:`initialize`. Likewise, the + variable may not be accessible after calling :ref:`finalize`. + +[:ref:`getter_setter_funcs` | :ref:`basic_model_interface`] + +.. _get_value_ptr: + +*get_value_ptr* +............... + +.. code-block:: java + + /* SIDL */ + int get_value_ptr(in string name, out array<> dest_ptr); + +The `get_value_ptr` function takes a variable name and returns a reference +to a variable. +Unlike the buffer returned from :ref:`get_value`, +the reference always points to the current values of the variable, +even if the model's state has changed. + +**Implementation notes** + +* The reference points to a flattened array. +* In C++, the *dest_ptr* argument is omitted, and the reference is + returned through the function. +* In Python, a :term:`numpy` array is returned. + +[:ref:`getter_setter_funcs` | :ref:`basic_model_interface`] + + +.. _get_value_at_indices: + +*get_value_at_indices* +...................... + +.. code-block:: java + + /* SIDL */ + int get_value_at_indices(in string name, in array<> dest, in array inds); + +Use the `get_value_at_indices` function to get a copy of a variable's values +at the locations specified by the one-dimensional array indices +in the *inds* argument. +The values are returned through the *dest* argument. + +**Implementation notes** + +All the notes from :ref:`get_value` apply. +Additionally, + +* Both *dest* and *inds* are flattened arrays. +* The *inds* argument is always of type integer. + +[:ref:`getter_setter_funcs` | :ref:`basic_model_interface`] + + +.. _set_value: + +*set_value* +........... + +.. code-block:: java + + /* SIDL */ + int set_value(in string name, in array<> src); + +The `set_value` function takes a variable name and an array of values, +*src*, +and copies those values into the model's internal array of values, +overwriting the current contents. +The type and size of *src* must match the model's internal array, +and can be determined through +:ref:`get_var_type`, :ref:`get_var_nbytes`, etc. +Recall that arrays are always flattened in BMI, +even if the model uses dimensional variables. + +**Implementation notes** + +* In Python, *src* is a :term:`numpy` array. +* In C++, `set_value` is a void function. +* Depending on how a model is written, a variable may not be + accessible until after the call to :ref:`initialize`. Likewise, the + variable may not be accessible after calling :ref:`finalize`. + +[:ref:`getter_setter_funcs` | :ref:`basic_model_interface`] + + +.. _set_value_at_indices: + +*set_value_at_indices* +...................... + +.. code-block:: java + + /* SIDL */ + int set_value_at_indices(in string name, in array inds, in array<> src); + +Use the `set_value_at_indices` function to set a variable's values +at the locations specified by the one-dimensional array indices +in the *inds* argument. + +**Implementation notes** + +All the notes from :ref:`set_value` apply. +Additionally, + +* Both *src* and *inds* are flattened arrays. +* The *inds* argument is always of type integer. -``set_value`` takes a variable name and an array of values an -copies those values into its internal array of values. +[:ref:`getter_setter_funcs` | :ref:`basic_model_interface`] diff --git a/docs/source/bmi.grid_funcs.rst b/docs/source/bmi.grid_funcs.rst index 109bd6d..885082a 100644 --- a/docs/source/bmi.grid_funcs.rst +++ b/docs/source/bmi.grid_funcs.rst @@ -1,226 +1,452 @@ -.. _get_grid: +.. _grid_funcs: -Model Grids -=========== +Model grid functions +-------------------- -Different models often use different computational grids. An -application that calls a BMI needs a complete and standardized -description of a model's grid in order to automatically accommodate -differences between model grids (via regridding) when coupled -models share data. Currently, BMI supports four different grid types. -Depending on the grid type, the model will implement a different -set of grid functions. By calling a model's :ref:`get_var_grid` -function, an application is able to determine which methods will -be implemented for a particular grid. +The functions in this section describe :ref:`model grids `. +In the BMI, +every :term:`exchange item` is defined on a grid, +and is referenced by a :term:`grid identifier` +returned from the :ref:`get_var_grid` function. +This identifier is a required input to the functions listed below. +A model can have multiple grids. +For example, +consider modeling the diffusion of temperature over a flat plate. +One grid could be a uniform rectilinear grid on which +temperature is defined. +A second grid could be a scalar, +on which a constant thermal diffusivity is defined. -Grid Type ---------- +Not all grid functions are used by each type of grid. +However, all BMI grid functions must be implemented. +(See :ref:`model_grids` and :ref:`implementation`.) + + +.. _get_grid_type: + +*get_grid_type* +............... .. code-block:: java - string get_grid_type(in int id) + /* SIDL */ + int get_grid_type(in int grid, out string type); -The type of grid as a string. Valid return values are: +Given a :term:`grid identifier`, get the type of that grid as a string. +Valid grid types are: -* ``uniform_rectilinear`` -* ``rectilinear`` -* ``structured_quadrilateral`` +* ``scalar`` +* ``points`` +* ``vector`` * ``unstructured`` +* ``structured_quadrilateral`` +* ``rectilinear`` +* ``uniform_rectilinear`` + +A detailed description of the grid types supported in BMI +is given in the :ref:`model_grids` section. + +**Implementation notes** + +* This function is needed for every :ref:`grid type `. +* In C++ and Python, the *type* argument is omitted and the grid + type name is returned from the function. + +[:ref:`grid_funcs` | :ref:`basic_model_interface`] .. _get_grid_rank: -Grid rank ---------- +*get_grid_rank* +............... .. code-block:: java - int get_grid_rank(in int id) + /* SIDL */ + int get_grid_rank(in int grid, out int rank); + +Given a :term:`grid identifier`, get the :term:`rank` of that grid as an integer. -The number of dimension in the grid is its *rank*. A grid's rank -determines the length of many of the following grid functions. -For instance, :ref:`get_grid_shape` will return an array that is -of length *rank*. In a similar way, a grid's rank determines which -of ``get_grid_x``, ``get_grid_y``, etc. are implemented. +A grid's rank determines the length of the return value +of many of the following grid functions. +For instance, :ref:`get_grid_shape` returns an array of length *rank*. +Similarly, a grid's rank determines which +of :ref:`get_grid_x`, :ref:`get_grid_y`, etc. are implemented. -``get_grid_rank`` returns the rank of a particular grid. ``0`` -for scalar, ``1`` for 1D, etc. +**Implementation notes** -Grid size ---------- +* This function is needed for every :ref:`grid type `. +* In C++ and Python, the *rank* argument is omitted and the grid + rank is returned from the function. + +[:ref:`grid_funcs` | :ref:`basic_model_interface`] + + +.. _get_grid_size: + +*get_grid_size* +............... .. code-block:: java - int get_grid_size(in int id) + /* SIDL */ + int get_grid_size(in int grid, out int size); + +Given a :term:`grid identifier`, +get the total number of elements (or :term:`nodes `) +of that grid as an integer. + +The grid size is used for, among other things, the +length of arrays returned by :ref:`get_grid_x` and :ref:`get_grid_y` +for :ref:`unstructured ` and +:ref:`structured quad ` grids. + +**Implementation notes** -``get_grid_size`` returns the size of a grid as the number of -elements. This is used for, among other things, to give the -length of arrays returned by ``get_grid_x`` and ``get_grid_y`` -for :ref:`unstructured ` and -:ref:`structured quad grids `. +* This function is needed for every :ref:`grid type `. +* In C++ and Python, the *size* argument is omitted and the grid + size is returned from the function. +[:ref:`grid_funcs` | :ref:`basic_model_interface`] -Structured grids of quadrilaterals ----------------------------------- .. _get_grid_shape: -Grid shape -^^^^^^^^^^ +*get_grid_shape* +................ .. code-block:: java - int get_grid_shape(in int id, out array shape) + /* SIDL */ + int get_grid_shape(in int grid, in array shape); -A structured grid of quadrilaterals is one formed by a stacked -next one-another such that every vertex is surrounded by four -quadrilaterals. A special case of such a grid is -:ref:`uniform_rectilinear` where rectangles are stacked next -to one another row-by-row. +Get the dimensions of the model grid. -For all quadrilateral grids, the ``get_grid_shape`` function -is necessary to provide the number of rows and columns (for -a 2D grid). Note that this function (as well as the other -grid functions) returns information about each dimension -ordered with "ij" indexing (as opposed to "xy"). For example, -the ``get_grid_shape`` function for the uniform rectilinear -grid shown below would return the array ``[4, 5]``. If there -were a third dimension, the length of the *z-dimension* +Note that this function (as well as the other grid functions) +returns information ordered with "ij" indexing (as opposed to "xy"). +For example, +consider a two-dimensional rectilinear grid +with four columns (``nx = 4``) +and three rows (``ny = 3``). +The :ref:`get_grid_shape` function would return a shape +of ``[ny, nx]``, or ``[3,4]``. +If there were a third dimension, the length of the *z*-dimension, ``nz``, would be listed first. -.. note:: +Also note that the grid shape is the number of :term:`nodes ` +in the coordinate directions and not the number of cells or elements. +It is possible for grid values to be associated with the nodes or with +the cells. + +**Implementation notes** + +* This function is used for describing all :ref:`structured grids + `. +* In Python, the *shape* argument is a :term:`numpy ` array. +* In C++, this is a void function. + +[:ref:`grid_funcs` | :ref:`basic_model_interface`] + + +.. _get_grid_spacing: + +*get_grid_spacing* +.................. + +.. code-block:: java + + /* SIDL */ + int get_grid_spacing(in int grid, in array spacing); + +Get the distance between the :term:`nodes ` of the model grid. + +The :ref:`get_grid_spacing` function provides the width of each cell in +the number of dimensions as returned by :ref:`get_grid_rank`. +As with :ref:`get_grid_shape`, +the spacing is given in "ij" indexing* order; +e.g., for a two-dimensional grid, +the spacing between rows is followed by spacing between columns, ``[dy, dx]``. + +**Implementation notes** + +* This function is used for describing :ref:`uniform rectilinear + ` grids. +* In Python, the *spacing* argument is a :term:`numpy ` array. +* In C++, this is a void function. + +[:ref:`grid_funcs` | :ref:`basic_model_interface`] + + +.. _get_grid_origin: + +*get_grid_origin* +................. + +.. code-block:: java + + /* SIDL */ + int get_grid_origin(in int grid, in array origin); + +Get the coordinates of the lower-left corner of the model grid. + +The *origin* parameter is a one-dimensional array of the size +returned by :ref:`get_grid_rank`. +As with :ref:`get_grid_shape`, +the origin is given in "ij" indexing* order; +e.g., for a two-dimensional grid, +the origin is given in the column dimension, followed by the row dimension, +``[y0, x0]``. + +**Implementation notes** + +* This function is used for describing :ref:`uniform rectilinear + ` grids. +* In Python, the *origin* argument is a :term:`numpy ` array. +* In C++, this is a void function. + +[:ref:`grid_funcs` | :ref:`basic_model_interface`] + + +.. _get_grid_x: + +*get_grid_x* +............ + +.. code-block:: java + + /* SIDL */ + int get_grid_x(in int grid, in array x); + +Get the locations of the grid :term:`nodes ` in the first +coordinate direction. + +The length of the resulting one-dimensional array depends on the grid type. +(It will have either :ref:`get_grid_rank` or :ref:`get_grid_size` elements.) +See :ref:`model_grids` for more information. + +**Implementation notes** - Note that the grid shape is the number of *nodes* in the - coordinate directions and not the number of cells or - elements. It is possible for grid values to be - associated with the nodes or with the cells. +* This function is used for describing :ref:`rectilinear `, + :ref:`structured quadrilateral `, + and all :ref:`unstructured ` grids. +* In Python, the *x* argument is a :term:`numpy ` array. +* In C++, this is a void function. +[:ref:`grid_funcs` | :ref:`basic_model_interface`] -.. _uniform_rectilinear: -Uniform rectilinear -^^^^^^^^^^^^^^^^^^^ +.. _get_grid_y: + +*get_grid_y* +............ + +.. code-block:: java + + /* SIDL */ + int get_grid_y(in int grid, in array y); + +Get the locations of the grid :term:`nodes ` in the second +coordinate direction. + +The length of the resulting one-dimensional array depends on the grid type. +(It will have either :ref:`get_grid_rank` or :ref:`get_grid_size` elements.) +See :ref:`model_grids` for more information. + +**Implementation notes** + +* This function is used for describing :ref:`rectilinear `, + :ref:`structured quadrilateral `, + and all :ref:`unstructured ` grids. +* In Python, the *y* argument is a :term:`numpy ` array. +* In C++, this is a void function. + +[:ref:`grid_funcs` | :ref:`basic_model_interface`] + + +.. _get_grid_z: + +*get_grid_z* +............ + +.. code-block:: java + + /* SIDL */ + int get_grid_z(in int grid, in array z); + +Get the locations of the grid :term:`nodes ` in the third +coordinate direction. + +The length of the resulting one-dimensional array depends on the grid type. +(It will have either :ref:`get_grid_rank` or :ref:`get_grid_size` elements.) +See :ref:`model_grids` for more information. + +**Implementation notes** + +* This function is used for describing :ref:`rectilinear `, + :ref:`structured quadrilateral `, + and all :ref:`unstructured ` grids. +* In Python, the *z* argument is a :term:`numpy ` array. +* In C++, this is a void function. + +[:ref:`grid_funcs` | :ref:`basic_model_interface`] + + +.. _get_grid_node_count: + +*get_grid_node_count* +..................... .. code-block:: java - int get_grid_origin(in int id, out array origin) - int get_grid_spacing(in int id, out array spacing) + /* SIDL */ + int get_grid_node_count(in int grid, out int count); -.. image:: images/mesh_uniform_rectilinear.png - :scale: 20 % +Get the number of :term:`nodes ` in the grid. -A uniform rectilinear (or Cartesian grid) is a special case of -a grid of quadrilaterals such that the elements have equal width -in each dimension. That is, for a 2D grid, elements have a -constant width of ``dx`` in the *x-direction* and ``dy`` in the -*y-direction*. The case of ``dx == dy`` is oftentimes called -as *raster grid*. +**Implementation notes** -To completely define points of a uniform rectilinear grid, -one needs only three pieces of information. Namely, the -number of elements in each dimension (:ref:`get_grid_shape`), -the width of each element (in each dimension) and the location -of the corner of the grid. +* This function is used for describing :ref:`unstructured + ` grids. +* In C++ and Python, the *count* argument is omitted and the node + count is returned from the function. -``get_grid_spacing`` provides the width of each element in -the number of dimension as returned by :ref:`get_grid_rank`. -The spacing is *ij-indexing* order. That is spacing in rows -followed by spacing in columns. +[:ref:`grid_funcs` | :ref:`basic_model_interface`] -``get_grid_origin`` provides the location of the lower-left -corner of the grid (also in *ij-indexing* order). +.. _get_grid_edge_count: -Rectilinear -^^^^^^^^^^^ +*get_grid_edge_count* +..................... .. code-block:: java - int get_grid_rank(in int id) - int get_grid_size(in int id) - int get_grid_shape(in int id, out array shape) - int get_grid_x(in int id, out array x) - int get_grid_y(in int id, out array y) - int get_grid_z(in int id, out array z) + /* SIDL */ + int get_grid_edge_count(in int grid, out int count); -.. image:: images/mesh_rectilinear.png - :scale: 20 % +Get the number of :term:`edges ` in the grid. -A rectilinear grid is simply a uniform rectilinear grid whose spacing -in a single dimension varies (as shown in the above image). In this -case, an array of coordinates for each row and column (for 2D) is -required. +**Implementation notes** -``get_grid_y`` provides an array (whose length is the number of -*rows*) that gives the y-coordinate for each row. +* This function is used for describing :ref:`unstructured + ` grids. +* In C++ and Python, the *count* argument is omitted and the edge + count is returned from the function. -``get_grid_x`` provides an array (whose length is the number of -*columns*) that gives the x-coordinate for each column. +[:ref:`grid_funcs` | :ref:`basic_model_interface`] -.. _structured_quad: +.. _get_grid_face_count: -Structured quadrilaterals -^^^^^^^^^^^^^^^^^^^^^^^^^ +*get_grid_face_count* +..................... .. code-block:: java - int get_grid_rank(in int id) - int get_grid_size(in int id) - int get_grid_shape(in int id, out array shape) - int get_grid_x(in int id, out array x) - int get_grid_y(in int id, out array y) - int get_grid_z(in int id, out array z) + /* SIDL */ + int get_grid_face_count(in int grid, out int count); -.. image:: images/mesh_structured_quad.png - :scale: 20 % +Get the number of :term:`faces ` in the grid. -The most general structured quadrilateral grid is one whose -rows (and columns) do not share a common coordinate. In this -case, coordinates are required for each grid element. For this -more general case, ``get_grid_x`` and ``get_grid_y`` are -repurposed to provide this information. +**Implementation notes** -``get_grid_y`` returns an array (whose length is the number -of total nodes) of y-coordinates. +* This function is used for describing :ref:`unstructured + ` grids. +* In C++ and Python, the *count* argument is omitted and the face + count is returned from the function. -``get_grid_x`` returns an array (whose length is the number -of total nodes) of x-coordinates. +[:ref:`grid_funcs` | :ref:`basic_model_interface`] -.. _unstructured_mesh: -Unstructured ------------- +.. _get_grid_edge_nodes: + +*get_grid_edge_nodes* +..................... .. code-block:: java - int get_grid_rank(in int id) + /* SIDL */ + int get_grid_edge_nodes(in int grid, out array edge_nodes); + +Get the edge-node connectivity. + +For each edge, connectivity is given as node at edge tail, followed by +node at edge head. + +**Implementation notes** + +* This function is used for describing :ref:`unstructured + ` grids. +* In Python, the *edge_nodes* argument is a :term:`numpy ` array. +* In C++, this is a void function. + +[:ref:`grid_funcs` | :ref:`basic_model_interface`] + + +.. _get_grid_face_edges: + +*get_grid_face_edges* +..................... + +.. code-block:: java + + /* SIDL */ + int get_grid_face_edges(in int grid, out array face_edges); + +Get the face-edge connectivity. + +**Implementation notes** + +* This function is used for describing :ref:`unstructured + ` grids. +* In Python, the *face_edges* argument is a :term:`numpy ` array. +* In C++, this is a void function. + +[:ref:`grid_funcs` | :ref:`basic_model_interface`] + + +.. _get_grid_face_nodes: + +*get_grid_face_nodes* +..................... + +.. code-block:: java + + /* SIDL */ + int get_grid_face_nodes(in int grid, out array face_nodes); + +Get the face-node connectivity. + +For each face, the nodes (listed in a counter-clockwise direction) +that form the boundary of the face. + +**Implementation notes** + +* This function is used for describing :ref:`unstructured + ` grids. +* In Python, the *face_nodes* argument is a :term:`numpy ` array. +* In C++, this is a void function. + +[:ref:`grid_funcs` | :ref:`basic_model_interface`] + + +.. _get_grid_nodes_per_face: + +*get_grid_nodes_per_face* +......................... + +.. code-block:: java - int get_grid_x(in int id, out array x) - int get_grid_y(in int id, out array y) - int get_grid_z(in int id, out array z) + /* SIDL */ + int get_grid_nodes_per_face(in int grid, out array nodes_per_face); - int get_grid_node_count(in int grid) - int get_grid_edge_count(in int grid) - int get_grid_face_count(in int grid) +Get the number of nodes for each face. - int get_grid_edge_nodes(in int grid, out array edge_nodes) - int get_grid_face_edges(in int grid, out array face_edges) - int get_grid_face_nodes(in int grid, out array face_nodes) - int get_grid_nodes_per_face(in int grid, out array nodes_per_face) +**Implementation notes** -This is the most general grid type and can be used for any type of grid. -However, most grids that consist of 4-sided polygons can be represented -using one of the other grid types. This grid type must be used if -the grid consists of any elements or *cells* that do not have four sides. -This includes any grid of triangles (e.g. -`Delaunay triangles `_ -and a -`Voronoi tesselation `_. +* This function is used for describing :ref:`unstructured + ` grids. +* In Python, the *nodes_per_face* argument is a :term:`numpy ` array. +* In C++, this is a void function. -Note that a grid of -`equilateral triangles `_, -while is most certainly *structured*, would need to be represented -as an unstructured grid. The same is true for a grid of -`hexagons `_. +[:ref:`grid_funcs` | :ref:`basic_model_interface`] diff --git a/docs/source/bmi.implementation.rst b/docs/source/bmi.implementation.rst new file mode 100644 index 0000000..0a51fd4 --- /dev/null +++ b/docs/source/bmi.implementation.rst @@ -0,0 +1,75 @@ +.. _implementation: + +BMI best practices +================== + +BMI is a simple concept---it's just a set of functions +with rules for the function names, arguments, and returns. +However, when implementing a BMI, the devil is often in the details. +In no particular order, +here are some tips to help when writing a BMI for a model. + +* All functions in the BMI must be implemented. For example, even if a + model operates on a :ref:`uniform rectilinear ` + grid, a :ref:`get_grid_x` function has to be written. This function + can be empty and simply return the ``BMI_FAILURE`` status code or + raise a ``NotImplemented`` exception, depending on the language. + +* The :ref:`BMI functions ` listed in the + documentation are the minimum required. Optional functions that act + as helpers can be added to a model's BMI. For example, an + `update_frac` function that updates a model's state by a fractional + time step is a common addition to a BMI. + +* Implementation details are left up to the model developer. All that + the BMI specifies are the names of the functions, their arguments, + and their return values. + +* Constructs and features that are natural for the language should be + used when implementing a BMI. BMI strives to be developer-friendly. + +* BMI functions always use flattened, one-dimensional arrays. This + avoids any issues stemming from row/column-major indexing when + coupling models written in different languages. It's the developer's + responsibility to ensure that array information is + flattened/redimensionalized in the correct order. + +* Avoid using global variables, if possible. This isn't strictly a BMI + requirement, but if a model only uses local variables, its BMI will + be self-contained. This may allow multiple instances of the model to + be run simultaneously, possibly permitting the model to be coupled + with itself. + +* Boundary conditions, including boundary conditions that change with + the model state, can be represented with :term:`exchange items + `. + +* :term:`Configuration files ` are typically text + (e.g., `YAML`_ is preferred by CSDMS), but this isn't a strict + requirement; binary data models such as `HDF5`_ and `netCDF`_ also + work well for storing configuration data. + +* Before fitting a model with a BMI, the model code may have to be + :term:`refactored ` into modular *initialize-run-finalize* + (IRF) steps in order to interact with the BMI functions. This is often + the most difficult part of adding a BMI, but the modularization + tends to improve the quality of the code. + +* Avoid allocating memory within a BMI function. Memory allocation is + typically the responsibility of the model. This helps keep the BMI + middleware layer thin. + +* Be sure to check out the examples: `C`_, `C++`_, `Fortran`_, `Python`_. Although + they wrap a very simple model, they give useful insights into how a + BMI can be implemented in each language. + + +.. Links: + +.. _YAML: https://yaml.org/ +.. _HDF5: https://www.hdfgroup.org/solutions/hdf5/ +.. _netCDF: https://www.unidata.ucar.edu/software/netcdf/ +.. _C: https://github.com/csdms/bmi-example-c +.. _C++: https://github.com/csdms/bmi-example-cxx +.. _Fortran: https://github.com/csdms/bmi-example-fortran +.. _Python: https://github.com/csdms/bmi-example-python diff --git a/docs/source/bmi.info_funcs.rst b/docs/source/bmi.info_funcs.rst index 74475fd..5ceab74 100644 --- a/docs/source/bmi.info_funcs.rst +++ b/docs/source/bmi.info_funcs.rst @@ -1,141 +1,139 @@ -Model Information Functions -=========================== +.. _info_funcs: -These BMI functions provide lists of names for the variables that -a model uses (`get_input_var_names`) and provides -(`get_output_var_names`). +Model information functions +--------------------------- -Input and output variable names -------------------------------- +These functions supply the model name +and the model's :term:`exchange items ` -- +the variables that the model can use from +and provide to other models that have a BMI. + +.. _get_component_name: + +*get_component_name* +.................... .. code-block:: java /* SIDL */ - array get_input_var_names(); - array get_output_var_names(); + int get_component_name(out string name); + +This function supplies the name of the model component as a string. +There are no restrictions on the name, +but it should be unique to prevent conflicts with other components. -.. code-block:: c +**Implementation notes** - /* C */ - int get_input_var_name_count(void *handle, int *count); - int get_output_var_name_count(void *handle, int *count); - int get_input_var_names(void *handle, char **names); - int get_output_var_names(void *handle, char **names); +* In C and Fortran, the *name* argument is a a character array. + In C++ and Python, this argument is omitted, and a string -- a basic type + in these languages -- is returned from the function. -.. code-block:: c++ +[:ref:`info_funcs` | :ref:`basic_model_interface`] - /* C++ */ - int GetInputVarNameCount(void); - int GetOutputVarNameCount(void); - void GetInputVarNames(char * const * const names); - void GetOutputVarNames(char * const * const names); -.. code-block:: fortran +.. _get_input_item_count: - ! Fortran (>=2003) - integer function get_input_var_name_count(this, count) - integer function get_output_var_name_count(this, count) - class (*), intent(in) :: this - integer, intent(out) :: count - integer function get_input_var_names(this, names) - integer function get_output_var_names(this, names) - class (*), intent(in) :: this - character (len=*), pointer, intent(out) :: names(:) +*get_input_item_count* +...................... +.. code-block:: java + + /* SIDL */ + int get_input_item_count(out int count); -`get_input_var_names` returns a string array of the model's -*input variable* names as, preferably, CSDMS Standard Names. -Likewise `get_output_var_names` returns a string array of the -model's *output variable* names as CSDMS Standard Names. +The number of variables the model can use from other models +implementing a BMI. +**Implementation notes** -Component name --------------- +* In C++ and Python, the argument is omitted and the count is returned + from the function. + +[:ref:`info_funcs` | :ref:`basic_model_interface`] + + +.. _get_output_item_count: + +*get_output_item_count* +....................... .. code-block:: java /* SIDL */ - string get_component_name() + int get_output_item_count(out int count); -.. code-block:: c +The number of variables the model can provide other models +implementing a BMI. - /* C */ - int get_component_name(void *handle, char * name); +**Implementation notes** -.. code-block:: c++ +* In C++ and Python, the argument is omittedq and the count is + returned from the function. - /* C++ */ - void GetComponentName(char * const name); +[:ref:`info_funcs` | :ref:`basic_model_interface`] -.. code-block:: fortran - ! Fortran (>=2003) - intger function get_component_name(this, name) - class (*), intent(in) :: this - character (len=*), pointer, intent(out) :: name +.. _get_input_var_names: +*get_input_var_names* +..................... -Return the name of the model as a string. We don't impose any -restrictions on the model name but it should be unique name -so as not to clash with other components. +.. code-block:: java -Model attributes ----------------- + /* SIDL */ + int get_input_var_names(out array names); -.. code-block:: java +Gets an array of names for the variables the model can use from other +models implementing a BMI. +The length of the array is given by :ref:`get_input_item_count`. +The names are preferably in the form of CSDMS :term:`Standard Names`. +Standard Names enable a modeling framework to determine whether an +input variable in one model is equivalent to, or compatible with, +an output variable in another model. +This allows the framework to automatically connect components. +Standard Names do not have to be used within the model. + +**Implementation notes** + +* In C and Fortran, the names are passed back as an array of character + pointers (because the variable names could have differing lengths). +* In C++, the argument is omitted and the names are returned from the + function in a vector, a standard container in the language. +* In Python, the argument is omitted and the names are returned from the + function in a tuple, a standard container in the language. +* A model may have no input variables. + +[:ref:`info_funcs` | :ref:`basic_model_interface`] - string get_attribute(in string att_name) - -.. note:: `get_attribute` is part of BMI++ - -`get_attribute` returns an attribute value as a string. These -attributes do not change from one model instance to another). -Examples of possible attributes are: - -* model_name -* version (e.g. 2.0.1) -* author_name -* grid_type -* time_step_type -* step_method (e.g. explicit, implicit, semi_implicit, iterative) - -For the *grid_type* attribute (see ''Grid Information Functions'' -below), examples of allowed return values are: - -* uniform_grid -* rectilinear_grid -* structured_grid -* unstructured_grid -* none - -For the "time_step_type" attribute, examples of allowed return values -are: - -* fixed (Timestep size is fixed for all time and is used by all grid cells.) -* adaptive (Timestep varies in time, but is used by all grid cells.) -* des (Timestep size varies in both space and time. See below.) -* none (State variables do not vary in time.) - -Note that `Discrete Event Simulation -`_ -(DES) models allow each grid cell to have its -own, adaptive time step. - -The "grid_type" attribute can be used by a framework to automatically -perform spatial regridding when coupled models use different grids as -well as to determine which grid control functions are implemented for -the model. - -The "time_step_type" attribute and BMI functions like -`get_time_step` below are used by a framework to automatically -accommodate time step differences between coupled models. - -For time-stepping models ("time_step_type" other than "none"), the -"step_method" attribute is used to distinguish between "explicit" -and "implicit" numerical solution schemes. Some "models" - like -root finders and "successive over relaxation" (SOR) solvers - -involve iterations as opposed to "time steps". They would return -a "time_step_type" attribute of "none" and a "step_method" attribute -of "iterative". Note that their `update` function still gives the -caller fine-grained control. +.. _get_output_var_names: + +*get_output_var_names* +...................... + +.. code-block:: java + + /* SIDL */ + int get_output_var_names(out array names); + +Gets an array of names for the variables the model can provide to other +models implementing a BMI. +The length of the array is given by :ref:`get_output_item_count`. +The names are preferably in the form of CSDMS :term:`Standard Names`. +Standard Names enable a modeling framework to determine whether an +input variable in one model is equivalent to, or compatible with, +an output variable in another model. +This allows the framework to automatically connect components. +Standard Names do not have to be used within the model. + +**Implementation notes** + +* In C and Fortran, the names are passed back as an array of character + pointers (because the variable names could have differing lengths). +* In C++, the argument is omitted and the names are returned from the + function in a vector, a standard container in the language. +* In Python, the argument is omitted and the names are returned from the + function in a tuple, a standard container in the language. +* A model may have no output variables. + +[:ref:`info_funcs` | :ref:`basic_model_interface`] diff --git a/docs/source/bmi.lang.c.rst b/docs/source/bmi.lang.c.rst deleted file mode 100644 index 253f377..0000000 --- a/docs/source/bmi.lang.c.rst +++ /dev/null @@ -1,5 +0,0 @@ -C -= - -.. literalinclude:: ../../bmi.h - :language: c diff --git a/docs/source/bmi.lang.cxx.rst b/docs/source/bmi.lang.cxx.rst deleted file mode 100644 index 3c27276..0000000 --- a/docs/source/bmi.lang.cxx.rst +++ /dev/null @@ -1,5 +0,0 @@ -C++ -=== - -.. literalinclude:: ../../bmi.hxx - :language: c++ diff --git a/docs/source/bmi.lang.fortran.rst b/docs/source/bmi.lang.fortran.rst deleted file mode 100644 index 62d49e6..0000000 --- a/docs/source/bmi.lang.fortran.rst +++ /dev/null @@ -1,10 +0,0 @@ -Fortran -======= - -Unlike other languages, -Fortran doesn’t really do headers. -The code below is the actual Fortran interface -(the "I" in BMI). - -.. literalinclude:: ../../bmi.f90 - :language: fortran diff --git a/docs/source/bmi.lang.py.rst b/docs/source/bmi.lang.py.rst deleted file mode 100644 index ee66f01..0000000 --- a/docs/source/bmi.lang.py.rst +++ /dev/null @@ -1,5 +0,0 @@ -Python -====== - -.. literalinclude:: ../../bmi.py - :language: python diff --git a/docs/source/bmi.lang.rst b/docs/source/bmi.lang.rst deleted file mode 100644 index 27a7a15..0000000 --- a/docs/source/bmi.lang.rst +++ /dev/null @@ -1,17 +0,0 @@ -BMI Bindings ------------- - -The following header files demonstrate how the BMI specification -is expressed in different languages. - -.. toctree:: - :maxdepth: 1 - - bmi.lang.sidl - bmi.lang.c - bmi.lang.cxx - bmi.lang.py - bmi.lang.fortran - -Download the language file of your choice -and use it to implement a BMI for a model. diff --git a/docs/source/bmi.lang.sidl.rst b/docs/source/bmi.lang.sidl.rst deleted file mode 100644 index f6bfde8..0000000 --- a/docs/source/bmi.lang.sidl.rst +++ /dev/null @@ -1,5 +0,0 @@ -SIDL -==== - -.. literalinclude:: ../../bmi.sidl - :language: java diff --git a/docs/source/bmi.spec.rst b/docs/source/bmi.spec.rst index 29bd0cc..1e53744 100644 --- a/docs/source/bmi.spec.rst +++ b/docs/source/bmi.spec.rst @@ -1,50 +1,138 @@ -The *Basic Model Interface (BMI)* is a simple interface +The *Basic Model Interface* (BMI) is a library specification created by the `Community Surface Dynamics Modeling System`_ (CSDMS) -to facilitate the conversion of a numerical model into a reusable, -plug-and-play component. -A model exposing a BMI can be integrated into -the `CSDMS Python Modeling Toolkit`_ (*pymt*) -and used within Python. - -Recall that, in this context, -an *interface* is a named set of functions with prescribed -function names, argument types and return types. The BMI functions -make a model *self-describing* and fully *controllable* by a -modeling framework or application. - +to facilitate the conversion of a model or dataset +into a reusable, plug-and-play component. +Recall that, in this context, an interface is a named set of functions +with prescribed arguments and return values. +The BMI functions make a model self-describing and fully controllable +by a modeling framework or application. By design, the BMI functions are straightforward to implement in -any language and use only simple, universal, data types. While the -:ref:`cmf` -supports C, C++, Fortran, Java, -and Python, a BMI can be written for any language. CSDMS -provides `example`_ BMI bindings in each of the above languages. - -Also by design, the BMI functions are *noninvasive*. This means -that a BMI-compliant model does not make any calls to other +any language, using only simple data types from standard language libraries. +Also by design, the BMI functions are noninvasive. +This means that a model's BMI does not make calls to other components or tools and is not modified to use any -framework-specific data structures. BMI therefore introduces no -dependencies into a model and the model can still be used -in a *stand-alone* manner. +framework-specific data structures. A BMI, therefore, introduces no +dependencies into a model, so the model can still be used +in a stand-alone manner. + +While a BMI can be written for any language, +CSDMS currently supports four languages: +C, C++, Fortran, and Python. +The specification for each language is given in Table 1, +along with a corresponding example +in which the BMI is implemented. + +.. table:: **Table 1:** BMI language specifications. + :align: center + :widths: 20, 25, 25, 30 + + ======== ============= ============== ====================== + Language Specification Repository Example + ======== ============= ============== ====================== + C `bmi.h`_ `bmi-c`_ `bmi-example-c`_ + C++ `bmi.hxx`_ `bmi-cxx`_ `bmi-example-cxx`_ + Fortran `bmi.f90`_ `bmi-fortran`_ `bmi-example-fortran`_ + Python `bmi.py`_ `bmi-python`_ `bmi-example-python`_ + ======== ============= ============== ====================== + +A complete description of the functions that make up the BMI is given next. + + +.. _basic_model_interface: + +The Basic Model Interface +========================= + +The functions that comprise the Basic Model Interface +can be grouped into categories: + +* :ref:`control_funcs` +* :ref:`info_funcs` +* :ref:`var_funcs` +* :ref:`time_funcs` +* :ref:`getter_setter_funcs` +* :ref:`grid_funcs` + +Table 2 lists the individual BMI functions +along with a brief description. +Following the table is a detailed description of each function, +including the function prototype in SIDL, +grouped by functional category. -BMI Specification -================= +.. table:: **Table 2:** Summary of BMI functions. + :align: center + :widths: 30, 70 -Detailed descriptions of the BMI functions -are grouped by functional category below. + ============================== ========================================= + Function Description + ============================== ========================================= + :ref:`initialize` Perform startup tasks for the model. + :ref:`update` Advance model state by one time step. + :ref:`update_until` Advance model state until the given time. + :ref:`finalize` Perform tear-down tasks for the model. + :ref:`get_component_name` Name of the model. + :ref:`get_input_item_count` Count of a model's input variables. + :ref:`get_output_item_count` Count of a model's output variables. + :ref:`get_input_var_names` List of a model's input variables. + :ref:`get_output_var_names` List of a model's output variables. + :ref:`get_var_grid` Get the grid identifier for a variable. + :ref:`get_var_type` Get the data type of a variable. + :ref:`get_var_units` Get the units of a variable. + :ref:`get_var_itemsize` Get the size (in bytes) of one element of a variable. + :ref:`get_var_nbytes` Get the total size (in bytes) of a variable. + :ref:`get_var_location` Get the grid element type of a variable. + :ref:`get_current_time` Current time of the model. + :ref:`get_start_time` Start time of the model. + :ref:`get_end_time` End time of the model. + :ref:`get_time_units` Time units used in the model. + :ref:`get_time_step` Time step used in the model. + :ref:`get_value` Get a copy of values of a given variable. + :ref:`get_value_ptr` Get a reference to the values of a given variable. + :ref:`get_value_at_indices` Get variable values at specific locations. + :ref:`set_value` Set the values of a given variable. + :ref:`set_value_at_indices` Set the values of a variable at specific locations. + :ref:`get_grid_rank` Get the number of dimensions of a computational grid. + :ref:`get_grid_size` Get the total number of elements of a computational grid. + :ref:`get_grid_type` Get the grid type as a string. + :ref:`get_grid_shape` Get the dimensions of a computational grid. + :ref:`get_grid_spacing` Get the spacing between grid nodes. + :ref:`get_grid_origin` Get the origin of a grid. + :ref:`get_grid_x` Get the locations of a grid's nodes in dimension 1. + :ref:`get_grid_y` Get the locations of a grid's nodes in dimension 2. + :ref:`get_grid_z` Get the locations of a grid's nodes in dimension 3. + :ref:`get_grid_node_count` Get the number of nodes in the grid. + :ref:`get_grid_edge_count` Get the number of edges in the grid. + :ref:`get_grid_face_count` Get the number of faces in the grid. + :ref:`get_grid_edge_nodes` Get the edge-node connectivity. + :ref:`get_grid_face_edges` Get the face-edge connectivity. + :ref:`get_grid_face_nodes` Get the face-node connectivity. + :ref:`get_grid_nodes_per_face` Get the number of nodes for each face. + ============================== ========================================= -.. toctree:: - :maxdepth: 1 +.. include:: bmi.control_funcs.rst +.. include:: bmi.info_funcs.rst +.. include:: bmi.var_funcs.rst +.. include:: bmi.time_funcs.rst +.. include:: bmi.getter_setter.rst +.. include:: bmi.grid_funcs.rst - bmi.control_funcs - bmi.info_funcs - bmi.time_funcs - bmi.var_funcs - bmi.getter_setter - bmi.grid_funcs .. Links .. _Community Surface Dynamics Modeling System: https://csdms.colorado.edu -.. _CSDMS Python Modeling Toolkit: https://pymt.readthedocs.io -.. _example: https://github.com/csdms/bmi/tree/master/bindings +.. _bmi.h: https://github.com/csdms/bmi-c/blob/master/bmi.h +.. _bmi.hxx: https://github.com/csdms/bmi-cxx/blob/master/bmi.hxx +.. _bmi.f90: https://github.com/csdms/bmi-fortran/blob/master/bmi.f90 +.. _bmi.py: https://github.com/csdms/bmi-python/blob/master/bmipy/bmi.py +.. _bmi-c: https://github.com/csdms/bmi-c +.. _bmi-cxx: https://github.com/csdms/bmi-cxx +.. _bmi-fortran: https://github.com/csdms/bmi-fortran +.. _bmi-python: https://github.com/csdms/bmi-python +.. _bmi-example-c: https://github.com/csdms/bmi-example-c +.. _bmi-example-cxx: https://github.com/csdms/bmi-example-cxx +.. _bmi-example-fortran: https://github.com/csdms/bmi-example-fortran +.. _bmi-example-python: https://github.com/csdms/bmi-example-python +.. _UDUNITS: http://www.unidata.ucar.edu/software/udunits/ +.. _The Units Database: https://www.unidata.ucar.edu/software/udunits/udunits-current/doc/udunits/udunits2.html#Database +.. _time unit conventions: https://www.unidata.ucar.edu/software/udunits/udunits-current/udunits/udunits2-accepted.xml diff --git a/docs/source/bmi.time_funcs.rst b/docs/source/bmi.time_funcs.rst index b021ad3..9ce26a5 100644 --- a/docs/source/bmi.time_funcs.rst +++ b/docs/source/bmi.time_funcs.rst @@ -1,46 +1,118 @@ +.. _time_funcs: + Time functions -============== +-------------- + +These simple diagnostic functions provide information on model time. +Model time is always expressed as a floating point value. + +.. _get_current_time: + +*get_current_time* +.................. + +.. code-block:: java + + /* SIDL */ + int get_current_time(out double time); + +The current model time. + +**Implementation notes** + +* In C++ and Python, the argument is omitted and the time is returned + from the function. + +[:ref:`time_funcs` | :ref:`basic_model_interface`] + + +.. _get_start_time: + +*get_start_time* +................ + +.. code-block:: java + + /* SIDL */ + int get_start_time(out double time); + +The start time of the model. + +**Implementation notes** + +* The start time in BMI is typically defined to be 0.0. +* In C++ and Python, the argument is omitted and the time is returned + from the function. + +[:ref:`time_funcs` | :ref:`basic_model_interface`] + + +.. _get_end_time: + +*get_end_time* +................ .. code-block:: java - double get_time_step() - string get_time_units() - double get_start_time() - double get_current_time() - double get_end_time() + /* SIDL */ + int get_end_time(out double time); + +The end time of the model. + +**Implementation notes** + +* If the model doesn't define an end time, a large number (e.g., + 1.0e6) is typically chosen. +* In C++ and Python, the argument is omitted and the time is returned + from the function. + +[:ref:`time_funcs` | :ref:`basic_model_interface`] -Time units ----------- .. _get_time_units: +*get_time_units* +................ + .. code-block:: java - string get_time_units() + /* SIDL */ + int get_time_units(out string units); + +Get the units of time as reported by the model's BMI (through +:ref:`get_current_time`, :ref:`get_end_time`, etc.). +It's recommended to use `time unit conventions`_ from Unidata's +`UDUNITS`_ package; e.g., `s`, `min`, `h`, `d`. + +**Implementation notes** + +* Avoid using `years` as a unit, if possible, since a year is + difficult to define precisely. +* In C++ and Python, the argument is omitted and the units are returned + from the function. -Return the units of time as reported by the model's BMI (through -`get_current_time`_, `get_end_time`_, etc.). -CSDMS recommends using time unit conventions from Unidata's -`UDUNITS `_ package. +[:ref:`time_funcs` | :ref:`basic_model_interface`] -Time step ---------- .. _get_time_step: +*get_time_step* +............... + .. code-block:: java - double get_time_step() + /* SIDL */ + int get_time_step(out double time_step); -Time ----- +Get the time step used in the model. +The time step is always expressed as a floating point value. -.. _get_current_time: -.. _get_start_time: -.. _get_end_time: +**Implementation notes** -.. code-block:: java +* A time step is typically a positive value. However, if the model + permits it, a negative value can be used (running the model + backward). +* In C++ and Python, the argument is omitted and the time step is returned + from the function. - double get_start_time() - double get_current_time() - double get_end_time() +[:ref:`time_funcs` | :ref:`basic_model_interface`] diff --git a/docs/source/bmi.var_funcs.rst b/docs/source/bmi.var_funcs.rst index aaf7250..6f42c2d 100644 --- a/docs/source/bmi.var_funcs.rst +++ b/docs/source/bmi.var_funcs.rst @@ -1,69 +1,169 @@ -Variable Information Functions -============================== +.. _var_funcs: -These BMI functions are called a framework to obtain information -about a particular input or output variable. They must -accommodate any variable that is returned by the BMI functions -`get_input_var_names` or `get_output_var_names`. Based on this -information, a framework can apply type or unit conversion when -necessary. +Variable information functions +------------------------------ + +These BMI functions provide information +about a particular input or output variable. +They must accommodate any variable returned from the +:ref:`get_input_var_names` or :ref:`get_output_var_names` functions -- +the variable name is used as an argument in each function. +Based on the information returned, +type or unit conversions can be applied when necessary. .. _get_var_grid: -Variables grids ---------------- +*get_var_grid* +.............. .. code-block:: java - int get_var_grid(in string name) - string get_var_location(in string name) + /* SIDL */ + int get_var_grid(in string name, out int grid); -Each variable is associated with a grid on which the variable is defined. -A single model can have one or more grids. `get_var_grid` returns an -id (as an `int`) to its grid. That id is then passed to the BMI -:ref:`get_grid` functions to get information about a particular grid -(x and y coordinates, size, etc.). The `get_var_location` function, -given a variable name, returns a string that indicates on what grid -element the variable is defined. Valid return values are `"node"`, -`"edge"`, and `"face"`. +Each input and output variable is defined on a grid. +(Available grid types are listed in the :ref:`grid_funcs` section.) +The `get_var_grid` function provides the identifier (an integer) for this grid. +The identifier can be passed to the BMI +:ref:`grid information ` functions +to get the details of a particular grid; +e.g., *x*- and *y*-coordinates, size, type, etc. +A model can have one or more grids. + +**Implementation notes** + +* Grid identifiers start at 0. +* In C++ and Python, the *grid* argument is omitted and the grid + identifier is returned from the function. + +[:ref:`var_funcs` | :ref:`basic_model_interface`] + + +.. _get_var_type: + +*get_var_type* +.............. + +.. code-block:: java + + /* SIDL */ + int get_var_type(in string name, out string type); + +The `get_var_type` function provides the data type of the +variable as it's stored in memory by the model. +The data type is returned as a string following the :term:`numpy` convention +used by the `dtype`_ attribute; e.g., `int32`, `float`, etc. -Variable units --------------- +**Implementation notes** + +* In C++ and Python, the *type* argument is omitted and the variable + type name is returned from the function. + +[:ref:`var_funcs` | :ref:`basic_model_interface`] + + +.. _get_var_units: + +*get_var_units* +............... .. code-block:: java - string get_var_units(in string name) + /* SIDL */ + int get_var_units(in string name, out string units); +Get the units of the given variable. Standard unit names, in lower case, should be used, such as `meters` -or `seconds`. Standard abbreviations, like `m` for meters, are +or `seconds`. +Standard abbreviations, such as `m` for meters, are also supported. For variables with compound units, each unit name is separated by a single space, with exponents other than 1 placed immediately after the name, as in `m s-1` for velocity, `W m-2` for -an energy flux, or `km2` for an area. Please see -`udunits `_ for a +an energy flux, or `km2` for an area. +The abbreviations used in the BMI are derived from +Unidata's `UDUNITS`_ package. +See, for example, `The Units Database`_ for a full description of valid unit names and a list of supported units. -Variable data type ------------------- +**Implementation notes** + +* In C++ and Python, the *units* argument is omitted and the variable + units name is returned from the function. + +[:ref:`var_funcs` | :ref:`basic_model_interface`] + + +.. _get_var_itemsize: + +*get_var_itemsize* +.................. .. code-block:: java - string get_var_type(in string name) - int get_var_itemsize(in string name) - int get_var_nbytes(in string name) + /* SIDL */ + int get_var_itemsize(in string name, out int size); + +The `get_var_itemsize` function provides the size, in bytes, +of a single element of the variable. +For example, if data for a variable are stored as 64-bit integers, +`get_var_itemsize` would return 8. + +**Implementation notes** + +* In C++ and Python, the *size* argument is omitted and the item size + is returned from the function. + +[:ref:`var_funcs` | :ref:`basic_model_interface`] + + +.. _get_var_nbytes: + +*get_var_nbytes* +................ + +.. code-block:: java + + /* SIDL */ + int get_var_nbytes(in string name, out int nbytes); + +The `get_var_nbytes` function provides the total amount of memory used to store +a variable; i.e., the number of items multiplied by the size of each item. + +**Implementation notes** + +* In C++ and Python, the *nbytes* argument is omitted and the total + amount of memory used by the variable is returned from the function. + +[:ref:`var_funcs` | :ref:`basic_model_interface`] + + +.. _get_var_location: + +*get_var_location* +.................. + +.. code-block:: java + + /* SIDL */ + int get_var_location(in string name, out string location); + +The `get_var_location` function, +given a variable name, returns a string that indicates on what grid +element the variable is defined. Valid return values are: + +* ``node`` +* ``edge`` +* ``face`` + +**Implementation notes** + +* In C++ and Python, the *location* argument is omitted and the location + is returned from the function. -These functions provide information about the size of the data as -it's stored in memory. `get_var_type` returns the data type of the -variable as it's stored by the model. The data type is returned as -a string following the `numpy` convention used by the `dtype` -attribute (`int32`, `float`, etc.). +[:ref:`var_funcs` | :ref:`basic_model_interface`] -`get_var_itemsize` returns the size, in bytes, of each item of the -variable. For example if data for a variable are stored as 64-bit -integers, `get_var_itemsize` would return 8. -`get_var_nbytes` return the total amount of memory used to store -the entire array of data for a variable. That is, the number -of items multiplied by the size of each item. +.. Links +.. _dtype: https://docs.scipy.org/doc/numpy/reference/arrays.dtypes.html diff --git a/docs/source/conf.py b/docs/source/conf.py index aa708f7..41d27db 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -52,17 +52,17 @@ # General information about the project. project = u'bmi' -copyright = u'2017, Eric Hutton' -author = u'Eric Hutton' +copyright = u'2020, Community Surface Dynamics Modeling System' +author = u'Community Surface Dynamics Modeling System' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. -version = '0.1' +version = '2.0' # The full version, including alpha/beta/rc tags. -release = '0.1' +release = '2.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -79,7 +79,15 @@ # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. -exclude_patterns = [] +exclude_patterns = [ + 'bmi.spec.rst', + 'bmi.control_funcs.rst', + 'bmi.info_funcs.rst', + 'bmi.var_funcs.rst', + 'bmi.time_funcs.rst', + 'bmi.getter_setter.rst', + 'bmi.grid_funcs.rst', +] # The reST default role (used for this markup: `text`) to use for all # documents. @@ -240,8 +248,8 @@ # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'bmi.tex', u'bmi Documentation', - u'Eric Hutton', 'manual'), + (master_doc, 'bmi.tex', u'BMI Documentation', + u'Community Surface Dynamics Modeling System', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of @@ -270,7 +278,7 @@ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - (master_doc, 'bmi', u'bmi Documentation', + (master_doc, 'bmi', u'BMI Documentation', [author], 1) ] @@ -284,7 +292,7 @@ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - (master_doc, 'bmi', u'bmi Documentation', + (master_doc, 'bmi', u'BMI Documentation', author, 'bmi', 'One line description of project.', 'Miscellaneous'), ] diff --git a/docs/source/csdms.rst b/docs/source/csdms.rst index 4d773e3..012d081 100644 --- a/docs/source/csdms.rst +++ b/docs/source/csdms.rst @@ -10,6 +10,9 @@ automatically using the CSDMS Babelizer tool, which generates bindings for all of the CSDMS supported languages, so that the model becomes a plug-in for within the CSDMS framework. +.. + "becomes a plug-in for"? I don't understand. + Any model that provides the BMI functions should also be straightforward to ingest as a component into other component-based modeling frameworks. For example, all model coupling frameworks @@ -31,7 +34,7 @@ computational grid is different. It also gains: CSDMS Standard Names -==================== +-------------------- Note that the *name* parameter in many of the BMI functions refers to a standardized variable name from the @@ -51,8 +54,8 @@ output variables. model's internal names. -Model Metadata -============== +Model metadata +-------------- For a model to be incorporated into the CSDMS framework, some additional metadata is required. This metadata describes such things as: diff --git a/docs/source/glossary.rst b/docs/source/glossary.rst new file mode 100644 index 0000000..01a5632 --- /dev/null +++ b/docs/source/glossary.rst @@ -0,0 +1,168 @@ +Glossary +======== + +A glossary of terms used with BMI. + + +.. glossary:: + + $ + + The default shell prompt. + + Anaconda + + A Python distribution that includes libraries for scientific + computing and a package manager. See + https://www.anaconda.com/distribution for more information. + + Basic Model Interface (BMI) + + A set a functions that are used to interact with and control a + model. See https://bmi.readthedocs.io for more information. + + Community Surface Dynamics Modeling System (CSDMS) + + CSDMS is an NSF-funded program that seeks to transform the + science and practice of earth-surface dynamics modeling. For + more information, visit https://csdms.colorado.edu. + + class + + A program that acts as a template for creating + :term:`objects`. + + conda + + The package manager for :term:`Anaconda`. Also an informal name + for an Anaconda installation. + + conda-forge + + A collection of community-built packages distributed by + :term:`Anaconda`. See https://conda-forge.org. + + conda environment + + A :term:`conda` sub-installation that isolates a group of + packages from the main conda installation. + + configuration file + + A file that contains information, including initial values of + parameters, for setting up a :term:`model`. + + coupling + + See :term:`model coupling`. + + data + + Information held by an :term:`object`. + + edge + + A line or curve bounded by two :term:`nodes `. + + exchange item + + A variable that a model with a BMI produces or consumes. + Exchange items are public, not internal variables in the + model. Exchange items should use :term:`Standard Names`. + + face + + A plane or surface enclosed by a set of :term:`edges `. In + a 2D horizontal application one may consider the word "polygon", + but in the hierarchy of elements the term "face" is most common. + See also :term:`node`. + + grid + + A representation of a larger spatial domain by smaller discrete + cells. See :ref:`model_grids` and :ref:`references`, as well as + terms :term:`node`, :term:`edge`, and :term:`face`. + + grid identifier + + A unique object that labels (identifies) a model grid. Grid + identifiers are integers, starting at zero. Often abbreviated + "grid id". They're obtained through the :ref:`get_var_grid` + function. + + grid node + + See :term:`node`. + + import + + The process of bringing code from a Python :term:`module` into + another module or into an interactive Python session. + + instance + + See :term:`object`. + + method + + Programs that act upon the :term:`data` of an :term:`object`. + + model + + A computer program that attempts to describe a physical process + with mathematical relationships that evolve over time and are + solved numerically. For more information, see, for example, + https://en.wikipedia.org/wiki/Numerical_modeling_(geology). + + model configuration file + + A file, usually in a text-based format, that lists the tunable + parameters of a model and supplies their initial values. + + model coupling + + Models are *coupled* when they exchange inputs and outputs, + often at the resolution of individual time steps. *One-way + coupling* occurs when the outputs from one model are used as + inputs to another model. *Two-way coupling* is when outputs from + one model are used as inputs for another model, which in turn + supplies its outputs to the first model as inputs, producing a + feedback. + + module + + A file (with the ``.py`` extension) that contains Python code. + + node + + A point that has a coordinate pair or triplet: the most basic + element of a grid. Variable values are typically calculated at + nodes. See also :term:`face` and :term:`edge`. + + NumPy + + A Python library that provides arrays. Outputs from *pymt* are + NumPy arrays. See also http://www.numpy.org. + + object + + A variable that is a concrete example of a + :term:`class`. Objects have :term:`data` and + :term:`methods` that act upon those data. + + rank + + The number of dimensions of a model grid. A scalar has rank 0, a + vector has rank 1, a rectilinear grid has rank 2, etc. + + refactor + + The act of modifying the internals of a program without changing + the external behaviors of the program. Refactoring is often done + to clean up code and improve its performance. + + Standard Names + + A semantic mediation technology developed at CSDMS for precisely + matching variable names between models. For more information, + see https://csdms.colorado.edu/wiki/CSDMS_Standard_Names. diff --git a/docs/source/index.rst b/docs/source/index.rst index b17b8cb..64b68e9 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -2,14 +2,12 @@ :align: center :scale: 85% :alt: Basic Model Interface (BMI) - :target: https://bmi-spec.readthedocs.org/ + :target: https://bmi.readthedocs.io/ .. title:: BMI .. include:: bmi.spec.rst -.. include:: bmi.lang.rst - Additional Topics ================= @@ -17,7 +15,10 @@ Additional Topics .. toctree:: :maxdepth: 2 + bmi.implementation + model_grids csdms + glossary references Project Information diff --git a/docs/source/model_grids.rst b/docs/source/model_grids.rst new file mode 100644 index 0000000..c4d422e --- /dev/null +++ b/docs/source/model_grids.rst @@ -0,0 +1,177 @@ +.. _model_grids: + +Model grids +=========== + +The Basic Model Interface (BMI) supports several different :term:`grid` types, +described below. +Depending on the grid type +(as returned from the :ref:`get_grid_type` function), +a model will implement a different set of :ref:`grid functions `. + + +.. _structured_grids: + +Structured grids +---------------- + +For the BMI specification, +a structured grid is formed in two dimensions by tiling a domain +with quadrilateral cells so that every interior vertex +is surrounded by four quadrilaterals. +In three dimensions, six-sided polyhedral cells are stacked such that +interior vertices are surrounded by eight cells. + +In the BMI, +dimensional information is ordered with "ij" indexing +(as opposed to "xy"). +For example, +for the uniform rectilinear grid shown below, +the :ref:`get_grid_shape` function would return the array ``[4, 5]``. +If there was a third dimension, +its length would be listed first. + +.. note:: + + The grid shape is the number of :term:`nodes ` in the + coordinate directions, not the number of cells or + elements. It is possible for grid values to be + associated with the nodes or with the cells. + + +.. _uniform_rectilinear: + +Uniform rectilinear +^^^^^^^^^^^^^^^^^^^ + +.. image:: images/mesh_uniform_rectilinear.png + :scale: 20 % + +A uniform rectilinear grid is a special case of structured quadrilateral grid +where the elements have equal width in each dimension. +That is, for a two-dimensional grid, elements have a constant width +of ``dx`` in the *x*-direction and ``dy`` in the *y*-direction. +The case of ``dx == dy`` is oftentimes called +a *raster* or *Catesian grid*. + +To completely specify a uniform rectilinear grid, +only three pieces of information are needed: +the number of elements in each dimension, +the width of each element (in each dimension), +and the location of the corner of the grid. + +Uniform rectilinear grids use the following BMI functions: + +* :ref:`get_grid_rank` +* :ref:`get_grid_size` +* :ref:`get_grid_shape` +* :ref:`get_grid_spacing` +* :ref:`get_grid_origin` + + +.. _rectilinear: + +Rectilinear +^^^^^^^^^^^ + +.. image:: images/mesh_rectilinear.png + :scale: 20 % + +In a rectilinear grid, the spacing between nodes in each dimension varies, +as depicted above. +Therefore, +an array of coordinates for each row and column +(for the two-dimensional case) is required. + +The :ref:`get_grid_y` function provides an array (whose length is the number of +*rows*) that gives the *y*-coordinate for each row. + +The :ref:`get_grid_x` function provides an array (whose length is the number of +*columns*) that gives the *x*-coordinate for each column. + +Rectilinear grids use the following BMI functions: + +* :ref:`get_grid_rank` +* :ref:`get_grid_size` +* :ref:`get_grid_shape` +* :ref:`get_grid_x` +* :ref:`get_grid_y` +* :ref:`get_grid_z` + + +.. _structured_quad: + +Structured quadrilateral +^^^^^^^^^^^^^^^^^^^^^^^^ + +.. image:: images/mesh_structured_quad.png + :scale: 20 % + +The most general structured quadrilateral grid is one where +the rows (and columns) do not share a common coordinate. In this +case, coordinates are required for each grid node. For this +more general case, :ref:`get_grid_x` and :ref:`get_grid_y` are +repurposed to provide this information. + +The :ref:`get_grid_y` function returns an array (whose length is the number +of total nodes returned by :ref:`get_grid_size`) of *y*-coordinates. + +The :ref:`get_grid_x` function returns an array (whose length is the number +of total nodes returned by :ref:`get_grid_size`) of *x*-coordinates. + +Structured quadrilateral grids use the following BMI functions: + +* :ref:`get_grid_rank` +* :ref:`get_grid_size` +* :ref:`get_grid_shape` +* :ref:`get_grid_x` +* :ref:`get_grid_y` +* :ref:`get_grid_z` + + +.. _unstructured_grids: + +Unstructured grids +------------------ + +This category includes the *unstructured* type, +as well as the special cases +*scalar*, *points*, and *vector*. +This is the most general grid type. +It can be used for any type of grid. +This grid type must be used if the grid consists of cells +that are not quadrilaterals; +this includes any grid of triangles (e.g. `Delaunay triangles`_ +and `Voronoi tesselations`_). + +.. note:: + + A grid of `equilateral triangles`_, while they are most certainly + *structured*, would need to be represented as an unstructured grid. + The same is true for a grid of `hexagons`_. + + +BMI uses the `ugrid conventions`_ to define unstructured grids. + +Unstructured grids use the following BMI functions: + +* :ref:`get_grid_rank` +* :ref:`get_grid_x` +* :ref:`get_grid_y` +* :ref:`get_grid_z` +* :ref:`get_grid_node_count` +* :ref:`get_grid_edge_count` +* :ref:`get_grid_face_count` +* :ref:`get_grid_edge_nodes` +* :ref:`get_grid_face_edges` +* :ref:`get_grid_face_nodes` +* :ref:`get_grid_nodes_per_face` + + +.. Links + +.. _Delaunay triangles: http://en.wikipedia.org/wiki/Delaunay_triangulation +.. _Voronoi tesselations: http://en.wikipedia.org/wiki/Voronoi_tessellation +.. _equilateral triangles: http://en.wikipedia.org/wiki/Triangle_tiling +.. _hexagons: http://en.wikipedia.org/wiki/Hexagonal_tiling +.. _ugrid conventions: http://ugrid-conventions.github.io/ugrid-conventions diff --git a/docs/source/references.rst b/docs/source/references.rst index 56a96ac..d26c25c 100644 --- a/docs/source/references.rst +++ b/docs/source/references.rst @@ -1,4 +1,5 @@ -========== +.. _references: + References ========== @@ -23,7 +24,7 @@ Basic Model Interface (BMI) Scientific Interface Definition Language (SIDL) Dahlgren, Tamara; Ebner, Dietmar; Epperly, Thomas; Kumfert, Gary; - Leek, James; Prantl, Adrian (): "Babel User's Guide: Part I + Leek, James; Prantl, Adrian (2012): "Babel User's Guide: Part I Foundation: SIDL Basics". https://computing.llnl.gov/projects/babel-high-performance-language-interoperability/docs/users_guide/index008.html (retrieved 2019-10-09). @@ -33,3 +34,11 @@ Scientific Interface Definition Language (SIDL) Babel". *The International Journal of High Performance Computing Applications*. **26** (3): 260–274. http://dx.doi.org/10.1177/1094342011414036 + +Model grids + + Hoffmann, Klaus A; Chiang, Steve T (2000): Computational Fluid + Dynamics Volume I. Third edition. *Engineering Education System*. + + Slingerland, Rudy; Kump, Lee (2011): Mathematical Modeling of + Earth's Dynamical Systems: A Primer. *Princeton University Press*. diff --git a/examples/c b/examples/c deleted file mode 160000 index 6946093..0000000 --- a/examples/c +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 6946093838298782dda02ff9e06f78f33686e15c diff --git a/examples/cxx b/examples/cxx deleted file mode 160000 index 651e1e5..0000000 --- a/examples/cxx +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 651e1e5c6f0b297b999d751179dea481b060ed04 diff --git a/examples/fortran b/examples/fortran deleted file mode 160000 index 37bc500..0000000 --- a/examples/fortran +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 37bc5006144e7b00bae3375e055b3a1e89a75f71 diff --git a/examples/python b/examples/python deleted file mode 160000 index 2bcb965..0000000 --- a/examples/python +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 2bcb9658d8b5e41df8f817d4a464f230348fa479