Skip to content

Commit

Permalink
Merge pull request #124 from eWaterCycle/bmi2
Browse files Browse the repository at this point in the history
Combine 0.2.x branch with master
  • Loading branch information
sverhoeven authored Mar 20, 2023
2 parents 8a10ae5 + 48d8e31 commit 236ec61
Show file tree
Hide file tree
Showing 71 changed files with 4,273 additions and 3,280 deletions.
3 changes: 3 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Apptainer images
*.sif
/.venv
66 changes: 45 additions & 21 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,39 +5,48 @@ name: CI

on:
push:
branches: [main]
pull_request:
types: [opened, synchronize, reopened]

jobs:
python:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v2
uses: actions/setup-python@v4
with:
python-version: 3.6
python-version: '3.10'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
python setup.py install
- name: Setup Singularity
uses: eWaterCycle/setup-singularity@v6
python -m pip install --upgrade pip wheel
pip install -e .[dev,R]
- name: Setup Apptainer
uses: eWaterCycle/setup-apptainer@v2
with:
singularity-version: 3.6.4
apptainer-version: 1.1.3
- name: Pull Docker image
run: docker pull ewatercycle/walrus-grpc4bmi:v0.3.1
- name: Cache Singularity image
id: cache-singularity-image
uses: actions/cache@v2
- name: Cache Apptainer image
id: cache-apptainer-image
uses: actions/cache@v3
with:
path: ~/.singularity
key: singularity-image
- name: Pull Singularity image
if: steps.cache-singularity-image.outputs.cache-hit != 'true'
run: singularity pull docker://ewatercycle/walrus-grpc4bmi:v0.3.1
path: ~/.apptainer
key: apptainer-image
- name: Pull Apptainer image
if: steps.cache-apptainer-image.outputs.cache-hit != 'true'
run: apptainer pull docker://ewatercycle/walrus-grpc4bmi:v0.3.1
- uses: r-lib/actions/setup-r@v2
with:
install-r: false
- name: Install R dependencies
run: |
Rscript -e "install.packages('remotes')"
Rscript -e "install.packages('R6')"
- name: Test with pytest
run: pytest --cov=grpc4bmi --cov-report xml
run: |
pytest -vv --cov=grpc4bmi --cov-report xml
- name: Correct coverage paths
run: sed -i "s+$PWD/++g" coverage.xml
- name: SonarCloud analysis
Expand All @@ -46,19 +55,33 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
cpp:
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
submodules: true
- name: Install grpc
uses: ewatercycle/setup-grpc@v4
with:
grpc-version: 1.27.2
grpc-version: 1.51.1
- name: Copy grpc to system default
run: |
sudo rsync -a $GRPC_ROOT/ /usr/local
sudo ldconfig
- name: Install bmi-cxx
run: |
git clone -b v2.0 https://github.com/csdms/bmi-cxx.git bmi-cxx
mkdir bmi-cxx/build
cd bmi-cxx/build
cmake ..
make install
- name: Install bmi-cxx
run: |
git clone -b v2.1 https://github.com/csdms/bmi-c.git bmi-c
mkdir bmi-c/build
cd bmi-c/build
cmake ..
make install
- name: Build dir
run: mkdir -p cpp/build
- name: configure
Expand All @@ -70,3 +93,4 @@ jobs:
- name: ctest
run: ctest -V
working-directory: cpp/build
# TODO use https://github.com/marketplace/actions/sonarcloud-scan-for-c-and-c
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,6 @@ ENV/

# mypy
.mypy_cache/

# Apptainer images
*.sif
6 changes: 0 additions & 6 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,6 +0,0 @@
[submodule "cpp/bmi-cxx"]
path = cpp/bmi-cxx
url = https://github.com/csdms/bmi-cxx.git
[submodule "cpp/bmi-c"]
path = cpp/bmi-c
url = https://github.com/csdms/bmi-c.git
16 changes: 16 additions & 0 deletions .readthedocs.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
version: 2

build:
os: "ubuntu-22.04"
tools:
python: "3.10"

sphinx:
configuration: docs/conf.py

