The pymusic interface

MUSIC has recently acquired a plain Python interface to go along with the C++ API. If you just want to connect with a simulation rather than adding MUSIC capability to a simulator, this Python interface can be a lot more convenient than C++. You have Numpy, Scipy and other high-level libraries available, and you don’t need to compile anything.

The interface is closely modelled on the C++ API; indeed, the steps to use it is almost exactly the same. You can mostly refer to the C++ description for explanation. Below we will only highlight the differences to the C++ API. The full example code is in the pymusic directory in the MUSIC repository.

Note

Please note that MUSIC and the recording backend for Arbor are mutually exclusive and cannot be enabled at the same time.

 1#!/usr/bin/env python3
 2import music
 3
 4[ ... ]
 5
 6outdata.map(music.Index.GLOBAL,
 7    base=firstId,
 8        size=nlocal)
 9
10[ ...]
11
12runtime = setup.runtime(TICK)
13tickt = runtime.time()
14while tickt < simtime:
15
16    for i in range(width):
17    send_poisson(outdata, RATE, tickt, i)
18
19    runtime.tick()
20    tickt = runtime.time()

The sending code is almost completely identical to its C++ counterpart. Make sure python3 is used as interpreter for the code (and make sure this file is executable). Import music in the expected way.

Unlike the C++ API, the index is not an object, but simply a label indicating global or local indexing. The map() call thus need to get the first ID and the number of elements mapped to this rank directly. Also note that the map() functions have a somewhat unexpected parameter order, so it’s best to use named parameters just in case.

The runtime looks the same as the C++ counterpart as well. We get the current simulation time, and repeatedly send new sets of events as long as the current time is smaller than the simulation time.

 1import Queue
 2
 3in_q = Queue.Queue()
 4
 5# Our input handler function
 6def inhandler(t, indextype, channel_id):
 7    in_q.put([t, channel_id])
 8
 9    [ ... ]
10
11indata.map(inhandler,
12        music.Index.GLOBAL,
13        base=firstId,
14        size=nlocal,
15        accLatency=IN_LATENCY)
16
17tickt = runtime.time()
18while tickt < simtime:
19
20    runtime.tick()
21    tickt = runtime.time()
22
23    while not in_q.empty():
24        ev = in_q.get()
25        f.write("{0}\t{1:8.4f}\n".format(ev[1], ev[0]))

Here is the structure for the receiving process, modelled on the C++ code. We use a Python Queue class to implement our event queue.

The input handler function has signature (float time, int indextype, int channel_id). The time and channel_id are the event times and IDs as before. The indextype is the type of the map index for this input and is music.Index.LOCAL or music.Index.GLOBAL.

The map() function keyword for acceptable latency is accLatency, and the maxBuffered keyword we mentioned in the previous section is, unsurprisingly, maxBuffered. The runtime is, again, the same as for C++.

As the pymusic bindings are still quite new, the documentation is still lagging behind. This quick introduction should nevertheless be enough for you to get going with the bindings. Feel free to ask our Mailing List if you need further help.