/**
* Name: Diffusion in a cuve (Cycle length)
* Author: Julien Mazars
* Description: This model is used to show how to use diffusion on a grid, and how to accelerate the process by computing several times the diffusion at each step. 
*     The cells at the center of the grid emit a pheromon at the cycle 0, which is spread through the grid thanks to the diffusion mechanism, using a particular matrix of diffusion. 
*     The "avoid_mask" facet is used in order to have a constant sum of pheromon. 
* Tags: diffusion, matrix, math, elevation
*/

model cycle_length

global {
	int size <- 64; // better to have a pow of 2 for the size of the grid
	int cycle_length <- 5;
  	geometry shape <- envelope(square(size));
  	list selected_cells;
  	list selected_quick_cells;
  	// Declare an uniform diffusion matrix
  	matrix mat_diff <- matrix([
									[1/9,1/9,1/9],
									[1/9,1/9,1/9],
									[1/9,1/9,1/9]]);
									
	int impulse_area_size <- 6;

	// Initialize the emiter cells as the cells at the center of the word
	init {
		selected_cells <- list(cells where (each.grid_x < location.x+impulse_area_size
			and each.grid_x > location.x-impulse_area_size
			and each.grid_y < location.y+impulse_area_size
			and each.grid_y > location.y-impulse_area_size
		));
		selected_quick_cells <- list(quick_cells where (each.grid_x < location.x+impulse_area_size
			and each.grid_x > location.x-impulse_area_size
			and each.grid_y < location.y+impulse_area_size
			and each.grid_y > location.y-impulse_area_size
		));
	}
	reflex init_value when:cycle=0 {
		ask(selected_cells){
			phero <- 1.0;
		}
		ask(selected_quick_cells){
			phero <- 1.0;
		}		
	}

	reflex diff {
		// Declare a diffusion on the grid "cells" and on "quick_cells". The diffusion declared on "quick_cells" will make 5 computations at each step to accelerate the process. 
		// The value of the diffusion will be store in the new variable "phero" of the cell.
		// In order to not loosing phero value, we apply a hand made mask (with the operator "where") and we turn the "avoid_mask" facet to true.
		list cells_where_diffuse <- cells where (each.grid_x < size-cycle_length and each.grid_x > cycle_length and each.grid_y < size-cycle_length and each.grid_y > cycle_length);
		diffuse var: phero on: cells_where_diffuse matrix: mat_diff avoid_mask: true method:dot_product;	
		list quick_cells_where_diffuse <- quick_cells where (each.grid_x < size-cycle_length and each.grid_x > cycle_length and each.grid_y < size-cycle_length and each.grid_y > cycle_length);
		diffuse var: phero on: quick_cells_where_diffuse matrix: mat_diff avoid_mask: true cycle_length: 10 method:dot_product;
	}
}


grid cells height: size width: size {
	// "phero" is the variable storing the value of the diffusion
	float phero  <- 0.0;
	// The color of the cell is linked to the value of "phero".
	rgb color <- (phero = 0) ? #black : hsb(phero,1.0,1.0) update: (phero = 0) ? #black : hsb(phero,1.0,1.0);
} 

grid quick_cells height: size width: size {
	// "phero" is the variable storing the value of the diffusion
	float phero  <- 0.0;
	// The color of the cell is linked to the value of "phero".
	rgb color <- (phero = 0) ? #black : hsb(phero,1.0,1.0) update: (phero = 0) ? #black : hsb(phero,1.0,1.0);
} 


experiment diffusion type: gui {
	output {
		layout #horizontal;
		display a type: opengl {
			// Display the grid with elevation
			grid cells elevation: phero*10 triangulation: true;
		}
		display quick type: opengl {
			// Display the grid with elevation
			grid quick_cells elevation: phero*10 triangulation: true;
		}
	}
}