Simulation Environment for JAM

Introduction

A simulation world consists of agent processing nodes (logical/virtual JAM nodes) and some communication links between nodes enabling migration of agents and propagation of signals between nodes. Nodes are placed in a two-dimensional spatial simulation world, and each node has a distinct position.

There are computational and physical agents. The latter represent physical entities like, e.g., humans, ants, cars. The default agent type is computational and agents represent mobile software.

A meshgrid network arranges nodes in a two-dimensional grid (that can be irregular and incomplete).

A patchgrid network is similar to NetLogo simulation worlds. A patch grid arranges nodes in a two-dimensional grid, too, but with an implicit global virtual communication link that enables migration of phyiscal agents between any of the nodes in the grid. Migration of computational agents (default) and propagation of message signals still require explicit links between nodes.

Communication ports and links have either (static or dynamic) point-to-point or broad/multicast characteristics, i.e., nodes within a specific spatial range can communicate with each other (computational agents).

Nodes (except in mesh- and patch grid worlds) can be moved within the two-dimensional world carrying their agents.

Architecture

Model

The simulation model is defined by a JS object structure containing the following sections:

model

type model = {
    name? : string,
    classes : model.classes,
    agents : model.classes,  // synonym for classes entry
    resources? : model.resource,
    patches? : model.resource,
    parameter? : model.parameter,
    world : model.world,
    physics? : physics,
}

The simulation model is a structure object consisting basically of agent and world descriptor attributes defining agent behaviour and visual properties, and the composition of the simulation world consisting of logical JAM nodes.

model.name

type model.name = string

The name of the simulation (model).

model.classes

model.agents

type model.classes = model.agents = {
    $ac: {
      behaviour: agent constructor function | open(file),
      visual : visual,
      type? : 'computational'|'phyiscal'|'behavioural'
      on?: { $event : visual },
    }
}

Definition of agent classes (behaviour, constructor function) and visual properties used in the simulation. The agent class can be loaded from a file (by using the open function, which is not supported in browsers). The event handlers defined in the on section can be used to be display visuals on signal delivery to an agent (the visual should define a display timeout).

An optional type attribute can classify the agent in two different super classes:

  1. Computational agents (default) → agents represent mobile software processes → ABC class
  2. Physical (or behavioural) agents → agents represent physical entities (like humans, although, being virtual in the simulation) → ABM class

model.resources

Passive agents with a visual shape and an optional set of parameters.

type model.resources = {
    $rc : {
           visual : visual,
           parameter : {}
    }
}

model.patches

type model.patches = {
   $pc : {
           visual : visual,
           parameter : {}
    }
}

Set of patch classes (node visuals). Patch parameter can be accessed by agents via the tuple space (node installs tuple provider and consumer functions) or by the ask.patchesprocedure.

model.parameter

type model.parameter = { $param : number|string|array|{}}

Definition of a set of simulation parameters that can be changed by run-time configuration.

model.world

type model.world = {
    init? : {
        agents? : { 
          $ac : function (nodeid:string,position) -> 
                {level:number,args:[]|{}|null}  
        },
        nodes? : function (node),
        resources? : function (resource),
        patches? : function (resource),
        world? : {},
        physics? : function (physics),
    },
    start?: function (env),
    stop? : function (env),
    data? : {},
    map? : function () -> simobj [],
    nodes? : { $nc: function () -> simobj },
    resources? : { $rc: function () -> simobj },
    meshgrid? : meshgrid,
    patchgrid? : patchgrid,
}

Definition of the simulation world.

The initialisation section provides functions that create agents on specific nodes (returning the individual parameter set of an agent), initialises nodes, resources, patches, and an optional additional physical MBP world.

The model.world.nodes and model.world.resources entries specify simulation object constructor functions returning a simulation object descriptor. The constructor functions can alternatively defined in the model.nodes and model.resources sections, respectively.

The map entry defines a function that returns a set of simulation objects at the beginning of the simulation (creation of the simulation world).

type agent

