User Manual


Introduction

The FLAME framework is an enabling tool to create agent-based models that can be run on high performance computers (HPCs). Models are created based upon a model of computation called extended finite state machines. By defining agent-based models in this way the FLAME framework can automatically generate simulation programs that can run models efficiently on HPCs. The user manual is split into 3 parts. Section 2 describes the way to specify the model design while Section 3 describes how to implement the model functionality. Section 4 finishes with how to run a model.

Model Description

Models descriptions are formatted in XML (Extensible Markup Language) tag structures to allow easy human and computer readability, and allow easier collaborations between developers writing applications that interact with model definitions.

The model XML document has a structure that is defined by a schema. The schema of the XML document is currently located at:

  http://flame.ac.uk/schema/xmml_v2.xsd

This provides a way to validate the model document to make sure all the tags are being used correctly. This can be achived by using xml command line tools like XMLStarlet and xmllint or by using editors that can have xml validation builtin like Eclipse. The start and end of a model file should be formatted as follows:

    <xmodel version="2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:noNamespaceSchemaLocation='http://flame.ac.uk/schema/xmml_v2.xsd'>
    <name>Model_name</name>
    <version>the version</version>
    <description>a description</description>
    <!-- more... -->
</xmodel>
  

Where name is the name of the model, version is the version, and description allows the description of the model. Models can also contain:

  • other models (enabled or disabled)
  • environment
    • constant variables
    • location of function files
    • time units
    • data types
  • agent types
    • name
    • description
    • memory
    • functions
  • message types
    • name
    • description
    • variables

Model in Multiple Files

It is possible to define a model in multiple files. FLAME reads a model from multiple files as if the model was defined in one file. This capability allows different parts of a model to be enabled or disabled easily. For example if a model includes different versions of a sub-model that can be exchanged, or a subsystem of a model can be disabled to see how it affects the model. Alternatively this capability could be used as a hierarchy, for example a `body' model could include a model of the `cardiovascular system' that includes a model of the `heart'. The following tags show the inclusion of two models, one enabled and one disabled:

    <models>
    <model><file>sub_model_1.xml</file><enabled>true</enabled></model>
    <model><file>sub_model_2.xml</file><enabled>false</enabled></model>
  </models>
  

The location of any sub model should be relative to the original model xmml file.

Environment

The environment of a model holds information that maybe required by a model but is not part of an agent or a message. This includes:

  • constant variables - for setting up different simulations easily
  • location of function files - the path to the implementations of agent functions
  • time units - for easily activating agent functions dependent on time periods
  • data types - user defined data types used by agent memory or message variables

This notion of environment does not correspond to an environment that would be a part of a model where agents would interact with the environment. Anything that can change in a model must be represented by an agent, therefore if a model includes a changeable environment that agents can interact with, this in itself must be represented by an agent.

Constant Variables

These are constant variables that can be set at the start of simulation runs initial starting values and cannot be altered thereafter. They can be defined as follows:

    <constants>
    <variable>
     <type>int</type>
     <name>my_constant</name>
     <description>value read in initial simulation settings</description>
    </variable>
  </constants>
  

Varible names cannot have spaces, instead please use lower case letters, numbers, underscores and hyphens. This also applies to agent memory names, message names, data type names and function names.

Function Files

Function files hold the source code for the implementation of the agent functions. The location is relative to the location of the model xmml file. They are included in the compilation script (Makefile) of the produced model:

    <functionFiles>
  <file>function_source_code_1.c</file>
  <file>function_source_code_2.c</file>
  </functionFiles>
  

Time Units

Time units are used to define time periods that agent functions act within. For example a model that uses a calendar based time system could take a day to be the smallest time step, i.e. one iteration. Other time units can then use this definition to define other time units, for example weeks, months, and years.

A time unit contains:

  • name - name of the time unit.
  • unit - can contain `iteration' or other defined time units.
  • period - the length of the time unit using the above units.

An example of a calendar based time unit set up can be defined as:

    <timeUnits>
  
    <timeUnit>
      <name>daily</name>
      <unit>iteration</unit>
      <period>1</period>
    </timeUnit>
    
    <timeUnit>
      <name>weekly</name>
      <unit>daily</unit>
      <period>5</period>
    </timeUnit>
    
    <timeUnit>
      <name>monthly</name>
      <unit>weekly</unit>
      <period>4</period>
    </timeUnit>
    
    <timeUnit>
      <name>quarterly</name>
      <unit>monthly</unit>
      <period>3</period>
    </timeUnit>
    
    <timeUnit>
      <name>yearly</name>
      <unit>monthly</unit>
      <period>12</period>
    </timeUnit>
    
  </timeUnits>
  


Data Types

Data types are user defined data types that can be used in a model. They are a structure for holding variables. Single variables can be:

  • C fundamental data types - int, float, double, char.
  • static array - of size ten: variable_name[10].
  • dynamic array - available by placing `_array' after the data type name: variable_name_array (please do not use if possible as useage affects load balancing on high performance computers).

