/**
* Name: Modavi
* Author: Arnaud Grignard
* Description: From a reference model with node of a given class, a spatial graph is created
* (or a barabasi graph if spatialGraph is set to false) in the advanced view to
* represent the interaction in the reference model.
* An abstract view/controller is created to summarize the interaction in the advanced view
* in a macro graph and control the reference model by defining an action (user_command)
* for each macroNode and macroEdge.
* Tags: 3d, graph, gui
*/
model modavi
global {
//Graph of the agents
graph my_graph ;
//Number of agents to create
int nbAgent parameter: 'Number of Agents' min: 1 <- 100 category: 'Model';
//Number of value per class
int nbValuePerClass parameter: 'Number of value per class' min: 1 max:100 <- 15 category: 'Model';
//Boolean to know if we display a spatial graph or not
bool spatialGraph parameter: 'Spatial Graph' <- true category: 'Model';
//Distance to link two node agents
float distance parameter: 'Distance' min: 1.0<- 10.0 category: 'Model';
//Threshold
int threshold parameter: 'Threshold' min: 0 <- 0 category: 'Model';
//Size of a node agent
int nodeSize parameter: 'Node size' min: 1 <- 1 category: 'Aspect';
//Size of a macro node agent
int macroNodeSize parameter: 'Macro Node size' min: 1 <- 2 category: 'Aspect';
//Number of type of class
int nbTypeOfClass <-1;
//Zoom factor
int zoomFactor <- nbTypeOfClass;
//List of the different interaction matrices
list> interactionMatrix <-list_with(nbTypeOfClass,matrix([0]));
//Number maximum of edges
int nbEdgeMax;
//Reflex to update the interaction matrix list
reflex updateInteractionMatrix{
//Ask for each edge agent to update it sources and destination to create the matrix
ask edge_agent{
loop i from:0 to: nbTypeOfClass-1{
src <- my_graph source_of(self);
dest <- my_graph target_of(self);
int tmp <- (interactionMatrix[i] at {(src.classVector[i]-1),(dest.classVector[i]-1)});
interactionMatrix[i][src.classVector[i]-1,dest.classVector[i]-1] <- (tmp+1);
}
}
}
//Reflex to compute te maximum number of edges
reflex computeNbEdgeMax{
//Number maximum of edges
nbEdgeMax <-1;
//Ask for each macro edge its aggregated link list number
ask macroEdge{
if(nbAggregatedLinkList[0] > nbEdgeMax){
nbEdgeMax <-nbAggregatedLinkList[0];
}
}
}
//Initialization of the model8
init {
//Initialization of the matrix
do InitInteractionMatrix;
//If we want a spatial graph in that case we create a graph according to their distance, else we create a barabasi albert graph
if(spatialGraph){
create node_agent number:nbAgent;
my_graph <- graph(as_distance_graph(node_agent, distance, edge_agent));
}
else{
my_graph <- graph(generate_barabasi_albert(nbAgent * 0.5,5,nbAgent,false,node_agent,edge_agent));
}
//For each node agent, we compute its class value
ask node_agent as list{
loop i from:0 to:nbTypeOfClass-1{
classVector[i] <- rnd(nbValuePerClass-1)+1;
}
}
int i<-1;
//Creation of the macronode according to the number of value per class
create macroNode number: nbValuePerClass{
class <-i;
location <- {(cos (((class-1)/nbValuePerClass)*360)*50 +50),(sin (((class-1)/nbValuePerClass)*360)*50+50),0};
color <- hsb (i/nbValuePerClass,1.0,1.0);
do updatemyNodes;
i<-i+1;
}
//We finally create the macroGraph
create macroGraph;
}
//Action to initialize the interaction Matrix according to the number of type of classes
action InitInteractionMatrix{
loop i from:0 to:nbTypeOfClass-1{
interactionMatrix[i] <- 0 as_matrix({nbValuePerClass,nbValuePerClass});
}
}
}
//Species to represent the node_agent
species node_agent {
//Color of the node agent
rgb color;
//List of the class
list classVector <- list_with (nbTypeOfClass,0);
//List of the position
list posVector <- list_with (nbTypeOfClass,{0,0});
//List of the color
list colorList <- list_with (nbTypeOfClass, rgb(0,0,0));
//Shuffle the classes of the node_agent
reflex shuffleClass{
loop i from:0 to: nbTypeOfClass-1{
classVector[i] <- rnd(nbValuePerClass-1)+1;
}
}
aspect real {
draw sphere(nodeSize) color: colorList[0];
}
aspect coloredByClass{
loop i from:0 to: nbTypeOfClass-1{
colorList[i]<- hsb (classVector[i]/nbValuePerClass,1.0,1.0);
posVector[i] <- {(location.x+i*110)*(1/zoomFactor),(location.y)*(1/zoomFactor),0};
draw sphere(nodeSize/zoomFactor) color: colorList[i] at: posVector[i] ;
}
}
}
//Species edge_agent to represent the edge of the graph
species edge_agent {
rgb color;
//Source of the edge
node_agent src;
//Target of the edge
node_agent dest;
aspect base {
draw shape color: rgb(125,125,125);
}
aspect edgeGenericSpatialized{
loop i from:0 to: nbTypeOfClass-1{
if ((src != nil) and (dest !=nil) ){
draw line( [ (src.posVector[i]) , (dest.posVector[i])] ) color:rgb(125,125,125);
}
}
}
}
//Species representing the macro node agents
species macroNode{
rgb color;
int class;
//List of all the aggregated nodes
list nbAggregatedNodes <- list_with(nbTypeOfClass,0);
//List of all the position
list posVector <-list_with(nbTypeOfClass,{0,0});
//Update the nodes of the agents
reflex update{
do updatemyNodes;
}
//For each classes, find all the nodes with the same classes
action updatemyNodes{
loop i from:0 to: nbTypeOfClass-1{
nbAggregatedNodes[i]<-0;
ask node_agent as list{
if (classVector[i] = myself.class) {
myself.nbAggregatedNodes[i] <- myself.nbAggregatedNodes[i]+1;
}
}
}
}
aspect sphere{
draw sphere((nbAggregatedNodes[0]/10)*macroNodeSize) color: color at: point([location.x,location.y]) ;
}
aspect Generic{
loop i from:0 to: nbTypeOfClass-1
{
posVector[i] <- {(location.x+i*150)*(1/zoomFactor),(location.y)*(1/zoomFactor),0};
draw sphere((nbAggregatedNodes[i]/10)*macroNodeSize*(1/zoomFactor)) color: color at: posVector[i] ;
}
}
//This action only works when having nbTypeOfClass=1
action removeMicroNode{
ask node_agent as list{
if (classVector[0] = myself.class) {
do die;
}
}
}
user_command "Remove all micro node" action: removeMicroNode;
}
//Species macroEdge representing the macro edges agents
species macroEdge {
rgb color <- #black;
//Source of the macroedge
macroNode src;
//Destination of the macroedge
macroNode dest;
//List of all the aggregated links
list nbAggregatedLinkList <- list_with(nbTypeOfClass,0);
aspect base {
loop i from:0 to: nbTypeOfClass-1{
if(nbAggregatedLinkList[i]>threshold){
draw (line([src.posVector[i],dest.posVector[i]]) buffer ((nbAggregatedLinkList[i])/((length(edge_agent)))*nbEdgeMax)) color: rgb(125,125,125) border:rgb(125,125,125);
}
}
}
//Action to remove a micro edge
action removeMicroEdge{
ask edge_agent as list{
if ((self.src.classVector[0] = myself.src.class) and (self.dest.classVector[0] = myself.dest.class)) {
do die;
}
}
}
user_command "Remove all micro edge" action: removeMicroEdge;
}
//Species macroGraph representing the macro graph composed of macroNode and macroEdge
species macroGraph {
//Reflex to update the graph by killing all the previous edges first
reflex updateAllMacroEdge {
ask macroEdge as list{
do die;
}
loop h from:0 to: nbTypeOfClass-1{
loop i from: 0 to: nbValuePerClass-1{
loop j from: 0 to: nbValuePerClass-1{
int tmp <- interactionMatrix[h] at {i,j};
if(i!=j){
create macroEdge{
nbAggregatedLinkList[h] <- tmp;
src <- macroNode[i];
dest <- macroNode[j];
}
}
}
}
}
}
//Reflex to initialize the matrix
reflex initMatrix{
loop i from:0 to:nbTypeOfClass-1{
interactionMatrix[i] <- 0 as_matrix({nbValuePerClass,nbValuePerClass});
}
}
}
experiment MODAVI type: gui {
output synchronized: true {
display MODAVI type:opengl axes:false {
camera #default location:{world.shape.width*1.5, world.shape.height,world.shape.width*4} target:{world.shape.width*1.5, world.shape.height,0};
graphics 'ReferenceModel'{
draw "Reference model" at:{200,50,0} size:5 color: #black perspective:false;
}
species node_agent aspect: real position:{100,0,0.01} ;
graphics 'View1'{
draw "Advanced view" at:{50,210,0} size:5 color: #black perspective:false;
}
species node_agent aspect: coloredByClass position: {0,100,0.02};
species edge_agent aspect: edgeGenericSpatialized position: {0,100,0.02};
graphics 'AbstractView'{
draw "Abstract view/controller" at:{250,210,0} size:5 color: #black perspective:false;
}
species macroNode aspect:Generic position: {200,100,0.01};
species macroEdge aspect:base position: {200,100,0.01};
}
}
}