function $name ($p1,$p2,..) {
    this.$v=init;
    ..
    this.act = {
      $activity: function (){..}
    }
    this.trans = {
      $activity: string|identifier|function () -> string,
    }
    this.on = {
      $handler: function () {},
      $signal:  function () {},
      ..
    }
    this.next = $activity;
}

Definition of the agent behaviour (based on the ATG model) with an agent object constructor function.

type node

type visual

type visual = {
    shape : 'circle'|'rect'|'triangle'|'icon',
    icon? : string,
    label? : { text : string, fontSize : number },
    width : number,
    height : number,
    fill? : {
      color : string,
      opacity : number [0..1]
    },
    line? : {
      width? : number,
      color? : string,
    },
    x? : number is relative position in parent frame,
    y? : number is relative position in parent frame,
    time? : number is a timeout for a visual,
}

This is the visual definition type of an agent, node, or resource (link)..

type simobj

type simobj = {
    id: string,
    x: number,
    y: number,
    ports? : { $id : comtype },
    gps? : {latitude,longitude,height},
    visual : visual
}

Simulation object descriptor (position and visual geometry) with optional communication ports.

type comobj

type comobj = {
    type : 'multicast'|'physical'|'unicast',
    status : function (nodes:string []) -> boolean|string [],
    ip? : string,          // type='physical',
    to? : string,          // ..
    proto? : 'udp'|'http', // ..
    visual : visual,
}

Communication port object descriptor.

type meshgrid

type meshgrid = {
      rows : number,  // y-axis
      cols : number,  // x-axis
      levels? : number,  // z.axis
      // Positions of z-levels on 2d plane
      matrix? :[[z1_x,z1_y],[z2_x,z2_y], [z3_x,z3_y]],
      node : {
        // Node ressource visual object
        visual : visual,
        // Node filter creating irregular meshgrids
        filter? : function (pos:number []) -> boolean
      },
      // Link port connectors
      port? : {    // Link port connectors
        type : 'unicast',
        place : function (node) -> {x:number,y:number,id:DIR} [],
        visual : visual
      },
      // Connections between nodes (with virtual port conectors)
      link? : {
        type : 'unicast',
        connect? : function (node1,node2,port1,port2) -> boolean,
        visual : visual
      },
      // Create some custom nodes dynamically with a constructor functon
      // defined below
      map? : function () -> [],
      // Some custom node constructor functions
      nodes : {
        $nodeclass : function (x:number,y:number) -> simobj         
      }
}

Defines a one, two, or three-dimensional meshgrid network of nodes connecting neighbouring nodes.

type patchgrid

This is a classical simulation world derived from the NetLogo simulation world model used for simulating social and technical systems. In a patch grid the world is divided into patches.

If the floating parameter is not set or false, each patch is related to a logical JAM node. Physical agents can occupy a patch via the logical JAM node. They can migrate from one patch to any other patch by a number of steps and a movement angle (delta vector) immediately. A node is connected to all other nodes in the grid by a virtual link. Each node provides connectivity for physical and computational agents which differ. Computational agents cannot migrate to any node in one step. They have to use other virtual links providing connectivity to some (neighbouring) nodes, e.g., simulating a short range mobile link.

If the floating parameter is true, only a visual grid with patch resources is displayed. In this case, a physical agent in the simulation is a mobile tuple <logical node,behavioural agent>.

type patchgrid = {
    rows : number,
    columns : number,
    width : number, // geometrical width and height of patch in pixels
    height : number,
    visual? : visual, // default visual for a patch field, can be changed
    floating? : boolean 
}

type physics

type physics  = {
  scenes:{
    plate:function plate(world,settings)-> mbp | open(file)
  }
}
type mbp = {
    masses : mass [],
    loadinggs : [],
    map : function (number []) -> mass,
    read: function (parameter) -> string,
    write: function (parameter,value)
}

Includes a physical model definition (MBP).

type resource

type resource = {
    parameter: {},
    visual : visual
}

API

The simulator provides some additional and extended AIOS APIs for agents.