For example:

    <variables>
    <variable>
      <type>int</type>
      <name>int_single</name>
      <description>A single integer</description>
    </variable>
    <variable>
      <type>int</type>
      <name>int_list[2]</name>
      <description>A list of 2 integers</description>
    </variable>
    <variable>
      <type>int_array</type>
      <name>int_dynamic_list</name>
      <description>A list of integers that can change size</description>
    </variable>
  </variables>
  

Data types can hold the above types of variables and also other defined data types. In the example below the data type line contains a variable of data type position which is defined above it:

    <dataTypes>

 <dataType>
  <name>position</name>
  <description>position in 3D using doubles</description>
  <variables>
   <variable><type>double</type><name>x</name>
    <description>position on x-axis</description>
   </variable>
   <variable><type>double</type><name>y</name>
    <description>position on y-axis</description>
   </variable>
   <variable><type>double</type><name>z</name>
    <description>position on z-axis</description>
   </variable>
  </variables>
 </dataType>

 <dataType>
  <name>line</name>
  <description>a line defined by two points</description>
  <variables>
   <variable><type>position</type><name>start</name>
    <description>start position of the line</description>
   </variable>
   <variable><type>position</type><name>end</name>
    <description>end position of the line</description>
   </variable>
  </variables>
 </dataType>

  </dataTypes>
  

Agents

An agent type contains a name, a description, memory, and functions:

    <agents>

  <xagent>
    <name>Agent_Name</name>
    <description></description>
    <memory>
     ...
    </memory>
    <functions>
      ...
    </functions>
  </xagent>
  
  </agents>
  

Agent Memory

Agent memory defines variables, where variables are defined by their type, C data types or user defined data types from the environment, a name, and a description:

    <memory>
    <variable>
      <type>int</type>
      <name>id</name>
      <description>identity number</description>
    </variable>
    <variable>
      <type>double</type>
      <name>x</name>
      <description>position in x-axis</description>
    </variable>
  </memory>
  

Note: Agent memory variable cannot be called 'name' as this is used to define the agent type in simulation input files.

Agent Functions

An agent function contains:

  • name - the function name which must correspond to an implemented function name and must be unique across the model
  • description
  • current state - the current state the agent has to be in.
  • next state - the next state the agent will transition to.
  • condition - a possible condition of the function transition.
  • inputs - the possible input messages.
  • outputs - the possible output messages.

And as tags:

    <function>
    <name>function_name</name>
    <description>function description</description>
    <currentState>current_state</currentState>
    <nextState>next_state</nextState>
    <condition>
    ...
    </condition>
    <inputs>
    ...
    </inputs>
    <outputs>
    ...
    </outputs>
  </function>
  

The current state and next state tags hold the names of states. This is the only place where states are defined. State names must coordinate with other functions states to produce a transitional graph from a single start state to end many possible end states.

A function can have a condition on its transition. This condition can include conditions on the agent memory and also on any time units defined in the environment. At any state with outgoing transitions with conditions it must be possible for a transition to happen, i.e. it must be possible for every agent to transition from the start state to an end state. Each possible transition must be mutually exclusive, i.e. the order that the function conditions are tested is not defined. A function named `idle' is available to be used for functions that do not require an implementation.

Conditions (that are not just time unit based) take the form:

  • lhs - left hand side of comparison
  • op - the comparison operator
  • rhs - the right hand side of the comparison

Or in tags:

    <lhs></lhs><op></op><rhs></rhs>
  

Sides to compare (lhs or rhs) can be either a value, denoted by value tags, a formula, currently also in value tags, or another comparison rule. Values and formula can include agent variables which are preceded by `a'.

