/***
* Name: Waterflowgridelevation
* Author: ben
* Description: 
* Tags: water, dem, grid
***/

/***
* Name: Water flow in a river represented by a set of cells, depending on the elevation
* Author: Benoit Gaudou
* Description: In this model, the space is discretised using a grid. Thus the river is a set of cells, each of them with an elevation.
* 	The data comes from a DEM (Digital Elevation Model) file.
* 	The upstream cells (i.e. the source cells) and the downstrem cells (i.e. the drain cells) are chosen by the modeler.
* 	At each step, the cells transmits a part of their water to their neighbor cells that are lower (their height is computed taken into account their elevation and height of water. 
* Tags: grid, gui, hydrology, water flow, DEM
***/

model Waterflowgridelevation

global {
	file dem_file <- file("../includes/DEM_100m_PP.asc");
	file river_file <- file("../includes/rivers_PP.shp");
  	 //Shape of the environment using the dem file
  	 geometry shape <- envelope(dem_file);
	
	//Diffusion rate
	float diffusion_rate <- 0.6;
	
	list drain_cells;
	list source_cells;
	
	float input_water;
	
	init {
		create river from: river_file;
		do init_cells;
		do init_water;
   	  	//Initialization of the drain cells
		drain_cells <- cell where (each.is_drain);
		source_cells <- cell where(each.is_source);
		ask cell {do update_color;}
	}	
	
   //Action to initialize the altitude value of the cell according to the dem file
   action init_cells {
      ask cell {
         altitude <- grid_value;
         neighbour_cells <- (self neighbors_at 1) ;
      }
   }	
   
   action init_water {
      ask cell where(each.altitude < 0) {
         water_height <- 3.0;
         is_source <- grid_y = 0;
         is_drain <- grid_y = matrix(cell).rows - 1;
      }
   }   

   //Reflex to add water among the water cells
   reflex adding_input_water {
   	  float water_input <- input_water;
      ask source_cells {
         water_height <- water_height + water_input;
      }
   }
   
   //Reflex to flow the water according to the altitute and the obstacle
   reflex flowing {
      ask cell {already <- false;}
      ask (cell sort_by ((each.altitude + each.water_height))) {
         do flow;
      }
   }
   
   //Reflex to update the color of the cell
   reflex update_cell_color {
      ask cell {
         do update_color;
      }
   }
   
   //Reflex for the drain cells to drain water
   reflex draining when: false{
      ask drain_cells {
         water_height <- 0.0;
      }
   }   
	
//	reflex d {
//		write "min  " + cell min_of(each.grid_value);
//		write "max  " + cell max_of(each.grid_value);		
//	}
}

   grid cell file: dem_file neighbors: 8 frequency: 0  use_regular_agents: false use_individual_shapes: false use_neighbors_cache: false {
	float altitude;
	float water_height;
	float height;
	list neighbour_cells;
	bool is_drain;
	bool is_source;
	bool already;

     //Action to flow the water 
      action flow {
      	//if the height of the water is higher than 0 then, it can flow among the neighbour cells
         if (water_height > 0) {
         	//We get all the cells already done
            list neighbour_cells_al <- neighbour_cells where (each.already);
            //If there are cells already done then we continue
            if (!empty(neighbour_cells_al)) {
               //We compute the height of the neighbours cells according to their altitude, water_height and obstacle_height
               ask neighbour_cells_al {height <- altitude + water_height ;}
               //The height of the cell is equals to its altitude and water height
               height <-  altitude +  water_height;
               //The water of the cells will flow to the neighbour cells which have a height less than the height of the actual cell
               list flow_cells <- (neighbour_cells_al where (height > each.height)) ;
               //If there are cells, we compute the water flowing
               if (!empty(flow_cells)) {
                  loop flow_cell over: shuffle(flow_cells) sort_by (each.height){
                     float water_flowing <- max([0.0, min([(height - flow_cell.height), water_height * diffusion_rate])]); 
                     water_height <- water_height - water_flowing;
                     flow_cell.water_height <-flow_cell.water_height +  water_flowing;
                     height <- altitude + water_height;
                  }   
               }
            }
         }
         already <- true;
      }  
      //Update the color of the cell
      action update_color { 
         int val_water <- 0;
         val_water <- max([0, min([255, int(255 * (1 - (water_height / 12.0)))])]) ;  
         color <- rgb([val_water, val_water, 255]);
         grid_value <- water_height + altitude;
      }
}

species river {
	aspect default {
		draw shape color: #red;
	}
}

experiment hydro type: gui {
	parameter "input water" var: input_water <- 1.0;
	output {
		display d {
			grid cell border: #black;
			species river;
		}
	}
}