mosaik-api 0.1.0

High-level API for Mosaik, a flexible Smart Grid co-simulation framework.
Documentation
# Rust API for Mosaik

This project allows Rust code to operate with Mosaik simulations in Python.
It provides a high-level API for simulators written in Rust to communicate with the [Mosaik Smart-Grid co-simulation framework](https://mosaik.offis.de/).

The API is based on the [Mosaik API](https://mosaik.readthedocs.io/en/3.3.3/mosaik-api/index.html) and is compatible with Mosaik version 3 <mark>but does not support asynchronous communication yet.</mark>

## Content of this repository

The [src](./src/) folder contains the components for communicating between Rust simulators and Mosaik:

- The trait for the **high-level API** in [lib.rs]./src/lib.rs.
- The **data types** used in the API and simulators in [types.rs]./src/types.rs.
- The **TCP manager** in [tcp.rs]./src/tcp.rs.
- The **parsing** and **handling of MosaikMessages** and low-level connection to simulators in [mosaik_protocol.rs]./src/mosaik_protocol.rs.

The [examples](./examples/) folder contains example simulators based on the [official Python tutorial](https://mosaik.readthedocs.io/en/3.3.3/tutorials/index.html) to demonstrate the API. See section [Running the example scenarios](#running-the-example-scenarios) for more information.

## Requirements

- A working Rust environment ([Install Rust]https://www.rust-lang.org/tools/install). The dependencies are declared in the [Cargo.toml]./Cargo.toml file.
- To run the examples you need a working Python environment, the setup of which is described [below]#running-the-example-scenarios.

## Implementing a simulation in Rust

For a simulator written in Rust to successfully communicate with Mosaik you must:

1. Add `mosaik-api = { git = "https://github.com/ekut-es/mosaik-api" }` to your `Cargo.toml` as a dependency.
2. Implement the `MosaikApi` trait for your simulator.
3. Use the `run_simulation()` function in your `main` to connect your simulator to Mosaik. This connects your simulator to Mosaik and handles the communication over a TCP channel. The `ConnectionDirection` depends on how you connect your simulator to Mosaik in Python (see [Connection Setup]#connection-setup).
4. Then connect the simulators in the `SIM_CONFIG` of your Mosaik python script as described in the following paragraph.

### Connection Setup

We support two ways to connect Rust simulators for communication with Mosaik. It is sufficient to implement one but possible to implement both simultaneously as shown in the [examples](#running-the-example-scenarios).

1. Invoke the Rust simulator and parse Mosaik's `addr` to it, via the `"cmd"` keyword in Mosaik's `SIM_CONFIG` in Python. For this you need the `ConnectionDirecton::ConnectToAddress` in Rust with the given address of Mosaik.
2. Run the Rust simulator manually with a predefined `addr` and connect Mosaik to it with the `"connect"` keyword in Mosaik's `SIM_CONFIG` in Python. In Rust you need to use `ConnectionDirecton::ListenOnAddress` for the `run_simulation()`.

Example setup to illustrate these two options with `ADDR` as the address of the communication channel between Mosaik and the Rust simulator, e.g. `127.0.0.1:5678`:

| Mosaik `SIM_CONFIG` key                       | Rust `ConnectionDirection` for `run_simulation()` | Notes                                                                                  |
| --------------------------------------------- | ------------------------------------------------- | -------------------------------------------------------------------------------------- |
| `"cmd": "cargo run SIMULATOR -- -a=%(addr)s"` | `ConnectionDirection::ConnectToAddress(ADDR)`     | ADDR needs to be read in from the CLI in Rust.                                         |
| `"connect": "ADDR"`                           | `ConnectionDirection::ListenOnAddress(ADDR)`      | Simulator needs to be started before running the Python script on the predefined ADDR. |

## Running the example scenarios

The example simulations are located in the [examples folder](./examples/).
It includes two scenarios inspired by the [Python tutorials](https://mosaik.readthedocs.io/en/3.3.3/tutorials/index.html): demo1 and demo2.
In contrast to the Python tutorials, the simulations are written in Rust and only invoked by a modified Python script to connect the Rust simulators with Mosaik (or connecting Mosaik with the simulators as shown by the Controller in demo2).

- The scenario in **Demo 1** consists of an example model `Model` used in the *hybrid* `ExampleSim` both implemented in [example_sim.rs]./examples/example_sim.rs and an *event-based* Monitor called `Collector` in [collector.rs]./examples/collector.rs.
- The scenario in **Demo 2** consists additionaly of the Rust implementation of an event-based [`Controller`]./examples/controller.rs. This controller is connected via a TCP connection instead of being run by the Python script for the sake of demonstration.

To run them, build a virtual environment for python:

```bash
virtualenv .venv_examples && \
source .venv_examples/bin/activate && \
pip install "mosaik>=3.3"
```

Then run the example scenarios with:

```bash
cargo build --examples
python examples/demo1.py
```

or

```bash
cargo build --examples
cargo run --example connector & python examples/demo2.py
```

## Local Development

For further development in this repository, it is recommended that you use [pre-commit](https://pre-commit.com/) and install the local pre-commit hook by running `pre-commit install` in your terminal.