The comparison operator can be one of the following comparison functions:

  • EQ - equal to
  • NEQ - not equal to
  • LEQ - less than or equal to
  • GEQ - greater than or equal to
  • LT - less then
  • GT - greater than
  • IN - an integer (in lhs) is a member of an array of integers (in rhs)

or can be one of the following logic operators as well:

  • AND
  • OR

The operator `NOT' can be used by placing `not' tags around a comparison rule. For example the following tagged rule describes the condition being true when the `z' variable of the agent is greater than zero and less than ten:

    <condition>
    <lhs>
      <lhs><value>a.z</value></lhs>
      <op>GT</op>
      <rhs><value>0.0</value></rhs>
    </lhs>
    <op>AND</op>
    <rhs>
      <not>
        <lhs><value>a.z</value></lhs>
        <op>LT</op>
        <rhs><value>10.0</value></rhs>
      </not>
    </rhs>
  </condition>
  

A condition can also depend on any time units described in the environment. For example the following condition is true when the agent variable `day_of_month_to_act' is equal to the number of iterations since of the start, the phase, of the `monthly' period, i.e. twenty iterations as defined in the time unit:

    <condition>
    <time>
      <period>monthly</period>
      <phase>a.day_of_month_to_act</phase>
    </time>
  </condition>
  

Time conditions can also be encased within a `not' tag in indicate the reverse condition.

Functions can have input and output message types. For example the following example the function takes message types `a' and `b' as inputs and outputs message type `c':

    <inputs>
    <input><messageName>a</messageName></input>
    <input><messageName>b</messageName></input>
  </inputs>
  <outputs>
    <output><messageName>c</messageName></output>
  </outputs>
  

Message filters can be applied to message inputs and allow the messages to be filtered. Filters are defined similar to function conditions but include message variables which are prefixed by an `m'. The following filter only allows messages where the agent variable `id' is equal to the message variable `worker_id':

    <input>
    <messageName>firing</messageName>
    <filter>
      <lhs><value>a.id</value></lhs>
      <op>EQ</op>
      <rhs><value>m.worker_id</value></rhs>
    </filter>
    <sort>
      <key>wage</key>
      <order>descend</order>
    </sort>
  </input>
  

The previous example also includes the use of a sort tag. The sort tag uses a key, a message variable, to sort the list in `ascend'ing or `descend'ing order via the order tag.

Other input filters available are called `box2d' and `box3d'. These filters only allow messages that are within a Cartesian box around the current agent. The variables `x' and `y' must be used in agent and message memory for `2d' and additionally `z' for using `3d'. The value given to this filter is the distance from the agent to the side of the box. For example a value of `1' gives a box of size `2'. The value can be a number or an agent memory variable using the `a.' notation. The limits of the box are inclusive which means messages with position on the edge of the box pass the filter.

    <input>
    <messageName>2d_location</messageName>
    <filter>
      <box2d>1.0</box2d>
    </filter>
  </input>
  <input>
    <messageName>3d_location</messageName>
    <filter>
      <box3d>a.apothem</box3d>
    </filter>
  </input>
  

Using filters in the model description enables FLAME to make message communication more efficient by pre-sorting messages and using other techniques. Messages can also be randomised using the random tag:

    <input>
    <messageName>firing</messageName>
    <random>true</random>
  </input>
  

Messages

Messages defined in a model must have a type which is defined by a name and the variables that are included in the message. Variables cannot include dynamic arrays. The following example is a message called `signal' that holds a position in 3D.

    <messages>
  
  <message>
    <name>signal</name>
    <description>Holds the position of the sending agent</description>
    <variables>
      <variable>
        <type>double</type>
        <name>x</name>
        <description>The x-axis position</description>
      </variable>
      <variable>
        <type>double</type>
        <name>y</name>
        <description>The y-axis position</description>
      </variable>
      <variable>
        <type>double</type>
        <name>z</name>
        <description>The z-axis position</description>
      </variable>
    </variables>
  </message>
  
  </messages>
  

Model Implementation

The implementations of each agent's functions are currently written in separate files written in C, suffixed with `.c'. Each file must include two header files, one for the overall framework and one for the particular agent that the functions are for. Functions for different agents cannot be contained in the same file. Thus, at the top of each file two headers are required:

  #include "header.h"
  #include "<agentname>_agent_header.h"

Where `<agent_name>' is replaced with the actual agent name. Agent functions can then be written in the following style:

  /*
   * \fn: int function_name()
   * \brief: A brief description of the function.
   */
  int function_name()
  {
     /* Function code here */
    
     return 0; /* Returning zero means the agent is not removed */
  }

The first commented part (four lines) is good practice and can be used to auto-generate source code documentation. The function name should coordinate with the agent function name and the function should return an integer. The functions have no parameters. Returning zero means the agent is not removed from the simulation, and returning the number one removes the agent immediately from the simulation. Agents of type `agentname' are added to a simulation by:

  add_agentname_agent(var1, .. varN);

New agents are only added at the start of the next iteration. This is because new agents start in their start state and are only picked up by the simulation engine when all other agents are also in their start states.


Accessing Agent Memory Variables

After including the specific agent header, the variables in the agent memory can be accessed by capitalising the variable name:

  AGENT_VARIABLE

To access elements of a static array use square brackets and the index number:

  MY_STATIC_ARRAY[index]

To access the elements and the size of dynamic array variables use `.size' and `.array[index]':

  MY_DYNAMIC_ARRAY.size
  MY_DYNAMIC_ARRAY.array[index]

To access variables of a model data type use `.variablename':

  MY_DATA_TYPE.variablename

Using Model Data Types

The following is an example of how to use a data type called vacancy:

  /* To allocate a local data type */
  vacancy vac;
  
  /* And initialise */
  init_vacancy(&vac);
  
  /* Initialise a static array of the data type */
  init_vacancy_static_array(&vac_static_array, array_size);
  
  /* Free a data type */
  free_vacancy(&vac);
  
  /* Free a static array of a data type */
  free_vacancy_static_array(&vac_static_array, array_size);
  
  /* Copy a data type */
  copy_vacancy(&vac_from, &vac_to);
  
  /* Copy a static array of a data type */
  copy_vacancy_static_array(&vac_static_array_from,
                            &vac_static_array_to, array_size);

If the data type is a variable from the agent memory, then the data type variable name must be capitalised.

Using Dynamic Arrays

Dynamic array variables are created by adding `_array' to the variable type. The following is an example of how to use a dynamic array:

  /* Allocate local dynamic array */
  vacancy_array vacancy_list;

  /* And initialise */
  init_vacancy_array(&vacancy_list);
  
  /* Reset a dynamic array */
  reset_vacancy_array(&vacancy_list);
  
  /* Free a dynamic array */
  free_vacancy_array(&vacancy_list);
  
  /* Add an element to the dynamic array */
  add_vacancy(&vacancy_list, var1, .. varN);
  
  /* Remove an element at index index */
  remove_vacancy(&vacancy_list, index);
  
  /* Copy the array */
  copy_vacancy_array(&from_list, &to_list);

If the dynamic array is a variable from the agent memory, then the dynamic array variable name must be capitalised.

Sending and receiving messages

Messages can be read using macros to loop through the incoming message list as per the template below, where `messagename' is replaced by the actual message name. Message variables can be accessed using an arrow `->':

  START_MESSAGENAME_MESSAGE_LOOP
    messagename_message->variablename
  FINISH_MESSAGENAME_MESSAGE_LOOP

Messages are sent or added to the message list by

  add_messagename_message(var1, .. varN);

Model Execution

FLAME contains a parser program called `xparser' that parses a model XMML definition into simulation program source code that can be compiled together with the agent functions implementation source code. The xparser includes template files which are used to generate the simulation program source code.

The xparser takes as parameters the location of the model file and an option for serial or parallel (MPI) version, serial being the default if the option is not specified. A production mode can also be switched on which removes any debugging features in the simulation program.

  xparser (Version 0.16.2)
  Usage: xparser [XMML file] [-s | -p] [-f]
          -s      Serial mode
          -p      Parallel mode
          -f      Final production mode

Generated Files

The xparser then generates simulation source code files in the same directory as the model file. These files include documentation of the model:

  • stategraph.dot - a directed acyclic graph of the states, functions and messages of agents in the model
  • stategraph_colour.dot - as above but functions are coloured
  • process_order_graph.dot - as above but the message syncronisation is shown
  • latex.dot - a latex document describing the model

The simulation program source code files:

  • Makefile - the compilation script used by the program `make'
  • xml.c - the source code file that handles inputs and outputs of the simulation
  • main.c - the source code file containing the main program loop
  • header.h - a C header file for global variables and function declarations between source code files
  • memory.c - the source code file that handles the memory requirements of the simulation
  • low_primes.h - holds data used for partitioning agents
  • messageboards.c - the source code that handles message functionality
  • partitioning.c - the source code that handles the partitioning of agents between nodes in parallel
  • timing.c - the source code that provides timing routines
  • Doxyfile - a configuration file for generating documentation using the program `doxygen'
  • rules.c - the source code file containing the generated rules for function conditions and message input filters

For each agent type an associated header file is created:

  • <agent_name>_agent_header.h - the header file containing macros for accessing agent memory variables

The simulation source code files then require compilation, which can be easily achieved using the included compilation script `Makefile' using the `make' build automation tool. The program `make' invokes the `gcc' C compiler, which are both free and available on various operating systems. If the parallel version of the simulation was specified the compiler invoked by `make' is `mpicc' which is a script usually available on parallel systems. To manually change the C compiler used the parameter `CC' can be set:

  make CC=gcc