Extension: net

Simulation functions for physical (behavioural) agents derived from NetLogo simulation model.

net.ask

function (what:string,who:string|string []|number|number [],callback?,remote?) -> *[]

The ask function (derived from NetLogo simulation model) can be used to apply a function to a set of simulation objects, i.e., agents (physical only), patches, resources, nodes. The simulation object passed to the callback function depends on the type selection (what) and can be modified by the callback function.

Note that the objects are not protected like agents executed in their own context and the callback function can invalidate the object, e.g., an (other) agent or a logical JAM node. If the simulation objects asked for agents and the remote flag is set, the callback function is executed in this agent context asynchronously, otherwise in the context of the caller agent synchronously. In this case, a second argument is providing the node object for the agent. The function returns the requested set of simulation objects.

The type of simulation object is selected by the what argument: agent(s),agent(s)-<class>, node(s), node(s)-<class>, patch(es), resource(s), resource(s)-<class>.

The who argument specifies the objects to be selected. Agents of a specific class can be selected either by the what or who argument. A specific agent can be found by a string who argument setting the agent identifier (or regular expression, alternatively). A specific world position (of a patch, node, or resource) is given by an array [x,y]. Agents, nodes, patches, and resources can be collected within a radius around the current agent (node) position by a number.

net.create

function (what:string,num:number,callback?) -> string []

Creates a number of simulation objects, i.e., agents, nodes, resources (derived from NetLogo simulation model). The optional callback function can be used to initialise the object. In the case of agents, the callback handler is executed in the agent context asynchronously and can be used to position (physical agent) in the world or to transfer an agent to a destination node.

The type of simulation object is selected by the what argument: agent(s),agent(s)-<class>, node(s), node(s)-<class>, resource(s), resource(s)-<class>.

net.set

function (p:string,v:*)

Sets a physical agent variable. Valid simulation object parameters are currently color and shape.

net.setxy

function (x:number,y:number)

Moves object to new position (x,y).

Extension: simu

Generic simulator interface.

simu.changeVisual

function (id:string,visual)

Changes the visual property of a simulation object.

simu.clear

function (msg:boolean,log:boolean)

Clears the system and (agent) message windows.

simu.createNode

function (nodeclass:string|function,arg1,arg2,...) -> nodeid

Creates a new simulation node (logical JAM node). The first argument either specifies the name of a simulation node constructor function defined in the model.world.nodes section of the simulation model.or a function returning an object of type simobj.

simu.createOn

fucntion (nodeid:string,ac:string,args:{}|[],level:number) -> agentid

Create a new agent of specified class on given node. The agent constructor function must be already compiled (from the simulation model section classes)

simu.createResource

function (id:string, resclass:string, visual, paramaeters?:{}) -> resid

Creates a new resource. A resource is a passive agent with an optional set of parameter variables.

simu.deleteResource

function (id:string)

Deletes and removes a resource from the simulation world.

simu.deleteNode

function (nodeid:string)

Deletes a simulation node (logical JAM node).

simu.event.add

function ()

simu.event.get

function () -> []

simu.getStats

function (target:'node'|undefined,arg:string)-> {}

simu.getSteps

function () -> number

simu.inspect

function (object|array|*,..) -> string

simu.message

function (string)

Print a pop-up message.

simu.model

function () -> model

Returns the simulation model descriptor object.

simu.move

function (id:string,dx,dy,and,andmore)

Relative movement of a simulation object in the 2D simulation world.

simu.moveTo

function (id:string,x,y,and,andmore)

Absolute movement of a simulation object in the 2D simulation world.

simu.network

{x:number,y:number,z:number}

simu.options

{..}

simu.parameter

function (parameter:string) -> *|model.parameter

Returns simulation model parameter (model.parameter, if defined). If argument is undefined the entire model parameter object is returned, otherwise a specific parameter.

simu.print

function (object|array|*)

Pretty printer for objects and arrays. Used for inspection only.

simu.sprint

function (object|array|*) -> string

