Welcome to grpc4bmi’s documentation!

Introduction

The Basic Modeling Interface (BMI, see https://github.com/csdms/bmi) is a multi-language library interface tailored to earth system models. This software allows you to wrap a BMI implementation in a server process and communicate with it via the included python client. The communication is serialized to protocol buffers by GRPC (https://grpc.io/) and occurs over network ports. On the server side, we support BMI implementations in python, R or C/C++. Fortran models need to be linked against the C-version of the BMI. On the client side, we expose the standard python BMI (https://github.com/csdms/bmi-python/).

This setup enables you to wrap your BMI-enabled model in a Docker (https://www.docker.com/) or Singularity (https://singularity.lbl.gov/) or Apptainer (https://apptainer.org) container and communicate with it from a python process on the host machine.

_images/design-overview.svg

Installing requirements

To use grpc4bmi the Python package should be installed.

If your model uses some virtual environment with installed dependencies (e.g. Anaconda or virtualenv), activate this environment before installing grpc4bmi.

Install the grpc4bmi python package with pip:

$ pip install grpc4bmi

This will install the latest release of the package; for the most recent github revision type instead

$ pip install git+https://github.com/eWaterCycle/grpc4bmi.git#egg=grpc4bmi

Creating a BMI server

Python

If you have a BMI-compliant model written in python, grpc4bmi provides a quick way to set up a BMI service.

Installing Requirements

The grpc4bmi Python package should be installed.

Creating

To obtain a python BMI for your model, install the python bmi package and implement the Bmi abstract base class for your model. For exposing this model as a GRPC service, it is necessary to have a constructor without arguments: all initialization state will be presented to the model via the configuration file in the initialize method.

Running

The installation of the grpc4bmi package installs the run-bmi-server command. You can run your model as a service by typing

$ run-bmi-server --name <PACKAGE>.<MODULE>.<CLASS>

where <PACKAGE>, <MODULE> are the python package and module containing your python BMI model, which should contain a python class <CLASS> that implements Bmi. The script assumes that this class does not take any constructor arguments. Upon running, the server will report which networking port it has decided to use on the terminal. This port will later be needed by BMI clients to communicate with your service. The port can also be specified by adding the option --port <PORT> or pre-define the environment variable BMI_PORT.

Example

As an example, suppose we have a package

$ mypackage
$ - __init__.py
$ - mymodule.py

and inside the mymodule.py the bmi implementation

from bmi import Bmi

class MyBmi(Bmi):
    def __init__(self):
        ...
    def get_component_name(self):
        return "Hello world"

Then we launch this toy model as a service by executing

$ run-bmi-server --name mypackage.mymodule.MyBmi

This will report the chosen port number in the standard output stream. It can be used to connect to the service via the BMI grpc python client.

R

Grpc4bmi allows you to wrap a Hydrological model written in the R language into a GRPC server.

Installing Requirements

The bmi-r package can be installed using the following devtools command

devtools::install_github("eWaterCycle/bmi-r")

Creating

A model must implement the basic model interface (bmi).

This can be done by sub-classing the AbstractBmi class found in the bmi-r R package.

A model (in the example called mymodel) can than be given a basic model interface with something like

library(R6)
library(bmi)
library(mymodel)

MyModelBmi <- R6Class(
    inherit = AbstractBmi,
    public = list(
        getComponentName = function() return('mymodel'),
        bmi_initialize = function(config_file) {
            # TODO Construct & initialize mymodel model
        },
        update = function() {
            # TODO evolve mymodel model to next time step
        },
        # TODO implement all other bmi functions
    )
)

For an example of a BMI interface of the Wageningen Lowland Runoff Simulator (WALRUS) see walrus-bmi.r

Running

Once the model has an BMI interface it can be run as a GRPC server by installing the grpc4bmi[R] Python package with

pip install grpc4bmi[R]

The server can be started with

run-bmi-server --lang R [--path <R file with BMI model>] --name [<PACKAGE>::]<CLASS> --port <PORT>

For the WALRUS model the command is

run-bmi-server --lang R --path ~/git/eWaterCycle/grpc4bmi-examples/walrus/walrus-bmi.r --name WalrusBmi --port 50051

The Python grpc4bmi Using the client can then be used to connect to the server.

C/C++/Fortran

Installing Requirements

For native programming languages it is necessary to install and compile the C++ bindings of GRPC and protobuf on your system:

git clone -b $(curl -L https://grpc.io/release) --depth=1 https://github.com/grpc/grpc
cd grpc && git submodule update --init --recursive
sudo make install && cd third_party/protobuf && sudo make install

You will also need to compile the bmi-c and grpc4bmi

git clone --depth=1 https://github.com/eWaterCycle/grpc4bmi.git
cd grpc4bmi && git submodule update --init --recursive
cd cpp/bmi-c && mkdir -p build && cd build
cmake .. && sudo make install
mkdir -p ../../build && cd ../../build && cmake .. && sudo make install

Creating

The grpc4bmi package comes with a C++ abstract base class that contains the BMI functions. The header file will be copied to your system include path upon the installation steps above. Write an implementation of the Bmi class using your model time step code and data structures. You don’t have to worry about global variables in your model code: with grpc4bmi every model instance runs in its own memory space. For the same reason, the get_value_ptr and set_value_ptr methods can be safely ignored, they are never called through the grpc process bridge.

Running

Since native language lack reflection, it is necessary to make your own run_bmi_server program. We provide a function run_bmi_server(Bmi*, int*, char*) in the bmi_grpc_server.h header that can be called with your model instance (see the example below). To compile your server binary, it is necessary to link against grpc4bmi and protobuf libraries. The program will accept a single optional argument which is the port the server will run on. The port can also be specified using the BMI_PORT environment variable. The default port is 50051.

Example

To create a BMI to your model, write a header file in which you declare the overridden functions of the base class Bmi in the included file bmi_class.h.

my_bmi_model.h:

#include <bmi_class.h>

class MyBmiModel: public Bmi
{
    public:
        MyBmiModel();
        int initialize(const char* config_file) override;
        ...
        int get_component_name(char* name) const override;
};

Write your implementation of the basic modeling interface in the corresponding source file

my_bmi_model.cc:

#include <my_bmi_model.h>
#include <cstring>

MyBmiModel::MyBmiModel(){}
int MyBmiModel::initialize(const char* config_file)
{
    /* ...initialize the model from config_file... */
    return BMI_SUCCESS;
}
...
int MyBmiModel::get_component_name(char* name) const
{
    strcpy(name, "Hello world");
    return BMI_SUCCESS;
}

Now the BMI server can be simply be implemented as

run_my_bmi_model.cc:

#include "bmi_grpc_server.h"
#include "my_bmi_model.h"

int main(int argc, char* argv[])
{
    Bmi* model = new HypeBmi();
    run_bmi_server(model, argc, argv);
    delete model;
    return 0;
}

This binary will need to be linked against grpc4bmi and the protobuf libraries:

g++ -o my_bmi_server run_my_bmi_model.o my_bmi_model.o `pkg-config --libs protobuf grpc++ grpc` -Wl,--no-as-needed -lgrpc++_reflection -ldl -lgrpc4bmi
Fortran

In case you have a Fortran model, we advice to write the corresponding functions in Fortran first and export them to the implementation, e.g.

my_bmi_model.f90:

subroutine get_component_name(name) bind(c, name="get_component_name_f")
    use, intrinsic ::iso_c_binding
    implicit none
    character(kind=c_char), intent(out) :: name(*)
    name(1:11)="Hello world"
    name(12)=c_null_char

Now it is possible to call this function from the BMI C implementation as follows,

my_bmi_model.cc:

extern "C" void get_component_name_f(char*)
int MyBmiModel::get_component_name(char* name) const
{
    get_component_name_f(name);
    return BMI_SUCCESS;
}

Using the client

We assume that service is always dedicated to a single client, addressing a BMI model with multiple users at the same time results in undefined behavior.

Python BMI Client

For a given running BMI service process connected to networking port <PORT>, we can start communicating with this server by instantiating the BmiClient python class:

import grpc
from grpc4bmi.bmi_grpc_client import BmiClient

mymodel = BmiClient(grpc.insecure_channel("localhost:<PORT>"))

For the example model launched in Example, the component name can be retrieved following the usual BMI syntax,

print(mymodel.get_component_name())
Hello world

Python Subprocess

This python class launches a BMI server upon creation,

from grpc4bmi.bmi_client_subproc import BmiClientSubProcess

model = BmiClientSubProcess(<PACKAGE>.<MODULE>.<CLASS>)

The code above will execute run-bmi-server in a python subprocess and automatically listen to the appropriate port. Note that this requires your client to run in the same python environment as your model.

Running Python server explains the roles of <PACKAGE>, <MODULE> and <CLASS>.

Polyglot CLI

Once you have started a GRPC server you can test it by connecting to it using the Polyglot - a universal grpc command line client.

Polyglot requires Java and the polglot.yar file can be downloaded at https://github.com/dinowernli/polyglot/releases

The following commands expects a GRPC server running on localhost on port 55555.

To get the component name use

echo '{}' | java -jar polyglot.jar call --endpoint=localhost:55555 --full_method=bmi.BmiService/getComponentName

Building a docker image

The biggest advantage of using grpc4bmi is that you can embed the model code in a container like a Docker image. The grpc bridge allows you to address it from the host machine with the python BMI.

To establish this, install your BMI model and grpc4bmi inside the container, and let run-bmi-server act as the entry point of the docker image.

Python

The docker file for the model container simply contains the installation instructions of grpc4bmi and the BMI-enabled model itself, and as entrypoint the run-bmi-server command. For the python example the Docker file will read

FROM ubuntu:bionic
MAINTAINER your name <your email address>

# Install grpc4bmi
RUN pip install git+https://github.com/eWaterCycle/grpc4bmi.git#egg=grpc4bmi

# Install here your BMI model:
RUN git clone <MODEL-URL> /opt/mymodeldir

# Run bmi server
ENTRYPOINT ["run-bmi-server", "--name", "mypackage.mymodule.MyBmi", "--path", "/opt/mymodeldir"]

# Expose the magic grpc4bmi port
EXPOSE 55555

The port 55555 is the internal port in the Docker container that the model communicates over. It is the default port for run_bmi_server and also the default port that all clients listen to.

R

The Docker image can be made by writing a Dockerfile file like

FROM r-base
LABEL maintainer="Your name <your email address>"

RUN apt update && apt install -t unstable -y python3-dev python3-pip git && \
  pip3 install git+https://github.com/eWaterCycle/grpc4bmi.git#egg=grpc4bmi[R]

RUN install.r remotes && installGithub.r eWaterCycle/bmi-r
RUN install.r <R mymodel library from CRAN>

# Copy BMI interface of model into Docker image
RUN mkdir /opt/
COPY mymodel-bmi.r /opt/

# Config file and forcing file will be mounted at /data
RUN mkdir /data
WORKDIR /data
VOLUME /data

ENV BMI_PORT=55555

CMD ["run-bmi-server", "--lang", "R", "--path", "/opt/mymodel-bmi.r", "--name", "mymodel"]

EXPOSE 55555

The WALRUS model has a Dockerfile file which can be used as an example.

C/C++/Fortran

For native languages you need to compile you BMI model inside the container let your bmi server runner binary program act as the entry point. The protobuf, grpc and grpc4bmi libraries need to be installed in your docker image, which means that the installation instructions must be adopted in your Docker file. Then, include the installation of the model itself and the bmi run binary that you have written (as described here). Finally the entry point in the docker file should be the launch of this binary and you should expose port 55555. For the C++ example C++ example

# ...download, compile and install grpc and grpc4bmi...
# ...download, compile and install my_bmi_model...
# Run bmi server
ENTRYPOINT ["my_bmi_server"]

# Expose the magic grpc4bmi port
EXPOSE 55555

Building and Publishing

The Docker image can be build with

docker build -t <image name> .

The Docker image can be published at Docker Hub by creating a repository and pushing it with

docker push <image name>

The example WALRUS model is published at https://cloud.docker.com/u/ewatercycle/repository/docker/ewatercycle/walrus-grpc4bmi.

The Docker image can then be started with the grpc4bmi docker client.

Using the container clients

Docker

Grpc4bmi can run containers with Docker engine.

Use the grpc4bmi.bmi_client_docker.BmiClientDocker class to start a Docker container and get a client to interact with the model running inside the container.

For example the PCR-GLOBWB model can be started in a Docker container with

from grpc4bmi.bmi_client_docker import BmiClientDocker

model = BmiClientDocker(image='ewatercycle/pcrg-grpc4bmi:latest', image_port=55555,
                        work_dir="./input")
# Interact with model
model.initialize('config.cfg')

# Stop container
del model

Singularity

Grpc4bmi can run containers on Singularity.

The Docker images build previously can be either run directly or converted to singularity image file and run.

To run a Docker image directly use docker://<docker image name> as singularity image name.

To convert a Docker image to a singularity image file use

singularity build  docker://<docker image name> <singularity image filename>

Use the grpc4bmi.bmi_client_singularity.BmiClientSingularity class to start a Singularity container and get a client to interact with the model running inside the container.

from grpc4bmi.bmi_client_singularity import BmiClientSingularity

image = '<docker image name of grpc4bmi server of a bmi model>'
input_dir = '<directory with models input data files>'
work_dir = '<directory where model can write output files>'
client = BmiClientSingularity(image, work_dir, input_dirs=[input_dir])

 # Interact with model
client.initialize('<absolute path to config file in the input directory>')

# Stop container
del client

For example for the wflow Docker image the commands would be the following

from grpc4bmi.bmi_client_singularity import BmiClientSingularity

image = 'docker://ewatercycle/wflow-grpc4bmi:latest'
work_dir = '/tmp/run1'
client = BmiClientSingularity(image, work_dir, input_dirs=['/scratch/input/wflow_rhine_sbm'])

 # Interact with model
client.initialize('/scratch/input/wflow_rhine_sbm/wflow_sbm_bmi.ini')

# Stop container
del client

Apptainer

Grpc4bmi can run containers on Apptainer.

Apptainer is an open source fork of singularity.

Apptainer behaves very similar to singularity so everything described in Singularity chapter also goes for Apptainer. You will need to replace the singularity command with apptainer and grpc4bmi.bmi_client_singularity.BmiClientSingularity class with grpc4bmi.bmi_client_apptainer.BmiClientApptainer class.

Sharing files between host computer and container

Containers run in an isolated file system and by default can not read/write any files on host computer. To get a directory on your host computer inside a container you have mount them with input_dirs and work_dir arguments of grpc4bmi.bmi_client_docker.BmiClientDocker and grpc4bmi.bmi_client_singularity.BmiClientSingularity.

See grpc4bmi.bmi_client_singularity.BmiClientSingularity for examples using input_dirs and work_dir.

Command line tools

run-bmi-server

BMI GRPC server runner

usage: run-bmi-server [-h] [--name PACKAGE.MODULE.CLASS] [--port N]
                      [--path DIR] [--language {python}]

Named Arguments

--name, -n

Full name of the BMI implementation class. The module should be in your search path and the class should have a constructor with no arguments

--port, -p

Network port for the GRPC server and client. If 0, let the OS choose an available port

Default: 0

--path, -d

Extra path name to append to the server instance process

--language

Possible choices: python

Language in which BMI implementation class is written

Default: “python”

Python API

grpc4bmi package

Submodules

grpc4bmi.bmi_client_apptainer module
class grpc4bmi.bmi_client_apptainer.BmiClientApptainer(image: str, work_dir: str, input_dirs: Iterable[str] = (), delay=0, timeout=None, capture_logs=True)[source]

Bases: BmiClient

BMI GRPC client for model running inside a Apptainer container.

On instantization launches an Apptainer container. The Apptainer container image is expected to run a BMI GRPC server as its default command. The client picks a random port and expects the container to run the BMI GRPC server on that port. The port is passed to the container using the BMI_PORT environment variable.

Parameters
  • image

    Apptainer image.

    For Docker Hub image use docker://* or convert it to a Apptainer image file.

    To convert Docker image ewatercycle/walrus-grpc4bmi with v0.2.0 tag to ./ewatercycle-walrus-grpc4bmi_v0.2.0.sif Apptainer image file use:

    apptainer pull ewatercycle-walrus-grpc4bmi_v0.2.0.sif docker://ewatercycle/walrus-grpc4bmi:v0.2.0
    

  • input_dirs (Iterable[str]) –

    Directories for input files of model.

    All of directories will be mounted read-only inside Apptainer container on same path as outside container.

  • work_dir (str) –

    Working directory for model.

    Directory is mounted inside container and changed into.

    To create a random work directory you could use

    from tempfile import TemporaryDirectory
    from grpc4bmi.bmi_client_apptainer import BmiClientApptainer
    
    work_dir = TemporaryDirectory()
    
    image = 'ewatercycle-walrus-grpc4bmi_v0.2.0.sif'
    client =  BmiClientApptainer(image, work_dir.name)
    
    # Write config to work_dir and interact with client
    
    # After checking output in work_dir, clean up
    work_dir.cleanup()
    

  • delay (int) –

    Seconds to wait for Apptainer container to startup, before connecting to it

    Increase when container takes a long time to startup.

  • timeout (int) –

    Seconds to wait for gRPC client to connect to server.

    By default will try forever to connect to gRPC server inside container. Set to low number to escape endless wait.

  • capture_logs (bool) –

    Whether to capture stdout and stderr of container .

    If false then redirects output to null device never to be seen again. If true then redirects output to temporary file which can be read with BmiClientApptainer.logs(). The temporary file gets removed when this object is deleted.

Example 1: Config file already inside image

MARRMoT has an example config file inside its Docker image.

from grpc4bmi.bmi_client_apptainer import BmiClientApptainer
client = BmiClientApptainer(image='docker://ewatercycle/marrmot-grpc4bmi:latest',
                            work_dir='/opt/MARRMoT/BMI/Config')
client.initialize('/opt/MARRMoT/BMI/Config/BMI_testcase_m01_BuffaloRiver_TN_USA.mat')
client.update_until(client.get_end_time())
del client

Example 2: Config file in input directory

The config file and all other files the model needs are in a directory (/tmp/input). Use /tmp/work to capture any output files like logs generated by model.

from grpc4bmi.bmi_client_apptainer import BmiClientApptainer
# Generate config file called 'config.mat' in `/tmp/input` directory
client = BmiClientApptainer(image='docker://ewatercycle/marrmot-grpc4bmi:latest',
                            input_dirs=['/tmp/input'],
                            work_dir='/tmp/work')
client.initialize('/tmp/input/config.mat')
client.update_until(client.get_end_time())
del client

Example 3: Read only input directory with config file in work directory

The forcing data is in a shared read-only location like /shared/forcings/walrus. In the config file (/tmp/work/walrus.yml) point to a forcing data file (/shared/forcings/walrus/PEQ_Hupsel.dat).

from grpc4bmi.bmi_client_apptainer import BmiClientApptainer
client = BmiClientApptainer(image='ewatercycle-walrus-grpc4bmi_v0.2.0.sif',
                            input_dirs=['/shared/forcings/walrus'],
                            work_dir='/tmp/work')
client.initialize('walrus.yml')
client.update_until(client.get_end_time())
del client

Example 4: Model writes in sub directory of input directory

Some models, for example wflow, write output in a sub-directory of the input directory. If the input directory is set with the input_dirs argument then the model will be unable to write its output as input directories are mounted read-only. That will most likely cause the model to die. A workaround is to use the work_dir argument with input directory as value instead. This will make the whole input directory writable so the model can do its thing.

When input directory is on a shared disk where you do not have write permission then the input dir should be copied to a work directory (/scratch/wflow) so model can write.

from grpc4bmi.bmi_client_apptainer import BmiClientApptainer
client = BmiClientApptainer(image='docker://ewatercycle/wflow-grpc4bmi:latest',
                            work_dir='/scratch/wflow')
client.initialize('wflow_sbm.ini')
client.update_until(client.get_end_time())
del client

Example 5: Inputs are in multiple directories

A model has its forcings (/shared/forcings/muese), parameters (/shared/model/wflow/staticmaps) and config file (/tmp/work/wflow_sbm.ini) in different locations. The config file should be set to point to the forcing and parameters files.

from grpc4bmi.bmi_client_apptainer import BmiClientApptainer
client = BmiClientApptainer(image='docker://ewatercycle/wflow-grpc4bmi:latest',
                            input_dirs=['/shared/forcings/muese',
                                        '/shared/model/wflow/staticmaps'],
                            work_dir='/tmp/work')
client.initialize('wflow_sbm.ini')
client.update_until(client.get_end_time())
del client

Example 6: Run model twice with their own work directory

While running 2 or models at the same time you do not want the any config or output to be mixed.

from grpc4bmi.bmi_client_apptainer import BmiClientApptainer
client_muese = BmiClientApptainer(image='docker://ewatercycle/wflow-grpc4bmi:latest',
                                  work_dir='/scratch/wflow-meuse')
client_muese.initialize('wflow_sbm.meuse.ini')
client_rhine = BmiClientApptainer(image='docker://ewatercycle/wflow-grpc4bmi:latest',
                                  work_dir='/scratch/wflow-rhine')
client_rhine.initialize('wflow_sbm.rhine.ini')
...
# Run models and set/get values
...
del client_muese
del client_rhine
get_value_ref(var_name)[source]

Not possible, unable give reference to data structure in another process and possibly another machine

logs() str[source]

Returns complete combined stdout and stderr written by the Apptainer container.

When object was created with log_enable=False argument then always returns empty string.

grpc4bmi.bmi_client_apptainer.check_apptainer_version()[source]
grpc4bmi.bmi_client_apptainer.check_apptainer_version_string(version_output: str) bool[source]
grpc4bmi.bmi_client_docker module
class grpc4bmi.bmi_client_docker.BmiClientDocker(image: str, work_dir: str, image_port=50051, host=None, input_dirs: Iterable[str] = (), user=1005, remove=False, delay=5, timeout=None)[source]

Bases: BmiClient

BMI gRPC client for dockerized server processes: the initialization launches the docker container which should have the run-bmi-server as its command. Also, it should expose the tcp port 50001 for communication with this client. Upon destruction, this class terminates the corresponding docker server.

Parameters
  • image (str) – Docker image name of grpc4bmi wrapped model

  • image_port (int) – Port of server inside the image

  • host (str) – Host on which the image port is published on a random port

  • input_dirs (Iterable[str]) –

    Directories for input files of model.

    All of directories will be mounted read-only inside Docker container on same path as outside container.

  • work_dir (str) –

    Working directory for model.

    Directory is mounted inside container and changed into.

  • user (str) – Username or UID of Docker container. Defaults to own UID.

  • remove (bool) –

    Automatically remove the container and logs when it exits.

    Enable to get logs when container dies prematurely.

  • delay (int) –

    Seconds to wait for Docker container to startup, before connecting to it

    Increase when container takes a long time to startup.

  • timeout (int) –

    Seconds to wait for gRPC client to connect to server.

    By default will try forever to connect to gRPC server inside container. Set to low number to escape endless wait.

See grpc4bmi.bmi_client_apptainer.BmiClientApptainer for examples using input_dirs and work_dir.

get_value_ref(var_name)[source]

Not possible, unable give reference to data structure in another process and possibly another machine

logs() str[source]

Returns complete combined stdout and stderr written by the Docker container.

grpc4bmi.bmi_client_singularity module
class grpc4bmi.bmi_client_singularity.BmiClientSingularity(image: str, work_dir: str, input_dirs: Iterable[str] = (), delay=0, timeout=None, capture_logs=True)[source]

Bases: BmiClient

BMI GRPC client for singularity server processes During initialization launches a singularity container with run-bmi-server as its command. The client picks a random port and expects the container to run the server on that port. The port is passed to the container using the BMI_PORT environment variable.

Parameters
  • image

    Singularity image.

    For Docker Hub image use docker://* or convert it to a Singularity image file.

    To convert Docker image ewatercycle/walrus-grpc4bmi with v0.2.0 tag to ./ewatercycle-walrus-grpc4bmi_v0.2.0.sif Singularity image file use:

    singularity pull ewatercycle-walrus-grpc4bmi_v0.2.0.sif docker://ewatercycle/walrus-grpc4bmi:v0.2.0
    

  • input_dirs (Iterable[str]) –

    Directories for input files of model.

    All of directories will be mounted read-only inside Singularity container on same path as outside container.

  • work_dir (str) –

    Working directory for model.

    Directory is mounted inside container and changed into.

    To create a random work directory you could use

    from tempfile import TemporaryDirectory
    from grpc4bmi.bmi_client_singularity import BmiClientSingularity
    
    work_dir = TemporaryDirectory()
    
    image = 'ewatercycle-walrus-grpc4bmi_v0.2.0.sif'
    client =  BmiClientSingularity(image, work_dir.name)
    
    # Write config to work_dir and interact with client
    
    # After checking output in work_dir, clean up
    work_dir.cleanup()
    

  • delay (int) –

    Seconds to wait for Singularity container to startup, before connecting to it

    Increase when container takes a long time to startup.

  • timeout (int) –

    Seconds to wait for gRPC client to connect to server.

    By default will try forever to connect to gRPC server inside container. Set to low number to escape endless wait.

  • capture_logs (bool) –

    Whether to capture stdout and stderr of container .

    If false then redirects output to null device never to be seen again. If true then redirects output to temporary file which can be read with BmiClientSingularity.logs(). The temporary file gets removed when this object is deleted.

Example 1: Config file already inside image

MARRMoT has an example config file inside its Docker image.

from grpc4bmi.bmi_client_singularity import BmiClientSingularity
client = BmiClientSingularity(image='docker://ewatercycle/marrmot-grpc4bmi:latest',
                              work_dir='/opt/MARRMoT/BMI/Config'))
client.initialize('/opt/MARRMoT/BMI/Config/BMI_testcase_m01_BuffaloRiver_TN_USA.mat')
client.update_until(client.get_end_time())
del client

Example 2: Config file in input directory

The config file and all other files the model needs are in a directory (/tmp/input). Use /tmp/work to capture any output files like logs generated by model.

from grpc4bmi.bmi_client_singularity import BmiClientSingularity
# Generate config file called 'config.mat' in `/tmp/input` directory
client = BmiClientSingularity(image='docker://ewatercycle/marrmot-grpc4bmi:latest',
                              input_dirs=['/tmp/input'],
                              work_dir='/tmp/work')
client.initialize('/tmp/input/config.mat')
client.update_until(client.get_end_time())
del client

Example 3: Read only input directory with config file in work directory

The forcing data is in a shared read-only location like /shared/forcings/walrus. In the config file (/tmp/work/walrus.yml) point to a forcing data file (/shared/forcings/walrus/PEQ_Hupsel.dat).

from grpc4bmi.bmi_client_singularity import BmiClientSingularity
client = BmiClientSingularity(image='ewatercycle-walrus-grpc4bmi_v0.2.0.sif',
                              input_dirs=['/shared/forcings/walrus'],
                              work_dir='/tmp/work')
client.initialize('walrus.yml')
client.update_until(client.get_end_time())
del client

Example 4: Model writes in sub directory of input directory

Some models, for example wflow, write output in a sub-directory of the input directory. If the input directory is set with the input_dirs argument then the model will be unable to write its output as input directories are mounted read-only. That will most likely cause the model to die. A workaround is to use the work_dir argument with input directory as value instead. This will make the whole input directory writable so the model can do its thing.

When input directory is on a shared disk where you do not have write permission then the input dir should be copied to a work directory (/scratch/wflow) so model can write.

from grpc4bmi.bmi_client_singularity import BmiClientSingularity
client = BmiClientSingularity(image='docker://ewatercycle/wflow-grpc4bmi:latest',
                              work_dir='/scratch/wflow')
client.initialize('wflow_sbm.ini')
client.update_until(client.get_end_time())
del client

Example 5: Inputs are in multiple directories

A model has its forcings (/shared/forcings/muese), parameters (/shared/model/wflow/staticmaps) and config file (/tmp/work/wflow_sbm.ini) in different locations. The config file should be set to point to the forcing and parameters files.

from grpc4bmi.bmi_client_singularity import BmiClientSingularity
client = BmiClientSingularity(image='docker://ewatercycle/wflow-grpc4bmi:latest',
                              input_dirs=['/shared/forcings/muese',
                                          '/shared/model/wflow/staticmaps'],
                              work_dir='/tmp/work')
client.initialize('wflow_sbm.ini')
client.update_until(client.get_end_time())
del client

Example 6: Run model twice with their own work directory

While running 2 or models at the same time you do not want the any config or output to be mixed.

from grpc4bmi.bmi_client_singularity import BmiClientSingularity
client_muese = BmiClientSingularity(image='docker://ewatercycle/wflow-grpc4bmi:latest',
                                    work_dir='/scratch/wflow-meuse')
client_muese.initialize('wflow_sbm.meuse.ini')
client_rhine = BmiClientSingularity(image='docker://ewatercycle/wflow-grpc4bmi:latest',
                                    work_dir='/scratch/wflow-rhine')
client_rhine.initialize('wflow_sbm.rhine.ini')
...
# Run models and set/get values
...
del client_muese
del client_rhine
get_value_ref(var_name)[source]

Not possible, unable give reference to data structure in another process and possibly another machine

logs() str[source]

Returns complete combined stdout and stderr written by the Singularity container.

When object was created with log_enable=False argument then always returns empty string.

grpc4bmi.bmi_client_singularity.check_singularity_version()[source]
grpc4bmi.bmi_client_singularity.check_singularity_version_string(version_output: str) bool[source]
grpc4bmi.bmi_client_subproc module
class grpc4bmi.bmi_client_subproc.BmiClientSubProcess(module_name, path=None, timeout=None)[source]

Bases: BmiClient

BMI GRPC client that owns its server process, i.e. initiates and destroys the BMI server upon its own construction or respective destruction. The server is a forked subprocess running the run_server command.

>>> from grpc4bmi.bmi_client_subproc import BmiClientSubProcess
>>> mymodel = BmiClientSubProcess(<PACKAGE>.<MODULE>.<CLASS>)
get_value_ref(var_name)[source]

Not possible, unable give reference to data structure in another process and possibly another machine

grpc4bmi.bmi_grpc_client module
class grpc4bmi.bmi_grpc_client.BmiClient(channel=None, timeout=None, stub=None)[source]

Bases: Bmi

Client BMI interface, implementing BMI by forwarding every function call via GRPC to the server connected to the same port. A GRPC channel can be passed to the constructor; if not, it constructs an insecure channel on a free port itself. The timeout parameter indicates the model BMI startup timeout parameter (s).

>>> import grpc
>>> from grpc4bmi.bmi_grpc_client import BmiClient
>>> mymodel = BmiClient(grpc.insecure_channel("localhost:<PORT>"))
>>> print(mymodel.get_component_name())
Hello world
static create_grpc_channel(port=0, host=None)[source]
finalize()[source]

Perform tear-down tasks for the model.

Perform all tasks that take place after exiting the model’s time loop. This typically includes deallocating memory, closing files and printing reports.

Notes

/* C */
int finalize(void *self);
get_component_name()[source]

Name of the component.

Returns

The name of the component.

Return type

str

Notes

/* C */
int get_component_name(void * self, char * name);
get_current_time()[source]

Current time of the model.

Returns

The current model time.

Return type

float

See also

get_start_time

Notes

/* C */
int get_current_time(void * self, double * time);
get_end_time()[source]

End time of the model.

Returns

The maximum model time.

Return type

float

See also

get_start_time

Notes

/* C */
int get_end_time(void * self, double * time);
get_grid_connectivity(grid_id)[source]

Get connectivity array of the grid.

Parameters

grid_id (int) – A grid identifier.

Returns

The graph of connections between the grid nodes.

Return type

array_like or int

See also

bmi.vars.BmiVars.get_var_grid

Obtain a grid_id.

Notes

/* C */
int get_grid_connectivity(void * self, int grid_id,
                          int * connectivity);
get_grid_offset(grid_id)[source]

Get offsets for the grid nodes.

Parameters

grid_id (int) – A grid identifier.

Returns

The offsets for the grid nodes.

Return type

array_like of int

See also

bmi.vars.BmiVars.get_var_grid

Obtain a grid_id.

Notes

/* C */
int get_grid_offset(void * self, int grid_id, int * offset);
get_grid_origin(grid_id)[source]

Get coordinates for the origin of the computational grid.

Parameters

grid_id (int) – A grid identifier.

Returns

The coordinates of the lower left corner of the grid.

Return type

array_like

See also

bmi.vars.BmiVars.get_var_grid

Obtain a grid_id.

Notes

/* C */
int get_grid_origin(void * self, int grid_id, double * origin);
get_grid_rank(grid_id)[source]

Get number of dimensions of the computational grid.

Parameters

grid_id (int) – A grid identifier.

Returns

Rank of the grid.

Return type

int

See also

bmi.vars.BmiVars.get_var_grid

Obtain a grid_id.

Notes

/* C */
int get_grid_rank(void * self, int grid_id, int * rank);
get_grid_shape(grid_id)[source]

Get dimensions of the computational grid.

Parameters

grid_id (int) – A grid identifier.

Returns

The dimensions of the grid.

Return type

tuple of int

See also

bmi.vars.BmiVars.get_var_grid

Obtain a grid_id.

Notes

/* C */
int get_grid_shape(void * self, const char * var_name,
                   int * shape);
get_grid_size(grid_id)[source]

Get the total number of elements in the computational grid.

Parameters

grid_id (int) – A grid identifier.

Returns

Size of the grid.

Return type

int

See also

bmi.vars.BmiVars.get_var_grid

Obtain a grid_id.

Notes

/* C */
int get_grid_size(void * self, int grid_id, int * size);
get_grid_spacing(grid_id)[source]

Get distance between nodes of the computational grid.

Parameters

grid_id (int) – A grid identifier.

Returns

The grid spacing.

Return type

array_like

See also

bmi.vars.BmiVars.get_var_grid

Obtain a grid_id.

Notes

/* C */
int get_grid_spacing(void * self, int grid_id, double * spacing);
get_grid_type(grid_id)[source]

Get the grid type as a string.

Parameters

grid_id (int) – A grid identifier.

Returns

Type of grid as a string.

Return type

str

See also

bmi.vars.BmiVars.get_var_grid

Obtain a grid_id.

Notes

/* C */
int get_grid_type(void * self, int grid_id, char * type);
get_grid_x(grid_id)[source]

Get coordinates of grid nodes in the streamwise direction.

Parameters

grid_id (int) – A grid identifier.

Returns

The positions of the grid nodes.

Return type

array_like of float

See also

bmi.vars.BmiVars.get_var_grid

Obtain a grid_id.

Notes

/* C */
int get_grid_x(void * self, const char * var_name, double * x);
get_grid_y(grid_id)[source]

Get coordinates of grid nodes in the transverse direction.

Parameters

grid_id (int) – A grid identifier.

Returns

The positions of the grid nodes.

Return type

array_like of float

See also

bmi.vars.BmiVars.get_var_grid

Obtain a grid_id.

Notes

/* C */
int get_grid_y(void * self, const char * var_name, double * y);
get_grid_z(grid_id)[source]

Get coordinates of grid nodes in the normal direction.

Parameters

grid_id (int) – A grid identifier.

Returns

The positions of the grid nodes.

Return type

array_like of float

See also

bmi.vars.BmiVars.get_var_grid

Obtain a grid_id.

Notes

/* C */
int get_grid_z(void * self, const char * var_name, double * z);
get_input_var_names()[source]

List of a model’s input variables.

Input variable names must be CSDMS Standard Names, also known as long variable names.

Returns

The input variables for the model.

Return type

list of str

Notes

Standard Names enable the CSDMS 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.

Notes

/* C */
int get_input_var_name_count(void * self, int * count);
int get_input_var_names(void * self, char ** names);
get_output_var_names()[source]

List of a model’s output variables.

Output variable names must be CSDMS Standard Names, also known as long variable names.

Returns

The output variables for the model.

Return type

list of str

Notes

/* C */
int get_output_var_name_count(void * self, int * count);
int get_output_var_names(void * self, char ** names);
get_start_time()[source]

Start time of the model.

Model times should be of type float. The default model start time is 0.

Returns

The model start time.

Return type

float

Notes

/* C */
int get_start_time(void * self, double * time);
get_time_step()[source]

Current time step of the model.

The model time step should be of type float. The default time step is 1.0.

Returns

The time step used in model.

Return type

float

Notes

/* C */
int get_time_step(void * self, double * dt);
get_time_units()[source]

Time units of the model.

Returns

The model time unit; e.g., days or s.

Return type

float

Notes

CSDMS uses the UDUNITS standard from Unidata.

Notes

/* C */
int get_time_units(void * self, char * units);
static get_unique_port(host=None)[source]
get_value(var_name)[source]

Get a copy of values of the given variable.

This is a getter for the model, used to access the model’s current state. It returns a copy of a model variable, with the return type, size and rank dependent on the variable.

Parameters

var_name (str) – An input or output variable name, a CSDMS Standard Name.

Returns

The value of a model variable.

Return type

array_like

Notes

/* C */
int get_value(void * self, const char * var_name, void * buffer);
get_value_at_indices(var_name, indices)[source]

Get values at particular indices.

Parameters
  • var_name (str) – An input or output variable name, a CSDMS Standard Name.

  • indices (array_like) – The indices into the variable array.

Returns

Value of the model variable at the given location.

Return type

array_like

Notes

/* C */
int get_value_at_indices(void * self, const char * var_name,
                         void * buffer, int * indices, int len);
get_value_ref(var_name)[source]

Not possible, unable give reference to data structure in another process and possibly another machine

get_var_grid(var_name)[source]

Get grid identifier for the given variable.

Parameters

var_name (str) – An input or output variable name, a CSDMS Standard Name.

Returns

The grid identifier.

Return type

int

See also

bmi.info.BmiInfo.get_input_var_names

Get var_name from this method or from get_output_var_names().

Notes

/* C */
int get_var_grid(void * self, const char * var_name, int * id);
get_var_itemsize(var_name)[source]

Get memory use for each array element in bytes.

Parameters

var_name (str) – An input or output variable name, a CSDMS Standard Name.

Returns

Item size in bytes.

Return type

int

Notes

/* C */
int get_var_itemsize(void * self, const char * var_name,
                     int * itemsize);
get_var_nbytes(var_name)[source]

Get size, in bytes, of the given variable.

Parameters

var_name (str) – An input or output variable name, a CSDMS Standard Name.

Returns

The size of the variable, counted in bytes.

Return type

int

Notes

/* C */
int get_var_nbytes(void * self, const char * var_name,
                   int * nbytes);
get_var_type(var_name)[source]

Get data type of the given variable.

Parameters

var_name (str) – An input or output variable name, a CSDMS Standard Name.

Returns

The Python variable type; e.g., str, int, float.

Return type

str

Notes

/* C */
int get_var_type(void * self, const char * var_name, char * type);
get_var_units(var_name)[source]

Get 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 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.

Parameters

var_name (str) – An input or output variable name, a CSDMS Standard Name.

Returns

The variable units.

Return type

str

Notes

CSDMS uses the UDUNITS standard from Unidata.

/* C */
int get_var_units(void * self, const char * var_name,
                  char * units);
initialize(filename: Optional[str])[source]

Perform startup tasks for the model.

Perform all tasks that take place before entering the model’s time loop, including opening files and initializing the model state. Model inputs are read from a text-based configuration file, specified by filename.

Parameters

filename (str, optional) – The path to the model configuration file.

Notes

Models should be refactored, if necessary, to use a configuration file. CSDMS does not impose any constraint on how configuration files are formatted, although YAML is recommended. A template of a model’s configuration file with placeholder values is used by the BMI.

/* C */
int initialize(void *self, char * filename);
static make_array(response)[source]
set_value(var_name, src)[source]

Specify a new value for a model variable.

This is the setter for the model, used to change the model’s current state. It accepts, through src, a new value for a model variable, with the type, size and rank of src dependent on the variable.

Parameters
  • var_name (str) – An input or output variable name, a CSDMS Standard Name.

  • src (array_like) – The new value for the specified variable.

Notes

/* C */
int set_value(void * self, const char * var_name, void * src);
set_value_at_indices(var_name, indices, src)[source]

Specify a new value for a model variable at particular indices.

Parameters
  • var_name (str) – An input or output variable name, a CSDMS Standard Name.

  • indices (array_like) – The indices into the variable array.

  • src (array_like) – The new value for the specified variable.

Notes

/* C */
int set_value_at_indices(void * self, const char * var_name,
                         int * indices, int len, void * src);
update()[source]

Advance model state by one time step.

Perform all tasks that take place within one pass through the model’s time loop. This typically includes 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() method and this method can return with no action.

Notes

/* C */
int update(void *self);
update_frac(time_frac)[source]

Advance model state by a fraction of a time step.

Parameters

time_frac (float) – A fraction of a model time step value.

See also

update

Notes

/* C */
int update_frac(void *self, double time_frac);
update_until(time)[source]

Advance model state until the given time.

Parameters

time (float) – A model time value.

See also

update

Notes

/* C */
int update_until(void *self, double time);
grpc4bmi.bmi_grpc_server module
class grpc4bmi.bmi_grpc_server.BmiServer(model)[source]

Bases: BmiServiceServicer

BMI Server class, wrapping an existing python implementation and exposing it via GRPC across the memory space (to listening client processes). The class takes a package, module and class name and instantiates the BMI implementation by assuming a default constructor with no arguments.

finalize(request, context)[source]
getComponentName(request, context)[source]
getCurrentTime(request, context)[source]
getEndTime(request, context)[source]
getGridConnectivity(request, context)[source]
getGridOffset(request, context)[source]
getGridOrigin(request, context)[source]
getGridRank(request, context)[source]
getGridShape(request, context)[source]
getGridSize(request, context)[source]
getGridSpacing(request, context)[source]
getGridType(request, context)[source]
getGridX(request, context)[source]
getGridY(request, context)[source]
getGridZ(request, context)[source]
getInputVarNames(request, context)[source]
getOutputVarNames(request, context)[source]
getStartTime(request, context)[source]
getTimeStep(request, context)[source]
getTimeUnits(request, context)[source]
getValue(request, context)[source]
getValueAtIndices(request, context)[source]
getValuePtr(request, context)[source]
getVarGrid(request, context)[source]
getVarItemSize(request, context)[source]
getVarNBytes(request, context)[source]
getVarType(request, context)[source]
getVarUnits(request, context)[source]
initialize(request, context)[source]
setValue(request, context)[source]
setValueAtIndices(request, context)[source]
setValuePtr(request, context)[source]
update(request, context)[source]
updateFrac(request, context)[source]
updateUntil(request, context)[source]
grpc4bmi.bmi_memoized module
class grpc4bmi.bmi_memoized.MemoizedBmi(origin: Bmi)[source]

Bases: Bmi

Wrapper around Bmi object that caches the return values of almost all methods.

Most BMI methods return same value each time it is called, so the results can be cached. gRPC communication is expensive and can be sped up by caching.

The following methods are not cached:

  • initialize

  • update_*

  • finalize

  • get_current_time

  • get_value_*

  • set_value_*

The cache is cleared when initialize() is called.

Example

A gRPC BMI server is running on localhost:1234, to cache it use the following.

>>> import grpc
>>> from grpc4bmi.bmi_grpc_client import BmiClient
>>> from grpc4bmi.bmi_memoized import MemoizedBmi
>>> slow_model = BmiClient(grpc.insecure_channel("localhost:1234"))
>>> model = MemoizedBmi(slow_model)
>>> print(model.get_component_name())
Hello world
>>> # Calling second time will return cached value
>>> # and not talk to server on "localhost:1234"
>>> print(model.get_component_name())
Hello world
finalize()[source]

Perform tear-down tasks for the model.

Perform all tasks that take place after exiting the model’s time loop. This typically includes deallocating memory, closing files and printing reports.

Notes

/* C */
int finalize(void *self);
get_component_name()[source]

Name of the component.

Returns

The name of the component.

Return type

str

Notes

/* C */
int get_component_name(void * self, char * name);
get_current_time()[source]

Current time of the model.

Returns

The current model time.

Return type

float

See also

get_start_time

Notes

/* C */
int get_current_time(void * self, double * time);
get_end_time()[source]

End time of the model.

Returns

The maximum model time.

Return type

float

See also

get_start_time

Notes

/* C */
int get_end_time(void * self, double * time);
get_grid_connectivity(grid_id)[source]

Get connectivity array of the grid.

Parameters

grid_id (int) – A grid identifier.

Returns

The graph of connections between the grid nodes.

Return type

array_like or int

See also

bmi.vars.BmiVars.get_var_grid

Obtain a grid_id.

Notes

/* C */
int get_grid_connectivity(void * self, int grid_id,
                          int * connectivity);
get_grid_offset(grid_id)[source]

Get offsets for the grid nodes.

Parameters

grid_id (int) – A grid identifier.

Returns

The offsets for the grid nodes.

Return type

array_like of int

See also

bmi.vars.BmiVars.get_var_grid

Obtain a grid_id.

Notes

/* C */
int get_grid_offset(void * self, int grid_id, int * offset);
get_grid_origin(grid_id)[source]

Get coordinates for the origin of the computational grid.

Parameters

grid_id (int) – A grid identifier.

Returns

The coordinates of the lower left corner of the grid.

Return type

array_like

See also

bmi.vars.BmiVars.get_var_grid

Obtain a grid_id.

Notes

/* C */
int get_grid_origin(void * self, int grid_id, double * origin);
get_grid_rank(grid_id)[source]

Get number of dimensions of the computational grid.

Parameters

grid_id (int) – A grid identifier.

Returns

Rank of the grid.

Return type

int

See also

bmi.vars.BmiVars.get_var_grid

Obtain a grid_id.

Notes

/* C */
int get_grid_rank(void * self, int grid_id, int * rank);
get_grid_shape(grid_id)[source]

Get dimensions of the computational grid.

Parameters

grid_id (int) – A grid identifier.

Returns

The dimensions of the grid.

Return type

tuple of int

See also

bmi.vars.BmiVars.get_var_grid

Obtain a grid_id.

Notes

/* C */
int get_grid_shape(void * self, const char * var_name,
                   int * shape);
get_grid_size(grid_id)[source]

Get the total number of elements in the computational grid.

Parameters

grid_id (int) – A grid identifier.

Returns

Size of the grid.

Return type

int

See also

bmi.vars.BmiVars.get_var_grid

Obtain a grid_id.

Notes

/* C */
int get_grid_size(void * self, int grid_id, int * size);
get_grid_spacing(grid_id)[source]

Get distance between nodes of the computational grid.

Parameters

grid_id (int) – A grid identifier.

Returns

The grid spacing.

Return type

array_like

See also

bmi.vars.BmiVars.get_var_grid

Obtain a grid_id.

Notes

/* C */
int get_grid_spacing(void * self, int grid_id, double * spacing);
get_grid_type(grid_id)[source]

Get the grid type as a string.

Parameters

grid_id (int) – A grid identifier.

Returns

Type of grid as a string.

Return type

str

See also

bmi.vars.BmiVars.get_var_grid

Obtain a grid_id.

Notes

/* C */
int get_grid_type(void * self, int grid_id, char * type);
get_grid_x(grid_id)[source]

Get coordinates of grid nodes in the streamwise direction.

Parameters

grid_id (int) – A grid identifier.

Returns

The positions of the grid nodes.

Return type

array_like of float

See also

bmi.vars.BmiVars.get_var_grid

Obtain a grid_id.

Notes

/* C */
int get_grid_x(void * self, const char * var_name, double * x);
get_grid_y(grid_id)[source]

Get coordinates of grid nodes in the transverse direction.

Parameters

grid_id (int) – A grid identifier.

Returns

The positions of the grid nodes.

Return type

array_like of float

See also

bmi.vars.BmiVars.get_var_grid

Obtain a grid_id.

Notes

/* C */
int get_grid_y(void * self, const char * var_name, double * y);
get_grid_z(grid_id)[source]

Get coordinates of grid nodes in the normal direction.

Parameters

grid_id (int) – A grid identifier.

Returns

The positions of the grid nodes.

Return type

array_like of float

See also

bmi.vars.BmiVars.get_var_grid

Obtain a grid_id.

Notes

/* C */
int get_grid_z(void * self, const char * var_name, double * z);
get_input_var_names()[source]

List of a model’s input variables.

Input variable names must be CSDMS Standard Names, also known as long variable names.

Returns

The input variables for the model.

Return type

list of str

Notes

Standard Names enable the CSDMS 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.

Notes

/* C */
int get_input_var_name_count(void * self, int * count);
int get_input_var_names(void * self, char ** names);
get_output_var_names()[source]

List of a model’s output variables.

Output variable names must be CSDMS Standard Names, also known as long variable names.

Returns

The output variables for the model.

Return type

list of str

Notes

/* C */
int get_output_var_name_count(void * self, int * count);
int get_output_var_names(void * self, char ** names);
get_start_time()[source]

Start time of the model.

Model times should be of type float. The default model start time is 0.

Returns

The model start time.

Return type

float

Notes

/* C */
int get_start_time(void * self, double * time);
get_time_step()[source]

Current time step of the model.

The model time step should be of type float. The default time step is 1.0.

Returns

The time step used in model.

Return type

float

Notes

/* C */
int get_time_step(void * self, double * dt);
get_time_units()[source]

Time units of the model.

Returns

The model time unit; e.g., days or s.

Return type

float

Notes

CSDMS uses the UDUNITS standard from Unidata.

Notes

/* C */
int get_time_units(void * self, char * units);
get_value(var_name)[source]

Get a copy of values of the given variable.

This is a getter for the model, used to access the model’s current state. It returns a copy of a model variable, with the return type, size and rank dependent on the variable.

Parameters

var_name (str) – An input or output variable name, a CSDMS Standard Name.

Returns

The value of a model variable.

Return type

array_like

Notes

/* C */
int get_value(void * self, const char * var_name, void * buffer);
get_value_at_indices(var_name, indices)[source]

Get values at particular indices.

Parameters
  • var_name (str) – An input or output variable name, a CSDMS Standard Name.

  • indices (array_like) – The indices into the variable array.

Returns

Value of the model variable at the given location.

Return type

array_like

Notes

/* C */
int get_value_at_indices(void * self, const char * var_name,
                         void * buffer, int * indices, int len);
get_value_ref(var_name)[source]

Get a reference to values of the given variable.

This is a getter for the model, used to access the model’s current state. It returns a reference to a model variable, with the return type, size and rank dependent on the variable.

Parameters

var_name (str) – An input or output variable name, a CSDMS Standard Name.

Returns

A reference to a model variable.

Return type

array_like

Notes

/* C */
int get_value_ref(void * self, const char * var_name,
                  void ** buffer);
get_var_grid(var_name)[source]

Get grid identifier for the given variable.

Parameters

var_name (str) – An input or output variable name, a CSDMS Standard Name.

Returns

The grid identifier.

Return type

int

See also

bmi.info.BmiInfo.get_input_var_names

Get var_name from this method or from get_output_var_names().

Notes

/* C */
int get_var_grid(void * self, const char * var_name, int * id);
get_var_itemsize(var_name)[source]

Get memory use for each array element in bytes.

Parameters

var_name (str) – An input or output variable name, a CSDMS Standard Name.

Returns

Item size in bytes.

Return type

int

Notes

/* C */
int get_var_itemsize(void * self, const char * var_name,
                     int * itemsize);
get_var_nbytes(var_name)[source]

Get size, in bytes, of the given variable.

Parameters

var_name (str) – An input or output variable name, a CSDMS Standard Name.

Returns

The size of the variable, counted in bytes.

Return type

int

Notes

/* C */
int get_var_nbytes(void * self, const char * var_name,
                   int * nbytes);
get_var_type(var_name)[source]

Get data type of the given variable.

Parameters

var_name (str) – An input or output variable name, a CSDMS Standard Name.

Returns

The Python variable type; e.g., str, int, float.

Return type

str

Notes

/* C */
int get_var_type(void * self, const char * var_name, char * type);
get_var_units(var_name)[source]

Get 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 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.

Parameters

var_name (str) – An input or output variable name, a CSDMS Standard Name.

Returns

The variable units.

Return type

str

Notes

CSDMS uses the UDUNITS standard from Unidata.

/* C */
int get_var_units(void * self, const char * var_name,
                  char * units);
initialize(filename)[source]

Perform startup tasks for the model.

Perform all tasks that take place before entering the model’s time loop, including opening files and initializing the model state. Model inputs are read from a text-based configuration file, specified by filename.

Parameters

filename (str, optional) – The path to the model configuration file.

Notes

Models should be refactored, if necessary, to use a configuration file. CSDMS does not impose any constraint on how configuration files are formatted, although YAML is recommended. A template of a model’s configuration file with placeholder values is used by the BMI.

/* C */
int initialize(void *self, char * filename);
set_value(var_name, src)[source]

Specify a new value for a model variable.

This is the setter for the model, used to change the model’s current state. It accepts, through src, a new value for a model variable, with the type, size and rank of src dependent on the variable.

Parameters
  • var_name (str) – An input or output variable name, a CSDMS Standard Name.

  • src (array_like) – The new value for the specified variable.

Notes

/* C */
int set_value(void * self, const char * var_name, void * src);
set_value_at_indices(var_name, indices, src)[source]

Specify a new value for a model variable at particular indices.

Parameters
  • var_name (str) – An input or output variable name, a CSDMS Standard Name.

  • indices (array_like) – The indices into the variable array.

  • src (array_like) – The new value for the specified variable.

Notes

/* C */
int set_value_at_indices(void * self, const char * var_name,
                         int * indices, int len, void * src);
update()[source]

Advance model state by one time step.

Perform all tasks that take place within one pass through the model’s time loop. This typically includes 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() method and this method can return with no action.

Notes

/* C */
int update(void *self);
update_frac(time_frac)[source]

Advance model state by a fraction of a time step.

Parameters

time_frac (float) – A fraction of a model time step value.

See also

update

Notes

/* C */
int update_frac(void *self, double time_frac);
update_until(time)[source]

Advance model state until the given time.

Parameters

time (float) – A model time value.

See also

update

Notes

/* C */
int update_until(void *self, double time);
grpc4bmi.bmi_r_model module
grpc4bmi.constants module
grpc4bmi.constants.GRPC_MAX_MESSAGE_LENGTH = 4194304

grpc max message size is 4Mb

grpc4bmi.exceptions module
exception grpc4bmi.exceptions.ApptainerVersionException[source]

Bases: ValueError

exception grpc4bmi.exceptions.DeadContainerException(message, exitcode, logs, *args)[source]

Bases: ChildProcessError

Exception for when a container has died.

Parameters
  • message (str) – Human readable error message

  • exitcode (int) – The non-zero exit code of the container

  • logs (str) – Logs the container produced

exitcode

Exit code of container

logs

Stdout and stderr of container

exception grpc4bmi.exceptions.SingularityVersionException[source]

Bases: ValueError

grpc4bmi.run_server module
grpc4bmi.run_server.build(name, path)[source]

Build a model based on it’s location and name

grpc4bmi.run_server.build_parser()[source]
grpc4bmi.run_server.build_r(class_name, source_fn)[source]
grpc4bmi.run_server.interrupt(signum, frame)[source]
grpc4bmi.run_server.main()[source]
grpc4bmi.run_server.serve(model, port)[source]

Module contents

Indices and tables