To compile a model the message board library is required and the installation directory is needed by the compilation script. Currently the directory for `libmboard' is set in the same location of the model file. This can also be manually changed by using the parameter `LIBMBOARD_DIR':

  make LIBMBOARD_DIR=/location/of/libmboard

The compiled program is called `main'. The parameters required to run a simulation include the number of iterations to run for and the initial start states (memory) of the agents, currently a formatted XML file.

  FLAME Application: test_model_simple_everthing 
  Debug mode enabled 
  Usage: ./main <number of iterations> [<states_directory>]/<init_state>
<partitions> [-f # | -f #+#]
  -f    Output frequency, 1st # is frequency, 2nd # is the offset if required

The frequency of producing output files can also be set by the parameter `-f'.

Start States Files

The format of the initial start states XML is given by the following example:

    <states>
  <itno>0</itno>
  
  <environment>
  <my_constant>6</my_constant>
  </environment>
  
  <agents>
    <xagent>
      <name>agent_name</name>
      <var_name>0</var_name>
      ...
    </xagent>
    ...
  </agents>

  </states>
  

The root tag is called `states' and the `itno' tag holds the iteration number that these states refer to. If there are any environment constants these are placed within the `environment' tags. Any agents that exist are defined within `xagent' tags and require the name of the agent within `name' tags. Any agent memory variable (or environment constant) value is defined within tags with the name of the variable. Arrays and data types are defined within curly brackets with commas between each element.

When a simulation is running after every iteration, a states file is produced in the same directory and in the same format as the start states file with the values of each agent's memory.

For advanced usage one can use the `import' and `output' tags.

Import tags are used to include other locations of start state data. You have to provide the location (from where the current file is located), the format (currently only `xml' is avaliable) and the type (either `environment' data or `agent' data). Currently the import tags work to only one depth, they cannot be nested. The following import tags read in agent and environment data from the file at `0_depth_1.xml' and agent data from `../test7/0_depth_1_agent.xml':


    <imports>
    <import>
      <location>0_depth_1.xml</location>
      <format>xml</format>
      <type>agent</type>
    </import>
    <import>
      <location>../test7/0_depth_1_agent.xml</location>
      <format>xml</format>
      <type>agent</type>
    </import>
    <import>
      <location>0_depth_1.xml</location>
      <format>xml</format>
      <type>environment</type>
    </import>
  </imports>
  

Output tags are used to better define what output one wants to save from a simulation. Outputs can have two types, either `snapshot' (where the whole simulation state, environment and agents, is output) or `agent' where the agent name is specified and only that agent type is output. The format of the output can be specified (although only xml is provided currently) and the output location. Finally the timing can be specified. The `period' defines the number of iterations between producing output, for example a period of 10 means data is output every 10 iterations, so if we start with iteration number 0 the data will be output in iterations 10, 20, 30.... A phase can also be applied to the output timing. A phase of 2 when used with a period of 10 means data is output 2 iterations after it usually would, for example it would now be 2, 12, 22, 32.... The following example outputs a snapshot every 10 iterations and the agent `agent_type_a' every 10 iterations starting at the second iteration:


    <outputs>
    <output>
      <type>snapshot</type>
      <format>xml</format>
      <location></location>
      <time>
        <period>10</period>
        <phase>0</phase>    
        </time>
    </output>
    <output>
      <type>agent</type>
      <name>agent_type_a</name>
      <format>xml</format>
      <location></location>
      <time>
        <period>10</period>
        <phase>2</phase>    
      </time>
    </output>
  </outputs>