UNPKG

cacatoo

Version:

Building, exploring, and sharing spatially structured models

182 lines (144 loc) 8.77 kB
<!-- EXAMPLE FILE: Serial transfer protocol --> <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 --> <script> /*-----------------------Start user-defined code ---------------------*/ let sim; function cacatoo() { let config = { title: "Serial transfer protocol", description: "The long-term evolution experiment. Without evolution... :D", maxtime: 100000, ncol: 50, nrow: 100, // dimensions of the grid to build skip: 0, // Skip 5 steps before redrawing the grid again wrap: [true, true], // Wrap boundary [COLS, ROWS] scale: 4, // scale of the grid (nxn pixels per grid cell) statecolours: { 'alive': { 1: 'blue' } }, // The background state '0' is never drawn skipbg_state: true, // Don't draw 0-state on grid (faster) graph_interval: 1, graph_update: 5, show_gridname: true, } sim = new Simulation(config) let influx = 0.0 // Continuous influx of resource into external environment let uptake = 0.6 // Rate with which resources are taken up by cells let upkeep = 0.02 // Upkeep used to keep the cell alive let refresh_medium_every = 1440 // Interval for refreshing the medium ("minutes", 24h) let refresh_medium_conc = 0.1 // Conc for refreshing the medium sim.makeGridmodel("batchculture"); // sim.batchculture.colourViridis("external_resources", 100) //sim.batchculture.colourViridis("internal_resources", 100) sim.createDisplay_continuous({model:"batchculture", property:"internal_resources", label:"Internal resources", minval:0, maxval:100, num_colours:40, fill: 'viridis',drawdots:true,radius:3}) sim.createDisplay_continuous({model:"batchculture", property:"external_resources", label:"External resources", minval:0, maxval:100, num_colours:40, fill: 'viridis'}) // sim.resource_e.colourRamp('resources_e',[0,0,0],[64, 224, 208],100) // Define ODEs with basic resource dynamics let resource_dynamics = function (i, u, k) { return function (x, y) { return [ i - u * y[0], // y[0] is the external resource concentration u * y[0] - k * y[1] // y[1] is the internal resource concentration ] } } // Configuration object with initial states, parameters, and diffusion rates let ode_config = { ode_name: "resources", init_states: [refresh_medium_conc, 0], // y[0] and y[1] parameters: [0.0, 0.0, 0.0], // i,u,k diffusion_rates: [0.2, 0.0] } // resources diffuse through exteral environment, but internal resources stay put // Attaches an ODE to all gridpoints with initial state = [0,0]. // If you want to access it by name, you can give a name as the final variable (here resources) sim.batchculture.attachODE(resource_dynamics, ode_config); // Add a single cell to the middle of the grid for (let x = 0; x < sim.batchculture.nc; x++) { sim.batchculture.grid[x][sim.batchculture.nr / 2]['alive'] = 1 sim.batchculture.grid[x][sim.batchculture.nr / 2].resources.pars = [influx, uptake, upkeep] sim.batchculture.grid[x][sim.batchculture.nr / 2].resources.state = [refresh_medium_conc, sim.rng.genrand_real1() * 0.3] } sim.batchculture.nextState = function (x, y) // Define the next-state function. This example is stochastic growth in a petri dish { if (this.grid[x][y].alive == 1) { if (this.grid[x][y].resources.state[1] < 0.01) { this.grid[x][y].alive = 0 this.grid[x][y].resources.state[0] += this.grid[x][y].resources.state[1] // Spill internal resources in external pool this.grid[x][y].resources.state[1] = 0.00 // Remove internal conc this.grid[x][y].resources.pars = [influx, 0.00, upkeep] // No more cell here, so no uptake } } else { let neighbour = this.randomMoore8(this, x, y) let food_in_neigh = neighbour.resources.state[1] if (neighbour.alive == 1 && food_in_neigh > 0.5) { this.grid[x][y].alive = 1; this.grid[x][y].resources.state[1] = food_in_neigh / 2 neighbour.resources.state[1] = food_in_neigh / 2 this.grid[x][y].resources.pars = [influx, uptake, upkeep] // Living cells get an influx par } } this.grid[x][y].resources.solveTimestep(0.1) // Update how this GP is displayed let conc_e = Math.max(0, this.grid[x][y].resources.state[0]) // Amount of prey (continuous variable) let conc_i = Math.max(0, this.grid[x][y].resources.state[1]) // Amount of pred (continuous variable) this.grid[x][y].external_resources = Math.min(Math.floor(conc_e * 500), 99) this.grid[x][y].internal_resources = Math.min(Math.floor(conc_i * 200), 99) } sim.batchculture.transfer = function () // custom defined function for serial passage { for (let x = 0; x < this.nc; x++) // x are columns for (let y = 0; y < this.nr; y++) // y are rows { if (this.time > 0 && this.time % refresh_medium_every == 0) { this.grid[x][y].resources.state[0] = refresh_medium_conc if (sim.rng.genrand_real1() < 0.95) { this.grid[x][y].alive = 0 this.grid[x][y].resources.state[1] = 0.00 // Remove internal conc this.grid[x][y].resources.pars = [influx, 0.00, upkeep] // No more cell here, so no uptake } } } this.perfectMix() } sim.batchculture.update = function () { this.diffuseODEstates() // Only diffuse state 0 (first state) of the ODE named "resources" this.asynchronous() // Asynchronous because division changes both parent and offspring grid points, so updating can't be synchronous without leading to bugs this.MargolusDiffusion() if (this.time % refresh_medium_every == 0) this.transfer() let sum_ext = 0 let sum_int = 0 for (let x = 0; x < this.nc; x++) // x are columns for (let y = 0; y < this.nr; y++) // y are rows { sum_ext += this.grid[x][y].resources.state[0] sum_int += this.grid[x][y].resources.state[1] } sum_ext /= this.nc * this.nr sum_int /= this.nc * this.nr this.plotPopsizes('alive', [1]) this.plotArray(["Resources [external]", "Resources [internal]"], [sum_ext, sum_int], ["turquoise", "gold"], "Average external / internal resources") } sim.addPauseButton() // Add a button that calls function "display" in "model" //sim.addButton("pause/continue", function () { sim.toggle_play() }) // Add a button that calls function "display" in "model" sim.addMovieButton(sim.batchculture, "Internal resources") sim.start() } /*-------------------------End user-defined code ---------------------*/ </script> <body onload="cacatoo()"> <div class="header" id="header"> <h2>ModelJS - </h2> </div> <div class="content" id="canvas_holder"></div> <div class="content" id="form_holder"></div> <div class="content" id="graph_holder"> </div> <div class="footer" id="footer"></div> </body> </html>