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:
- Computational agents (default) → agents represent mobile software processes → ABC class
- 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.patches
procedure.
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:
- Internal embedded SQL data base mode with local file system access
- 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