Skip to content

Instantly share code, notes, and snippets.

@mikeskaug
Forked from vasturiano/README.md
Last active June 29, 2022 14:13
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mikeskaug/27de9c33d44d6b415b2c7b3e7362cde8 to your computer and use it in GitHub Desktop.
Save mikeskaug/27de9c33d44d6b415b2c7b3e7362cde8 to your computer and use it in GitHub Desktop.
Brownian motion

Simulation of particles immersed in fluid at some temperature, using the d3-force physics engine.

This is was inspired by this block.

The velocities of the fluid particles are drawn from the Maxwell-Boltzman velocity distribution and scale with temperature like sqrt(T).

This illustrates the origin of Brownian motion, which is the random motion of particles suspended in a fluid due to collisions with the fast moving fluid particles or molecules.

<head>
<script src="//cdnjs.cloudflare.com/ajax/libs/d3/4.8.0/d3.min.js"></script>
<script src="//unpkg.com/d3-force-bounce@0.4/dist/d3-force-bounce.min.js"></script>
<script src="//unpkg.com/d3-force-surface@0.4/dist/d3-force-surface.min.js"></script>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="controls">
Temperature:
<input id="temperature-control" type="range" min="1" max="50" step="1" value="10" oninput="onTemperatureChange(this.value)">
<span id="temperature-val">5</span>
</div>
<svg id="canvas"></svg>
<script src="index.js"></script>
</body>
const GAS_DENSITY = 0.0005, // particles per sq px
NUM_DIFFUSERS = 5,
DIFFUSER_RADIUS = 50;
let TEMP = 10;
const canvasWidth = window.innerWidth,
canvasHeight = window.innerHeight,
numGasParticles = Math.round(canvasWidth * canvasHeight * GAS_DENSITY),
svgCanvas = d3.select('svg#canvas')
.attr('width', canvasWidth)
.attr('height', canvasHeight);
function randomVelocity(temp) {
// The Maxwell-Boltzman velocity distribution where temp is a renormalized temperature temp = kT/m
return d3.randomNormal(0, Math.sqrt(temp))();
}
function generateParticles(temp) {
const diffusers = d3.range(NUM_DIFFUSERS).map(() => {
return {
x: Math.random() * canvasWidth,
y: Math.random() * canvasHeight,
vx: 0,
vy: 0,
r: DIFFUSER_RADIUS
}
});
const gas = d3.range(numGasParticles).map(() => {
return {
x: Math.random() * canvasWidth,
y: Math.random() * canvasHeight,
vx: randomVelocity(temp),
vy: randomVelocity(temp),
r: 3
}
});
return diffusers.concat(gas);
}
const forceSim = d3.forceSimulation()
.alphaDecay(0)
.velocityDecay(0)
.on('tick', particleDigest)
.force('bounce', d3.forceBounce()
.radius(d => d.r)
)
.force('container', d3.forceSurface()
.surfaces([
{from: {x:0,y:0}, to: {x:0,y:canvasHeight}},
{from: {x:0,y:canvasHeight}, to: {x:canvasWidth,y:canvasHeight}},
{from: {x:canvasWidth,y:canvasHeight}, to: {x:canvasWidth,y:0}},
{from: {x:canvasWidth,y:0}, to: {x:0,y:0}}
])
.oneWay(true)
.radius(d => d.r)
)
.nodes(generateParticles(TEMP));
// Event handlers
function onTemperatureChange(temp) {
d3.select('#temperature-val').text(temp);
let updatedParticles = forceSim.nodes().map(node => {
return node.r === DIFFUSER_RADIUS ? node : {
x: node.x,
y: node.y,
vx: node.vx * Math.sqrt(temp) / Math.sqrt(TEMP),
vy: node.vy * Math.sqrt(temp) / Math.sqrt(TEMP),
r: 3
};
})
forceSim.nodes(updatedParticles);
TEMP = temp;
}
//
function particleDigest() {
let particle = svgCanvas.selectAll('circle.particle').data(forceSim.nodes());
particle.exit().remove();
particle.merge(
particle.enter().append('circle')
.classed('particle', true)
.attr('r', d=>d.r)
.attr('fill', 'darkslategrey')
)
.attr('cx', d => d.x)
.attr('cy', d => d.y);
}
body {
margin: 0;
text-align: center;
font-family: sans-serif;
font-size: 14px;
}
#controls {
position: absolute;
margin: 8px;
padding: 1px 5px 5px 5px;
background: rgba(230, 230, 250, 0.7);
opacity: 0.5;
border-radius: 3px;
z-index: 1000;
}
#controls:hover {
opacity: 1;
}
#velocity-control {
position: relative;
top: 3px;
cursor: grab;
cursor: -webkit-grab;
}
#velocity-control:active {
cursor: grabbing;
cursor: -webkit-grabbing;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment