All molecules move randomly according to Brownian motion. The 'A' molecules (light blue) create new 'A' molecules at a fixed rate per unit time. When an 'A' molecule encounters a 'B' molecule (magenta), the 'A' molecule is converted to a 'B' molecule. The 'B' molecules decay at a fixed rate per unit time. I used Quadtree to detect when two molecules, one of each type, move within range to react. It's generally fast, but does slow down when there are many reactions occuring very close together.
-
-
Save newby-jay/b84c6aa65c08e315524e to your computer and use it in GitHub Desktop.
Chemical reaction
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<style> | |
html, body { margin: 0; padding: 0; background: #222;} | |
</style> | |
<canvas id="canvas"></canvas> | |
<script src="http://d3js.org/d3.v3.min.js"></script> | |
<script src="LV.js"></script> | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function () { | |
var canvas = document.getElementById("canvas"), | |
width = canvas.width = 960, | |
height = canvas.height = 500, | |
g = canvas.getContext("2d"); | |
var reactionRadius2 = 2, | |
alpha = 0.007, // fraction of A molecules made per step | |
gamma = alpha/1.5, // fraction of B molecules that decay per step | |
randIC = function (i) { | |
return [width*Math.random(), height*Math.random()]; | |
}, | |
A = d3.range(5e3).map(randIC), | |
B = d3.range(1e3).map(randIC); | |
d3.timer(step); | |
function step() { | |
A = A.concat( | |
d3.range((A.length > 3e3) ? 0 : 1 + Math.round(alpha*A.length)) | |
.map(randBirth)); // add new A molecules | |
B.splice(0, 1 + Math.round(gamma*B.length)); // remove decayed B molecules | |
if (B.length != 0) A.forEach(react()); // reaction | |
g.fillStyle = "rgba(0, 0, 0, .05)"; // fade old | |
g.fillRect(0, 0, width, height); | |
g.fillStyle = "#00FFFF"; | |
A.forEach(moveDrawPoint); | |
g.fillStyle = "#FA58AC"; | |
B.forEach(moveDrawPoint); | |
} | |
function randBirth(i) { | |
var n = Math.round((A.length - 1)*Math.random()); | |
return [A[n][0], A[n][1]]; | |
} | |
function react() { | |
var qt = d3.geom.quadtree()(B); | |
return function (r, i) { | |
if (Math.random()<0.3) return 0; | |
var rb = qt.find(r), | |
dx = r[0] - rb[0], | |
dy = r[1] - rb[1]; | |
if (dx*dx + dy*dy < reactionRadius2) { | |
B.push(r); | |
A.splice(i, 1); | |
} | |
} | |
} | |
var rng = d3.random.normal(0, 1); | |
function moveDrawPoint(r) { | |
r[0] += rng(); | |
r[1] += rng(); | |
if (r[0] < 0) r[0] += width; | |
if (r[0] > width) r[0] -= width; | |
if (r[1] < 0) r[1] += height; | |
if (r[1] > height) r[1] -= height; | |
g.fillRect(r[0], r[1], 0.5, 0.5); | |
} | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment