The high-level API

Currently, there are high-level APIs for Python, Java, C#, and MatLab.

Installation

The Python implementation of the mosaik API is available as a separate package an can easily be installed via pip:

pip install mosaik-api

It supports Python 2.7, >= 3.3 and PyPy.

For the use of the Java-API please refer to the Java-tutorial.

Usage

You create a subclass of mosaik_api.Simulator which implements the four API calls init(), create(), step() and get_data(). You can optionally override configure() and finalize(). The former allows you to handle additional command line arguments that your simulator may need. The latter is called just before the simulator terminates and allows you to perform some clean-up.

You then call mosaik_api.start_simulation() from your main() function to get everything set-up and running. That function handles the networking as well as serialization and de-serialization of messages. Commands from the low-level API are translated to simple function calls. The return value of these functions is used for the reply.

For example, the message

["create", [2, "Model", {"param1": 15, "param2": "spam"}]

will result in a call

create(2, 'Model', param1=15, param2='spam')

API calls

class mosaik_api.Simulator(meta)

This is the base class that you need to inherit from and implement the API calls.

meta

Meta data describing the simulator (the same that is returned by init()).

{
    'api_version': 'x.y',
    'type': 'time-based'|'event-based'|'hybrid',
    'models': {
        'ModelName': {
            'public': True|False,
            'params': ['param_1', ...],
            'attrs': ['attr_1', ...],
            'any_inputs': True|False,
            'trigger': ['attr_1', ...],
            'non-persistent': ['attr_2', ...],
        },
        ...
    },
    'extra_methods': [
        'do_cool_stuff',
        'set_static_data'
    ]
}

The api_version is a string that defines which version of the mosaik API the simulator implements. Since mosaik API version 2.3, the simulator’s major version (“x”, in the snippet above) has to be equal to mosaik’s. Mosaik will cancel the simulation if a version mismatch occurs.

The type defines how the simulator is advanced through time and whether its attributes are persistent in time or transient.

models is a dictionary describing the models provided by this simulator. The entry public determines whether a model can be instantiated by a user (True) or if it is a sub-model that cannot be created directly (False). params is a list of parameter names that can be passed to the model when creating it. attrs is a list of attribute names that can be accessed (reading or writing). If the optional any_inputs flag is set to true, any attributes can be connected to the model, even if they are not attrs. This may, for example, be useful for databases that don’t know in advance which attributes of an entity they’ll receive. trigger is a list of attribute names that cause the simulator to be stepped when another simulator provides output which is connected to one of those.

extra_methods is an optional list of methods that a simulator provides in addition to the standard API calls (init(), create() and so on). These methods can be called while the scenario is being created and can be used for operations that don’t really belong into init() or create().

mosaik

An RPC proxy to mosaik.

time_resolution

The time resolution of the scenario.

init(sid, time_resolution=1.0, **sim_params)
Initialize the simulator with the ID sid and pass the

time_resolution and additional parameters (sim_params) sent by mosaik. Return the meta data meta.

If your simulator has no sim_params, you don’t need to override this method.

create(num, model, **model_params)

Create num instances of model using the provided model_params.

num is an integer for the number of model instances to create.

model needs to be a public entry in the simulator’s meta['models'].

model_params is a dictionary mapping parameters (from meta['models'][model]['params']) to their values.

Return a (nested) list of dictionaries describing the created model instances (entities). The root list must contain exactly num elements. The number of objects in sub-lists is not constrained:

[
    {
        'eid': 'eid_1',
        'type': 'model_name',
        'rel': ['eid_2', ...],
        'children': [
            {'eid': 'child_1', 'type': 'child'},
            ...
        ],
    },
    ...
]

The entity ID (eid) of an object must be unique within a simulator instance. For entities in the root list, type must be the same as the model parameter. The type for objects in sub-lists may be anything that can be found in meta['models']. rel is an optional list of related entities; “related” means that two entities are somehow connect within the simulator, either logically or via a real data-flow (e.g., grid nodes are related to their adjacent branches). The children entry is optional and may contain a sub-list of entities.

setup_done()

Callback that indicates that the scenario setup is done and the actual simulation is about to start.

At this point, all entities and all connections between them are know but no simulator has been stepped yet.

Implementing this method is optional.

Added in mosaik API version 2.3

step(time, inputs, max_advance)

Perform the next simulation step from time time using input values from inputs and return the new simulation time (the time at which step() should be called again).

time and the time returned are integers. Their unit is arbitrary, e.g. seconds (from simulation start), but has to be consistent among all simulators used in a simulation.

inputs is a dict of dicts mapping entity IDs to attributes and dicts of values (each simulator has to decide on its own how to reduce the values (e.g., as its sum, average or maximum):

{
    'dest_eid': {
        'attr': {'src_fullid': val, ...},
        ...
    },
    ...
}

max_advance tells the simulator how far it can advance its time without risking any causality error, i.e. it is guaranteed that no external step will be triggered before max_advance + 1, unless the simulator activates an output loop earlier than that. For time-based simulators (or hybrid ones without any triggering input) max_advance is always equal to the end of the simulation (until).

get_data(outputs)

Return the data for the requested attributes in outputs

outputs is a dict mapping entity IDs to lists of attribute names whose values are requested:

{
    'eid_1': ['attr_1', 'attr_2', ...],
    ...
}

The return value needs to be a dict of dicts mapping entity IDs and attribute names to their values:

{
    'eid_1: {
        'attr_1': 'val_1',
        'attr_2': 'val_2',
        ...
    },
    ...
    'time': output_time (for event-based sims, optional)
}

Time-based simulators have set an entry for all requested attributes, whereas for event-based and hybrid simulators this is optional (e.g. if there’s no new event). Event-based and hybrid simulators can optionally set a timing of their non-persistent output attributes via a time entry, which is valid for all given (non-persistent) attributes. If not given, it defaults to the current time of the step. Thus only one output time is possible per step. For further output times the simulator has to schedule another self-step (via the step’s return value).

configure(args, backend, env)

This method can be overridden to configure the simulation with the command line args as created by docopt.

backend and env are the simpy.io backend and environment used for networking. You can use them to start extra processes (e.g., a web server).

The default implementation simply ignores them.

finalize()

This method can be overridden to do some clean-up operations after the simulation finished (e.g., shutting down external processes).

The mosaik-api package provides an example simulator that demonstrates how the API can be implemented.

Asynchronous requests

The asynchronous requests can be called via the MosaikRemote proxy self.mosaik from within step(), except for set_data() which has to be called from another thread/process (see below). They don’t return the actual results but an event (similar to a future of deferred). The event will eventually hold the actual result. To wait for that result to arrive, you simply yield the event, e.g.:

def step(self, time, inputs, max_advance):
    progress = yield self.mosaik.get_progress()
    # ...
MosaikRemote.get_progress()

Return the current simulation progress from sim_progress.

MosaikRemote.get_related_entities(entities=None)

Return information about the related entities of entities.

If entities omitted (or None), return the complete entity graph, e.g.:

{
    'nodes': {
        'sid_0.eid_0': {'type': 'A'},
        'sid_0.eid_1': {'type': 'B'},
        'sid_1.eid_0': {'type': 'C'},
    },
    'edges': [
        ['sid_0.eid_0', 'sid_1.eid0', {}],
        ['sid_0.eid_1', 'sid_1.eid0', {}],
    ],
}

If entities is a single string (e.g., sid_1.eid_0), return a dict containing all entities related to that entity:

{
    'sid_0.eid_0': {'type': 'A'},
    'sid_0.eid_1': {'type': 'B'},
}

If entities is a list of entity IDs (e.g., ['sid_0.eid_0', 'sid_0.eid_1']), return a dict mapping each entity to a dict of related entities:

{
    'sid_0.eid_0': {
        'sid_1.eid_0': {'type': 'B'},
    },
    'sid_0.eid_1': {
        'sid_1.eid_1': {'type': 'B'},
    },
}
MosaikRemote.get_data(attrs)

Return the data for the requested attributes attrs.

attrs is a dict of (fully qualified) entity IDs mapping to lists of attribute names ({'sid/eid': ['attr1', 'attr2']}).

The return value is a dictionary, which maps the input entity IDs to data dictionaries, which in turn map attribute names to their respective values: ({'sid/eid': {'attr1': val1, 'attr2': val2}}).

MosaikRemote.set_data(data)

Set data as input data for all affected simulators.

data is a dictionary mapping source entity IDs to destination entity IDs with dictionaries of attributes and values ({'src_full_id': {'dest_full_id': {'attr1': 'val1', 'attr2': 'val2'}}}).

MosaikRemote.set_event(event_time)

Schedules an event/step at simulation time event_time.

The mosaik-api package provides an example “multi-agent system” that demonstrates how asynchronous requests can be implemented.

Starting the simulator

To start your simulator, you just need to create an instance of your Simulator sub-class and pass it to start_simulation():

mosaik_api.start_simulation(simulator, description='', extra_options=None)

Start the simulation process for simulation.

simulation is the instance of your API implementation (see Simulator).

description may override the default description printed with the help on the command line.

extra_option may be a list of options for docopt (example: ['-e, --example     Enable example mode']). Commandline arguments are passed to Simulator.configure() so that your API implementation can handle them.

Here is an example with a bit more context:

import mosaik_api


example_meta = {
    'type': 'time-based',
    'models' {
        'A': {
              'public': True,
              'params': ['init_val'],
              'attrs': ['val_out', 'dummy_out'],
        },
    }
}


class ExampleSim(mosaik_api.Simulator):
    def __init__(self):
        super().__init__(example_meta)

    sim_name = 'ExampleSimulation'

    def configure(self, args, backend, env):
        # Here you could handle additional command line arguments

    def init(self, sid):
        # Initialize the simulator
        return self.meta

    # Implement the remaining methods (create, step, get_data, ...)


def main():
    import sys

    description = 'A simple example simulation for mosaik.'
    extra_options = [
       '--foo       Enable foo',
       '--bar BAR   The bar parameter',
    ]

    return mosaik_api.start_simulation(ExampleSim(), description, extra_options)


if __name__ == '__main__':
    sys.exit(main())