python:
install:
- method: pip
path: .
extra_requirements:
- docs
44 changes: 30 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

## Purpose

This software allows you to wrap your Basic Model Interface (BMI) implementation ([https://github.com/csdms/bmi](https://github.com/csdms/bmi)) 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/](https://grpc.io/)) and occurs over network ports.
This software allows you to wrap your [Basic Model Interface (BMI)](https://github.com/csdms/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. Can run models in isolated containers using Docker or Apptainer.

## Installation

Expand Down Expand Up @@ -43,13 +43,17 @@ in the cpp folder.

### Model written in Python

For inspiration look at the example in the test directory. To start a server process that allows calls to your BMI implementation, type
A model should be a subclass of the `Bmi` class from the [bmipy](https://pypi.org/project/bmipy/2.0/) package.

For inspiration look at the [example](test/fake_models.py) in the test directory.

To start a server process that allows calls to your BMI implementation, type

```bash
run-bmi-server --name <PACKAGE>.<MODULE>.<CLASS> --port <PORT> --path <PATH>
```

where ```<PACKAGE>, <MODULE>``` are the Python package and module containing your implementation, ```<CLASS>``` is your
where ```<PACKAGE>, <MODULE>``` are the python package and module containing your implementation, ```<CLASS>``` is your
bmi model class name, ```<PORT>``` is any available port on the host system, and optionally ```<PATH>``` denotes an
additional path that should be added to the system path to make your implementation work. The name option above is
optional, and if not provided the script will look at the environment variables ```BMI_PACKAGE```, ```BMI_MODULE``` and
Expand Down Expand Up @@ -99,9 +103,8 @@ mymodel.initialize(<FILEPATH>)
...further BMI calls...
```

The package contains also client implementation that own the server process, either as a Python subprocess or a docker
image or a singularity image running the ```run-bmi-server``` script. For instance

The package contains also client implementation that own the server process, either as a Python subprocess or a Docker
container or a Singularity container or a Apptainer container running the ```run-bmi-server``` script. For instance
```python
from grpc4bmi.bmi_client_subproc import BmiClientSubProcess
mymodel = BmiClientSubProcess(<PACKAGE>.<MODULE>.<CLASS>)
Expand All @@ -110,18 +113,25 @@ mymodel = BmiClientSubProcess(<PACKAGE>.<MODULE>.<CLASS>)
will automatically launch the server in a sub-process and

```python
from grpc4bmi.bmi_client_subproc import BmiClientDocker
mymodel = BmiClientDocker(<IMAGE>,<PORT>)
from grpc4bmi.bmi_client_docker import BmiClientDocker
mymodel = BmiClientDocker(<IMAGE>, <WORK DIR TO MOUNT>, input_dirs=[<INPUT DIRECTORIES TO MOUNT>])
```

will launch a docker container, assuming that a gRPC BMI server will start and exposes the port ```<PORT>```.
will launch a Docker container based on supplied Docker image
and will mount supplied directories to share files between the container and host.

```python
from grpc4bmi.bmi_client_singularity import BmiClientSingularity
mymodel = BmiClientSingularity(<IMAGE>,<PORT>)
mymodel = BmiClientSingularity(<IMAGE>, <WORK DIR TO MOUNT>, input_dirs=[<INPUT DIRECTORIES TO MOUNT>])
```
will launch a singularity container on based supplied Singularity image
and will mount supplied directories to share files between the container and host.

will launch a singularity container, assuming that a gRPC BMI server will start and exposes the port ```<PORT>```.
```python
from grpc4bmi.bmi_client_apptainer import BmiClientApptainer
mymodel = BmiClientApptainer(<IMAGE>, <WORK DIR TO MOUNT>, input_dirs=[<INPUT DIRECTORIES TO MOUNT>])
```
will launch a Apptainer container on based supplied Apptainer image
and will mount supplied directories to share files between the container and host.

For more documentation see [https://grpc4bmi.readthedocs.io/](https://grpc4bmi.readthedocs.io/).

Expand All @@ -130,10 +140,16 @@ For more documentation see [https://grpc4bmi.readthedocs.io/](https://grpc4bmi.r
When developers change the proto-file, it is necessary to install gRPC tools Python packages in your Python environment:

```bash
pip install -r requirements.txt
pip install -e .
# Create virtual env
python3 -m venv .venv
. venv/bin/activate
# Make sure latest pip and wheel are install
pip install -U pip wheel
pip install -e .[dev]
# For R integration also install the R extras with
pip install -e .[R]
# For building docs (cd docs && make html) also install the docs extras with
pip install -e .[docs]
```

and install the C++ runtime and `protoc` command as described in <https://github.com/google/protobuf/blob/master/src/README.md>.
Expand Down
31 changes: 24 additions & 7 deletions cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,17 +1,25 @@
cmake_minimum_required (VERSION 2.6)
cmake_minimum_required (VERSION 3.6)

project (grpc4bmi)
project (grpc4bmi C CXX)
set (GRPC4BMI_VERSION 0.2)

configure_file(${CMAKE_CURRENT_SOURCE_DIR}/grpc4bmi.pc.cmake
${CMAKE_CURRENT_BINARY_DIR}/grpc4bmi.pc)

add_compile_options(-std=c++11)
if (NOT DEFINED CMAKE_CXX_STANDARD)
set (CMAKE_CXX_STANDARD 14)
endif()

find_package(Threads REQUIRED)
find_package(Protobuf REQUIRED)
message(STATUS "Using protobuf ${Protobuf_VERSION}")
find_program(GRPC_CPP_PLUGIN grpc_cpp_plugin REQUIRED)
find_library(GRPCPP_UNSECURE grpc++_unsecure)
find_library(GRPCLIB grpc)
find_library(GRPCREFLECTION grpc++_reflection)
find_library(GRPCLIB grpc CONFIG REQUIRED)
message(STATUS "Using gRPC ${GRPCLIB_VERSION}")
find_package(PkgConfig REQUIRED)
pkg_check_modules(BMI REQUIRED IMPORTED_TARGET bmic bmicxx)
message(STATUS "Using BMI ${BMI_VERSION}")

set(PROTO_PATH "${CMAKE_SOURCE_DIR}/../proto/grpc4bmi")
add_custom_command(
Expand All @@ -31,11 +39,20 @@ add_custom_command(
)
set(GRPC_SRC_FILES ${CMAKE_CURRENT_BINARY_DIR}/bmi.pb.cc ${CMAKE_CURRENT_BINARY_DIR}/bmi.grpc.pb.cc)
set(GRPC_HDR_FILES ${CMAKE_CURRENT_BINARY_DIR}/bmi.pb.h ${CMAKE_CURRENT_BINARY_DIR}/bmi.grpc.pb.h)
link_libraries(${PROTOBUF_LIBRARY} ${GRPCPP_UNSECURE} ${GRPC} ${BMIC})

include_directories(${CMAKE_SOURCE_DIR})
include_directories(${CMAKE_CURRENT_BINARY_DIR})
add_library (grpc4bmi SHARED bmi-c/bmi.h bmi-cxx/bmi.hxx bmi_cpp_extension.h bmi_cpp_extension.cc
include_directories(${BMI_INCLUDE_DIRS})

add_library (grpc4bmi SHARED bmi_cpp_extension.h bmi_cpp_extension.cc
bmi_c_wrapper.h bmi_c_wrapper.cc bmi_grpc_server.cc bmi_grpc_server.h ${GRPC_SRC_FILES} ${GRPC_HDR_FILES})

target_link_libraries(
grpc4bmi
${GRPCREFLECTION}
${GRPC}
${PROTOBUF_LIBRARY}
)
set_target_properties(grpc4bmi PROPERTIES PUBLIC_HEADER "bmi_cpp_extension.h;bmi_c_wrapper.h;bmi_grpc_server.h;${GRPC_HDR_FILES}")
add_subdirectory (test)

Expand Down
1 change: 0 additions & 1 deletion cpp/bmi-c
Submodule bmi-c deleted from 9b5b34
1 change: 0 additions & 1 deletion cpp/bmi-cxx
Submodule bmi-cxx deleted from 46cec3
Loading

0 comments on commit 236ec61

Please sign in to comment.