Message structure

Introduction

The messages for SIM0MQ are aimed at executing distributed simulations. This means that multiple models, or so-called federates (a logging component in a federation is not a model, but still gets messsages), have to exchange information. The idea behind the SIM0MQ messages is that we build in some fault-tolerance, e.g., by clearly defining the sender and receiver of the message,and the type of each field in the message. In this way, we can check the validity of the message in the given circumstances. Furthermore, it is considered to be useful to know the message type, to avoid mistakes for parsing the wrong message. Although it adds a bit to the message overhead, the benefits of not parsing and interpreting a wrong message are clearly outweighing the transmission of a few bytes. In cases where many short messages of a certain type are sent, untyped messages could be preferred over typed simulation messages.

In many cases, we want to distinguish between a definition of something, a subsequent change, and the deletion or termination of something. As an example, a generated entity can report its initial status, update state changes, and indicate when it leaves the simulation. Therefore a one-byte status is included in the message header to indicate its status.If it is not needed, it can be set to zero.

Finally, when multiple simulations are running in parallel, it is important to know for which running simulation the message is intended. In case it gets delivered to the wrong simulation, it can be discarded and potentially, the mistake can be logged.

All fields are serialized with the standards as defined in the djunits-serialization manual, which describes the encoding/decoding (aka serializing/deserializing, marshalling/unmarshalling) of different types of fields, such as primitives, vectors, matrices, strings, and scalars, vectors and matrices with units. In addition, endianness is taken into account for the (de)coding of the fields.

Structure

The message structure of a typical typed Sim0MQ simulation message looks as follows:

Frame 0. Magic number = |9|0|0|0|5|S|I|M|#|#| where ## stands for the version number, e.g., 01. The magic number is always coded as a UTF-8 String, so it always starts with a byte equal to 9.

Frame 1. Federation id. Federation ids can be provided in different types. Examples are a 64-bit long, or a String with a UUID number, a String with meaningful identification, or a short or an int with a simulation run number. In order to check whether the right information has been received, the id can be translated to a String and compared with an internal string representation of the required simulation run id. Typically we use a String to provide maximum freedom. In that case, the run id can be coded as UTF-8 or UTF-16.

Frame 2. Sender id. Sender ids can be provided in different types. Examples are a 64-bit long, or a String with a UUID number, a String with meaningful identification, or a short or an int with a sender id number. The sender id can be used to send back a message to the sender at some later time. Typically we use a String to provide maximum freedom. In that case, the sender id can be coded as UTF-8 or UTF-16.

Frame 3. Receiver id. Receiver ids can be provided in different types. Examples are a 64-bit long, or a String with a UUID number, a String with meaningful identification, or a short or an int with a receiver id number. The receiver id can be used to check whether the message is meant for us, or should be discarded (or an error can be sent if we receive a message not meant for us). Typically we use a String to provide maximum freedom. In that case, the receiver id can be coded as UTF-8 or UTF-16.

Frame 4. Message type id. Message type ids can be defined per type of simulation, and can be provided in different types. Examples are a String with a meaningful identification, or a short or an int with a message type number. For interoperability between different types of simulation, a String id with dot-notation (e.g., DSOL.1 for a simulator start message from DSOL or OTS.14 for a statistics message from OpenTrafficSim) would be preferred. In that case, the run id can be coded as UTF-8 or UTF-16.

Frame 5. Unique message number. The unique message number will be sent as a long (64 bits), and is meant to confirm with a callback that the message has been received correctly. The number is unique for the sender, so not globally within the federation.

Frame 6. Message status id. Messages can be about something new (containing a definition that can be quite long), an update (which is often just an id followed by a single number), and a deletion (which is often just an id). The three different status codes are defined as follows: 1 for new, 2 for change, and 3 for delete. The message status is is coded as a byte. Zero is also a possible value for messages where the status does not matter.

Frame 7. Number of fields. The number of fields in the payload is indicated to be able to check the payload and to avoid reading past the end. The number of fields can be encoded using byte, short, or int. A 32-bit positive int (including zero) is the standard encoding.

Frame 8-n. Payload, where each field has a 1-byte prefix denoting the type of field.

Example coding standard

In the rest of the manual (and in the example implementation), the federation id, sender id, receiver id, and message id are coded sing dot notation:

  • The federation id is coded as a UTF-8 String with a short abbreviation for the type of simulation that is running, folllowed by a dot and the experiment id, followed by a dot and the replication id. An example for federation 'IDVV', experiment 4, replication 7 is "IDVV.4.7".
  • The sender id is coded as a UTF-8 String with an abbreviation for the federate name, followed by a dot and number in case multiple federates (can) exist. The (sinle) Model Controller can therefore be coded as "MC.1".
  • The receiver id is coded as a UTF-8 String with an abbreviation for the federate name, followed by a dot and number in case multiple federates (can) exist. The (first) Logging component can therefore be coded as "LOG.1".
  • The message id is coded as a UTF-8 String with an abbreviation for the originating type of federate, followed by a dot and number to distinguish the message types. An example is the message from the Federation Manager (FM) to start a federate on a node in the network, and is sent to the Federate Starter, which has the code FM.1. The Federate Starter answers with a message "FederateStarted" that has code FS.1.

Message Example

Suppose we have a simulation called IDVV.14.2 in which a message to change the (double) simulation speed to the value 0.2 is sent, of which the message type is DSOL.3. The message is sent by "MC.1" and received by "MM1.4". Suppose the message number is 124. Then the message looks as follows (note that the double representation of 0.2 is 0x3FC999999999999A):

|9|0|0|0|5|S|I|M|0|1|9|0|0|0|9|I|D|V|V|.|1|4|.|2| 
|9|0|0|0|4|M|C|.|1|9|0|0|0|5|M|M|1|.|4|9|0|0|0|6|D|S|O|L|.|3| 
|3|0|0|0|0|0|0|0|124|0|2|1|0|1| 
|5|0x3F|0xC9|0x99|0x99|0x99|0x99|0x99|0x9A|

or field by field:

0. Magic number:   |9|0|0|0|5|S|I|M|0|1|          (String, 5 chars, SIM01)
1. Federation id:  |9|0|0|0|9|I|D|V|V|.|1|4|.|2|  (String, 9 chars, IDVV14.2)
2. Sender id:      |9|0|0|0|4|M|C|.|1|            (String, 4 chars, MC.1)
3. Receiver id:    |9|0|0|0|5|M|M|1|.|4|          (String, 5 chars, MM1.4)
4. Message type:   |9|0|0|0|6|D|S|O|L|.|3|        (String, 6 chars, DSOL.3)
5. Message id:     |3|0|0|0|0|0|0|0|124|          (Long, 8 bytes, 124)
6. Status id:      |0|2|                          (Byte, value 2, CHANGE)
7. Nr of fields:   |1|0|1|                        (Short, value 1)
8. Payload:        |5|0x3F|0xC9|0x99|0x99|0x99|0x99|0x99|0x9A|  (Double, 0.2)