cacatoo
Version:
Building, exploring, and sharing spatially structured models
139 lines (103 loc) • 5.79 kB
HTML
<!--
EXAMPLE FILE Turing patterns
Another simple example of using ODEs coupled by diffusion,
creating awesome Turing patterns! <3
-->
<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: "Turing patterns",
description: "Reaction-diffusion system with short-range activation and long-range inhibition",
maxtime: 100000,
ncol: 100,
nrow: 100, // dimensions of the grid to build
wrap: [true, true], // Wrap boundary [COLS, ROWS]
scale: 3, // scale of the grid (nxn pixels per grid cell
show_gridname: true,
graph_interval: 1,
graph_update: 5
}
sim = new Simulation(config)
sim.makeGridmodel("turing")
sim.turing.colourViridis("activator", 100)
sim.createDisplay_continuous({model:"turing", property:"activator", label:"Activator density", // Createa a display for a continuous variable (ODE state for external resources)
minval:0, maxval:100})
// A self-replicating turing, which also produces a second molecule which inhibits the turing
let Turing = function (a, b, i, d) {
return function (x, y) {
return [
a * y[0] - i * y[1] - d * y[0] * y[0], // y[0] is the activating molecule
b * y[0] - i * y[1] - d * y[1] * y[1] // y[1] is the inhibiting molecule, which inhibits both but is produced by the activating molecule,
]
}
}
// Configuration object with initial states, parameters, and diffusion rates
let ode_config = {
ode_name: "turingeq",
init_states: [0, 0], // y[0] and y[1]
parameters: [0.5, 0.5, 0.5, 0.05], // a,b,i,d
diffusion_rates: [0.1, 0.2]
} // resources diffuse through exteral environment, but internal resources stay put
// Attaches an ODE to all gridpoints with initial state = [0,0].
// By default, all ODEs are stored in an array in the grid point, but...
// If you want to access it by name, you can give a name as the final variable (here lotka)
sim.turing.attachODE(Turing, ode_config);
// Initialise the left 3 cols with predators and prey by setting the state via the named ODE 'lotka'
for (let x = 0; x < sim.turing.nc; x++)
for (let y = 0; y < sim.turing.nr; y++)
sim.turing.grid[x][y].turingeq.state = [1 + sim.rng.genrand_real1(), 1]
// The nextState function has 3 steps: 1) ODE integration, 2) Diffusion, 3) Update what is displayed on the grid
sim.turing.nextState = function (x, y) // Define the next-state function.
{
// 1) ODE integration
this.grid[x][y].turingeq.solveTimestep(1.0, opt_pos = true)
// 3) Update how this GP is displayed
let act = Math.max(0.001, this.grid[x][y].turingeq.state[0]) // Amount of prey (continuous variable)
let inh = Math.max(0.001, this.grid[x][y].turingeq.state[1]) // Amount of pred (continuous variable)
this.grid[x][y].activator = Math.min(Math.floor(act * 80), 99)
}
sim.turing.update = function () {
this.asynchronous() // For only solving the ODEs within grid points, asynchronous or synchronous is identical.
this.diffuseODEstates()
let sumact = 0
let suminh = 0
let midact = 0
let midinh = 0
for (let x = 0; x < this.nc; x++) // x are columns
for (let y = 0; y < this.nr; y++) // y are rows
{
sumact += this.grid[x][y].turingeq.state[0]
suminh += this.grid[x][y].turingeq.state[1]
if (x == this.nc / 2 && y == this.nr / 2) midact = this.grid[x][y].turingeq.state[0]
if (x == this.nc / 2 && y == this.nr / 2) midinh = this.grid[x][y].turingeq.state[1]
}
this.plotArray(["Act", "Inh"],
[sumact, suminh],
["gold", "#FF00AA"],
"Total act/inh abundance")
this.plotArray(["Act", "Inh"],
[midact, midinh],
["gold", "#FF00AA"],
"ODE states in central grid point")
//if(this.time%100==0) this.drawSlide("Activator density") // Calls a download-request for images, allowing users to store their grids while running the simulation
}
sim.addButton("mix grid", function () { sim.turing.perfectMix() })
sim.addMovieButton(sim.turing,"Activator density")
sim.start()
}
/*-------------------------End user-defined code ---------------------*/
</script>
<body onload="cacatoo()">
<div class="header" id="header"></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>