Get MASyV at SourceForge.net. Fast, secure and Free Open Source software downloads


MASyV's API (or Writing your own client simulations)

Coming soon: Actual GTK-style API definitions which will be much more helpful.

MASyV, which stands for Multi-Agent System Visualization, was developed to facilitate the visualization of cellular automata, or agent-based or individual-based models, without the need for the user to actually implement a graphical user interface (GUI). The software employs a client-server architecture with the server providing I/O and supervisory services to the client simulation. The MASyV package consists of a GUI server, masyv, a non-graphical command-line server, logmasyv, and a message passing library, libmasyv, which provides functions to be used by the client to communicate with the server.

The message passing library was implemented to enforce standards in the way the client simulations should communicate with the server, but also to save one the trouble of having to duplicate and maintain the code to speak with the server (command-line or GUI) in each client simulation. It consists of libmasyv.so, the actual message passing library, and "#include <masyv⁄masyv.h>", which contains the function prototypes and defines a few useful macros for use by the clients. The client communicates with the server through a Unix domain socket stream using the message types provided by the message passing library.

The message passing library defines the following message types to be used by the client:

  • masyv_create_client_socket_file(char *program_name, char *address );
  • masyv_send_pixtablespec(int socket_fd, float grid_unit_cell[2][2], int num_layers, int *num_images);
  • masyv_send_arena_size(int socket_fd, int width, int height);
  • masyv_send_texels(int socket_fd, int layer_num, int image_num, int width, int height, const unsigned char *pixels);
  • masyv_send_start_step(int socket_fd, int total_time, int clear);
  • masyv_send_stop_sequence(int socket_fd);
  • masyv_send_agent(int socket_fd, int x, int y, int layer, int image, int opacity);
  • masyv_send_circle(int socket_fd, int x, int y, int layer, int radius, int opacity);
  • masyv_send_stats(int socket_fd, char *stats);
  • masyv_receive_msg(int client_socket_fd, struct ma_receive_ops_t *ops, void *data);
  • masyv_send_terminate_signal(int client_socket_fd);
  • masyv_random_a_b(int a, int b);
  • masyv_drandom_a_b(double a, double b);
  • Messages masyv_send_pixtablespec, masyv_send_arena_size, and masyv_send_texels are used by the client at initialization time to prepare the GUI, while masyv_send_start_step, masyv_send_stop_sequence, masyv_send_agent, masyv_send_circle, and masyv_send_stats are messages sent by the client during the simulation to tell the server how to update the simulation grid and the statistics produced by the client.

    To demonstrate usage of the message passing library by the client, let us look at the Hello World example of a client simulation, ma_hello, which consists of a single grey square moving around randomly on a square grid.

    #include <unistd.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <masyv/masyv.h>
    #include "particle.c" /* The image of the square */
    
    #define PROGRAM_NAME "ma_hello"
    #define GRID_SPACING 4
    #define NUM_LAYERS 1  /* Number of layers */
    #define LAYER 0       /* The name of the only layer */
    #define NUM_IMAGES 1  /* Number of images in the LAYER layer */
    
    char *ui_socket_address = NULL;
    int client_socket_fd;
    struct masyv_receive_ops_t msg_ops;
    int grid_width = 10, grid_height = 10;
    int total_time = 0;
    
    void receive_terminate_signal( void *data ){ exit( 0 ); }
    
    void do_time_advance( int steps, void *data )
    {
        int pos;
    
        masyv_send_start_step( client_socket_fd, total_time+steps, CLEAR_GRID );
        while( steps-- ) {
            total_time++;
            pos = masyv_random_a_b(0,grid_width*grid_height-1);
            masyv_send_agent( client_socket_fd, pos%grid_width, pos/grid_width, \
                               LAYER, 1, OPAQUE );
        }
        masyv_send_stop_sequence( client_socket_fd );
    }
    
    void configure( void *data )
    {
        int num_images[] = { NUM_IMAGES+1 };
        float grid_unit_cell[2][2] = SQUARE_UNIT_CELL( GRID_SPACING );
    
        masyv_send_pixtablespec( client_socket_fd, grid_unit_cell, NUM_LAYERS, \
                                  num_images );
        masyv_send_arena_size( client_socket_fd, grid_width, grid_height );
        masyv_send_texels( client_socket_fd, LAYER, 1, particle.width, \
                            particle.height, particle.pixel_data);
        masyv_send_stop_sequence( client_socket_fd );
    }
    
    int main( int argc, char *argv[] )
    {
        msg_ops = (struct masyv_receive_ops_t) {
            masyv_receive_req_config: configure,
            masyv_receive_req_time_advance: do_time_advance,
            masyv_receive_terminate_signal: receive_terminate_signal
        };
        int key;
        char tmp_msg[200];
    
        while( (key = getopt(argc, argv, "s:")) != EOF )
            switch(key) {
                case 's':
                    ui_socket_address = optarg;
                break;
                default:
                    exit(0);
                break;
            }
        if( ui_socket_address == NULL ) {
            sprintf( tmp_msg,"%s: Problem receiving socket address from server.\n",\
                      PROGRAM_NAME );
            perror( tmp_msg );
            exit(1);
        }
    
        client_socket_fd = masyv_create_client_socket_file( PROGRAM_NAME, \
                                                             ui_socket_address );
    
        while(1)
            masyv_receive_msg( client_socket_fd, &msg_ops, NULL );
    
        exit(0);
    }
    
    Figure: C code of the Hello World client simulation, ma_hello.c.

    First, let us look at the main function. Because it is the server, either masyv or logmasyv, which runs the client, client options have to be given to the server who passes them on to the client. The server will always pass to the client a -s option whose argument is the server's socket address, ui_socket_address. Each client is required to parse this command-line option so that it can connect to the server's socket using the libmasyv library function masyv_create_client_socket_file as shown in the ma_hello.c code above. In addition, the server can pass any number of arguments to the client. Those arguments have to be defined in the client's code and the client is responsible for parsing them. On the command-line, the client's arguments are separated from those of the server by a --. Let us illustrate this with an example. Say I have a client, ma_client, which takes the arguments -x and -y which are the grid's width and grid's height, respectively. The command would look like

    prompt> masyv -s ma_client -- -x 110 -y 70
    

    and the client's code to parse these arguments could look like

      while( (key = getopt(argc, argv, "s:x:w:")) != EOF )
          switch(key) {
             case 's':
                ui_socket_address = optarg;
             break;
             case 'x':
                grid_width = atoi(optarg);
             break;
             case 'y':
                grid_height = atoi(optarg);
             break;
             default:
                exit(0);
             break;
          }
    

    Note that if your client's code uses MASyV's old -c option, this is still ok but instead of typing

    prompt> masyv -s ma_client -c 110:70
    you would now type
    prompt> masyv -s ma_client -- -c 110:70


    After initialization, the client puts itself in a perpetual receiving mode with the command masyv_receive_msg. The msg_ops structure defines which client function will handle each of the server's request messages. The masyv_receive_req_config message is sent once by the server, as the first message, to requests the configuration information from the client. The configuration messages sent by the client as a response to the server's request consists in transmitting:

    1. the specification of the structure to store the client's images (masyv_pixtablespec);
    2. the dimensions of the grid (masyv_send_arena_size); and
    3. each image to be used by the client (with repeated calls to masyv_send_texels).
    Then, the client will send a masyv_send_stop_sequence message to the server to signal that all the configuration data has been sent.

    Then, the server will begin requesting steps. The client will send the current time step and tell the server whether to clear the grid from the previous step or not using masyv_send_start_step, it will send each agent by specifying which image to use and where on the grid it should appear using masyv_send_agent and/or can send one or more circles using masyv_send_circle, will send the statistics for that time step using masyv_send_stats, and will indicate to the server that all the data for this step has been sent with a call to masyv_send_stop_sequence.

    Finally, the server can terminate the client when it itself receives a terminate signal from the user, for example, by sending a terminate signal to the client. The client should know how to handle such a signal. In the above example, the ma_hello client's function receive_terminate_signal handled the terminate signal by a simple call to exit(0).





    Last modified: July 22, 2008, 13:47.