cacatoo
Version:
Building, exploring, and sharing spatially structured models
182 lines (144 loc) • 8.77 kB
HTML
<!--
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>