Pretty printer for objects and arrays. Used for inspection only. Returns string.

simu.start

function (steps:number|undefined)

Start the simulation.

simu.stat

function (p,v)

simu.stop

function () -> number

Stop the simulation and returns the number of simulated steps.

simu.time

function () .> number

Get the current simulation world time (includes lag correction and is not the host system time)

simu.untis

??

Simulation world units

simu.Vec3

function (x,y,z) -> CANNON.vec3

Returns a vector for physical simulation (CANNON MBP).

Database

There are two data base modes supported:

  1. Internal embedded SQL data base mode with local file system access
  2. External SQL data base (already running) that is accessed via a proprietary communication protocol and socket/http communication.

The first mode supports synchronous operations, whereas the second mode only supports asynchronous operations using a callback function. The first mode returns SQL request-response objects:

type sqlresponse = {
    code:number,
    ok:boolean|undefined,
    statement:string,
    result: []|{}|*|undefined
}

simu.db.init

function (path:string,channel:number|undefined,callback?) -> status

Opens or creates a new SQL data base. Two modes are supported: (1) Embedded SQL and local file system mode (channel argument must be undefined) or (2) External SQL data base that is accessed via a proprietary communication protocol and socket/http communication.

simu.db.createMatrix

function (path:string,matname:string,header:[],callback?) -> status

Creates a new matrix in the data base referenced by the path argument. The header argument specifies the type interface of a row, i.e., ['$name:$type'] or [$type]. $type is either an SQL integer or varchar(n) type.

simu.db.createTable

function (path:string,matname:string,header:{},callback?) -> status

Creates a new table in the data base referenced by the path argument. The header argument specifies the type interface of a row, i.e., { $name:$type }. $type is either an SQL integer or varchar(n) type.

simu.db.drop

function (path:string,table:string,callback?) -> status

Deletes a table (or matrix) in the data base referenced by the path argument.

simu.db.exec

function (path:string,cmd:string,callback?) -> status

Executes a SQL statement on the data base referenced by the path argument.

simu.db.get

function (path,callback?) -> status

??

simu.db.insert

function (path,table:string,row,callback?) -> status

Inserts a row in the given table and data base.

simu.db.insertMatrix

function (path,matrix:string,row,callback?) -> status

Inserts a matrix ??

simu.db.readMatrix

function (path,matrix:string,callback) -> status

Reads an entire matrix.

simu.db.select

function (path,table:string, vars:[], cond:string, callback?) -> status

Data base select operation

db.writeMatrix

function (path:string,matrixname:string,matrix:[][],callback?) -> status

Writes an entire matrix to the given data base.

CSV

simu.csv.read

function (file:string, callback, verbose?) -> status

Asynchronous reads and parses a CSV file and passes the content as a matrix to the callback function

simu.csv.write

function (file:string,header:string [],data:[][],callback:function,verbose?) -> status

Writes a matrix to a file in CSV format.

Physics

simu.phy.get

function (id:string) -> *

Returns a physical simulation object

simu.phy.refresh

function ()

Refreshs the physical simulation

simu.phy.step

fucntion (n:number,callback)

Performs (n) physical and computational simulation step(s)

simu.phy.stepPhyOnly

function (n:number,callback)

Performs (n) physical simulation step(s)

Networking

A world consists of a set of logical (virtual) JAM nodes can communicate via virtual channels with each other. Selected logical nodes can be connected to the outside world via physical IP links.

Comparison of NetLogo and SEJAM Simulations

The well known and established NetLogo simulator is (commonly) used for the ABM domain only. In contrast, the SEJAM simulator is primarily used for the ABC domain, although any physical simulation can be transformed in a computational task implementing the behaviour of a physical entity. The fusion of real worlds deploying computational agents (that interact with machines and humans) with virtual simulation models requires a mapping methodology to be able to simulate physical agents (i.e., artifacts of real entities) using computational agents.

