Architecture
The purpose of iMOD Coupler is to couple hydrological kernels. iMOD Coupler itself is written in Python, but the kernels are written in either Julia or Fortran. The most common way of interacting with libraries written in different languages is by letting them expose a C interface and compiling them as shared libraries.
While not technically required, these libraries are expected to follow a variation of the Basic Model Interface or BMI. This describes a standardized way of controlling a modelling framework. It also allows to utilize the xmipy
package, which wraps the C API into a Python API. On top of that, it is often convenient to add functions specific to the kernels. This is why Ribasim and MODFLOW 6 get a XmiWrapper
subclass, that is called ribasim_api
and modflow_api
respectively.
Most input data needs to be pre-processed in order to be suitable for the hydrological kernels. In the case of Ribasim this is handled by Ribasim Python, in the case of MODFLOW 6 it is handled by iMOD Python. However, the input data for the iMOD Coupler needs to be pre-processed as well. Coupling tables describe how the coupling takes place. In order to generate them, input data from all kernels are needed. The primod
package wraps the functionality of the kernel pre-processors and generates the coupling data for iMOD Coupler.
Drivers
Coupling Ribasim and MODFLOW 6 is only one of multiple coupling configurations. Each configuration is handled by an iMOD Coupler driver. A driver is a Python module under imod_coupler/drivers
. At the minimum, it includes a subclass of the abstract class Driver
as well as its own config under the [[driver.coupling]]
namespace. A driver itself also includes a BMI interface, executing it then looks like this:
self.initialize()
while self.get_current_time() < self.get_end_time():
self.update()
self.finalize()
Logging of exchanged values
An integral task of an iMOD Coupler driver is to support the exchange of values between hydrological kernels. Values exchanged by the coupler for a specific variable can optionally be written to file during the simulation for inspection. These values are written as timeseries to separate files per variable. In the initialization stage of the simulation a dictionary-like structure (ExchangeCollector class) is created which holds a collection of labelled ExchangeLogger instances. The initialization of an ExchangeLogger creates a netcdf file with dimensions time
and id
, a variable time
with dimension (time
) and a variable xchg
with dimensions (time
, id
). The time dimension is the unlimited dimension.
Continuous Integration
We took great care to set up a pipeline to ensure that iMOD Coupler continues to work with the newest version of its dependencies. This is especially important since we access internal state of the kernels when coupling them. It can happen very easily that kernel developers change something that break assumptions of the coupler.
At the time of this writing, there are three kernels handled by iMOD Coupler:
- Ribasim,
- MODFLOW 6, and
- MetaSWAP.
On TeamCity, the three kernels will be compiled to shared libraries and iMOD Coupler will be compiled to an executable. These binaries are then collected in a zip file, called the iMOD Collector. The iMOD Collector is checked on our testbench and can be downloaded by users.