UNPKG

cacatoo

Version:

Building, exploring, and sharing spatially structured models

234 lines (189 loc) 11.6 kB
<!-- 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>