cacatoo
Version:
Building, exploring, and sharing spatially structured models
234 lines (189 loc) • 11.6 kB
HTML
<!--
Cooperation example for students
DO NOT CHANGE THE FIRST 5 LINES OF CODE BELOW, THEY ARE NECESSARY FOR THE PAGE TO WORK
-->
<html>
<script src="../../dist/cacatoo.js"></script> <!-- Include cacatoo library (compiled with rollup) -->
<script src="../../lib/all.js"></script> <!-- Load other packages -->
<link rel="stylesheet" href="../../style/cacatoo.css"> <!-- Set style sheet -->
<!--
CODE FOR SIMULATION BEGINS HERE
-->
<script>
// First, we define a few 'variables', which we can use to ajust the model later
var sim; // This 'global' variable will hold the entire simulation
var base_fitness_1 = 0.0
var base_fitness_2 = 0.0
var helper_rate_type_1 = 1.0 // Determines how much help a 'cooperative' individual gives to its neighbours
var helper_rate_type_2 = 0.00 // Determines how much help a 'cheating' individual gives to its neighbours
var death = 0.05 // Determines how often an individual spontaneously dies, making a new spot available
var movement = 0.1 // Determines how much individuals 'move around'
/**
* function cacatoo() contains all the user-defined parts of a cacatoo-model. Configuration, update rules, what is displayed or plotted, etc. It's all here.
*/
function cacatoo() {
/*
1. SETUP. First, set up a configuration-object. Here we define how large the grid is, how long will it run, what colours will the critters be, etc.
*/
let config = { // Configuration of your model. How large is the grid, how long will it run, what colours will the critters be, etc.
title: "Simulating evolution ",
description: "",
maxtime: 1000000,
ncol: 200,
nrow: 100, // dimensions of the grid to build
seed: 61,
fpsmeter: true,
wrap: [false, false], // Wrap boundary [COLS, ROWS]
scale: 5, // scale of the grid (nxn pixels per grid point)
graph_interval: 5,
graph_update: 20,
statecolours: {'type':{'Cooperator':'gold','Cheater':'violet'}, 'alive': { 1: 'white' }}
}
/*
1. SETUP. (continued) Now, let's use that configuration-object to generate a new Cacatoo simulation
*/
sim = new Simulation(config) // Initialise a new Simulation instance with configuration given above
sim.makeGridmodel("coop") // Make a new gridmodel named cheater
sim.initialise = function()
{
sim.coop.clearGrid()
let init_individuals = [{type:"Cooperator", alive:1, fitness: base_fitness_1, base_fitness: base_fitness_1, helping_rate: helper_rate_type_1},
{type:"Cheater", alive:1, fitness: base_fitness_2, base_fitness: base_fitness_2, helping_rate: helper_rate_type_2}]
sim.populateSpot(sim.coop, init_individuals, [0.3,0.5], 100, config.ncol/2, config.nrow/2, {alive:0, fitness:0}) // cheaters and cooperators 50/50
sim.display()
sim.coop.resetPlots()
}
sim.coop.colourGradient('helping_rate', 100, [103, 64, 181], [59, 82, 139], [33, 144, 140], [93, 201, 99], [253, 231, 37])
/* sim.createDisplay_continuous({model:"coop", property:"fitness", fill:"viridis",
drawdots:true, max_radius: 5.0, stroke: false, strokeWidth: 0.2, strokeStyle: "white",
label:"Fitness", minval:0, maxval:base_fitness_1+helper_rate_type_1*8, decimals:1, num_colours: 100})
*/
sim.createDisplay_discrete({model:"coop", property:"type",
drawdots:true, max_radius: 2.5, min_radius: 1, radius:"fitness", stroke: false, strokeWidth: 1, strokeStyle: "black",
label:"Working together (colour = cooperation, size = growth rate)", minval:0, maxval:1, decimals:1, num_colours: 100})
// sim.coop.canvases["Cooperation"].legend.style.display = "none" // Hack to remove the legend :)
/**
* Define your next-state function here: for each grid point, what determines what that grid point will be like next timestep?
*/
sim.coop.nextState = function (x, y) // Define the next-state function. This example is two mutualists and a cheater
{
// let pA, pB, pC, psum
if (!this.grid[x][y].alive) // If there is no living cell here
{
let neighbours = this.getMoore8(this, x, y,'alive',1)
let winner = this.rouletteWheel(neighbours, 'fitness', 8.0)
if (winner != undefined)
{
this.grid[x][y].alive = winner.alive
this.grid[x][y].type = winner.type
this.grid[x][y].helping_rate = winner.helping_rate
this.grid[x][y].base_fitness = winner.base_fitness
}
}
if (this.rng.random() < death){ // Stochastic death (species become 0, which is an empty space for the next step to compete over)
this.grid[x][y].alive = 0
this.grid[x][y].type = 0
this.grid[x][y].fitness = 0
this.grid[x][y].helping_rate = 0
this.grid[x][y].base_fitness = 0
}
}
calculatefitness = function(x,y)
{
sim.coop.grid[x][y].fitness = sim.coop.grid[x][y].base_fitness + sim.coop.sumMoore8(sim.coop, x, y, "helping_rate")
/* if(x+y==0) console.log(sim.coop.grid[x][y].base_fitness) */
}
migration = function(x,y) {
if(sim.rng.random() < movement)
{
/* let me = sim.coop.grid[x][y] */
let direction = sim.rng.genrand_int(1,8)
let n = sim.coop.getNeighXY((sim.ncol+x+sim.coop.moore[direction][0])%sim.ncol,(sim.nrow+y+sim.coop.moore[direction][1])%sim.nrow)
/* console.log((x+sim.coop.moore[direction][0])%sim.ncol,y+(sim.coop.moore[direction][1])%sim.nrow)
console.log(n) */
/* let neigh = sim.coop.grid[n[0]][n[1]] */
let newme = sim.coop.copyGridpoint(x,y)
let newneigh = sim.coop.copyGridpoint(n[0],n[1])
sim.coop.grid[x][y] = newneigh
sim.coop.grid[n[0]][n[1]] = newme
}
}
/**
* Define your update-function here: stuff that is applied to the entire grid every timestep. E.g. apply the next-state, diffuse stuff, mix individuals, show graphs, etc.
*/
sim.coop.update = function () {
this.apply_sync(calculatefitness)
this.synchronous() // Update all grid points based on the next-state function (defined above)
if(movement>=1) for(let i=0; i<movement;i++) this.MargolusDiffusion() // Every so often mix individuals a bit
else this.apply_async(migration)
this.updateGraphs() // OPTIONAL: add some graphs (see function below)
}
/**
* OPTIONAL: add some graphs to show how your model progresses. Cacatoo currently supports three graph types, all of which are illustrated in this example
*/
sim.coop.updateGraphs = function () {
// Let's count some stuff every update
let sumhelping = sumalive = sumcheater = sumcoop = 0
for (let x = 0; x < this.nc; x++) // x are columns
for (let y = 0; y < this.nr; y++) // y are rows
{
if (this.grid[x][y].alive == 1) {
sumhelping += this.grid[x][y].helping_rate
sumalive ++
if(this.grid[x][y].type == "Cooperator") sumcoop++
if(this.grid[x][y].type == "Cheater") sumcheater++
}
}
// Update the plots. If the plot do not yet exist, a new plot will be automatically added by cacatoo
this.plotArray(["population size", "#cheaters", "#cooperators"], [sumalive,sumcheater,sumcoop], ["black","#5f3ba6","#3dab78"], "Population sizes")
}
sim.coop.bottleneck = function()
{
for (let x = 0; x < this.nc; x++) {
for (let y = 0; y < this.nr; y++) {
if(this.rng.genrand_real1() < 0.95){
this.grid[x][y].alive = 0
this.grid[x][y].type = 0
this.grid[x][y].fitness = 0
this.grid[x][y].helping_rate = 0
this.grid[x][y].base_fitness = 0
}
}
}
}
sim.addButton("Play", function () { sim.toggle_play() }) // Add a button that calls function "display" in "model"
sim.addButton("Step", function () { sim.step(); sim.display(); }) // Add a button that calls function "display" in "model"
sim.addButton("Well mix", function () { sim.toggle_mix() }) // Add a button that calls function "perfectMix" in "model.cheater"
sim.addButton("Catastrophe!", function () {sim.coop.bottleneck() })
sim.addButton("Restart", function () {sim.initialise();sim.coop.apply_sync(calculatefitness); sim.display() })
sim.addHTML("form_holder", "<br><br>")
sim.addSlider("movement", 0,5,0.1, "Movement rate")
sim.addSlider("death", 0.00, 1.00, 0.001, "Death rate")
sim.initialise()
sim.coop.updateGraphs()
/**
* OPTIONAL: add some buttons and sliders so you can play with your model easily
*/
sim.start()
/* sim.update() */
sim.coop.apply_sync(calculatefitness)
sim.display()
sim.pause = true
}
</script>
<!--
CODE FOR SIMULATION ENDS HERE, DO NOT CHANGE BEYOND THIS POINT
-->
<body onload="cacatoo()">
<div class="header" id="header">
<h2>Cacatoo </h2>
</div>
<div class="content">
</div>
<div class="content" id="canvas_holder"><br></div>
<div class="content" id="form_holder"></div>
<div class="content" id="graph_holder"></div>
<div class="footer" id="footer">
</div>
</body>
</html>