Computational agents as mobile software processes require a connected communication network of host platforms (computers) to migrate along a path AB. A human being, in contrast, do not require such a digital transport network. In a simulation world, a physical (pure behavioural) agent can overcome arbitrary distances in one step (in principle).

To combine social interaction and computational simulation models, the SEJAM simulation model was extended by two super classes of agents: (1) Computational (2) Behavioural/Physical agents. A behavioural agent consists of a <mobile node, physical agent> tuple. The behavioural agent is bound to this node and can change its position only by moving the node carrying the agent. In contrast, computational agents are mobile and can hop from one platform to another if there is a communication link between both platforms by performing process serialisation and deserialisation. The link can be virtual (inside the simulation world) or physical connecting a logical node of the simulation world with another JAM platform in the real world (e.g., a smartphone) via the Internet.

The mapping of NetLogo model constructs and statements on the SEJAM simulation model is shown in the following table. There are two approaches implementing the NetLogo patch grid world in the SEJAM simulation world: (1) Floating grid with mobile nodes carrying immobile agents representing turtles (active agents) and resources representing patches (2) Static grid with immobile nodes and mobile agents (turtles) representing patches. Only the first approach is considered (although both can be implemented with SEJAM). In NetLogo, the agent behaviour is entirely controlled and executed by a global observer (centralised macro control), whereas in SEJAM the agent behaviour is controlled and executed by each individual agent (decentralised micro control).

.

NetLogo SEJAM
Entity Turtle Active agent: mobile logical JAM node linked with physical behavioural JAM agent, Passive agent: Resource
Entity Patch Resource
Entity World JAM world consisting of one physical JAM node and multiple mobile logical JAM nodes (on patch positions), patch grid
Observer World agent on dedicated JAM world node controlling simulation
turtles-own [x,y] Agent body variables this.x, this.y
patches-own Patch resource parameter set
forward n, rotate dang Moving of physical agent with its node inside the simulation world
ask turtles net.ask('agents',..) simulation interface for physical agents
ask patches net.ask('patches',..) simulation interface for physical agents
globals Global model parameter, JAM world agent and world node

Comparison of NetLogo simulation model with SEJAM model using floating patch grid approach

to setup
  ask patch x y [
    sprout 1 [
      set color brown
      set shape "circle"
      set size 10
      stamp
    ]
  ]
function world () {
    this.act = {
        init: function () {
            net.ask ('patch', [x, y], function (patch) {
                net.set({
                    color: 'brown',
                    shape: 'circle',
                    width: 10,
                    height: 10
                })
            })
        }
    }
}

Modification of patches in NetLogo and SEJAM with NetLogo compatibility layer

// 0. NetLogo 
bread [agents agent]
ask [                    ask id []  ask id-here []
    set data 0
    set more 0
    rotate a
    forward n
]
// 1. Observer control 
function world () {
  simu.bread(['agent'])
  this.act = {
    function act1 () {
      net.ask('agents',id|{}|number|number[]|null,function (ag) {
        this.data = 0  // Executed in ag Ctx
        this.more = 0
        net.rotate(a)
        net.forward(n)
      },true)
   }
}
// 2. Agent control
function agent() {
  this.act = {
    function actx () {
        this.data = 0
        this.more = 0
        net.rotate(a)
        net.forward(n)          
    }      
  }
}

Relation of NetLogo turtle modification and AgentJS behaviour. Either the agent itself modifies its visual, position, and body data, or the world agent modifies a set of agents via the simulation interface.

model = {
    agents : {
      $name : {
        behaviour : function ac () {},
        visual : visual,
        type : 'physical'|'behavioural'|'computational'
      }
    },
    resources : {
       $name : {
           visual : visual,
           parameter : {}
       }
    },
    nodes : {
       $name : {
         visual : visual,
         parameter ; {}
       } 
    }
    world : {
        patchgrid : {
            rows: number,
            columns: number,
            ..,
            visual? : visual,
        }  
    }
}

The entire simulation model structure (visual parameters define the visual shape of simulation objects)

Release Information

Author: Stefan Bosse
Revision: 17.5.2019