Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save chooblarin/bfbd1bf2a2827ac31d00c39c7ece5345 to your computer and use it in GitHub Desktop.
Save chooblarin/bfbd1bf2a2827ac31d00c39c7ece5345 to your computer and use it in GitHub Desktop.
1-dimensional diffusion simulation with D3.js
console.clear();
const { BehaviorSubject, interval } = rxjs;
const { take } = rxjs.operators;
const margin = { top: 20, right: 20, bottom: 40, left: 45 }
const width = 640 - margin.left - margin.right
const height = 400 - margin.top - margin.bottom
const svg = d3.select('body')
.append('svg')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.append('g')
.attr('transform', `translate(${margin.left}, ${margin.top})`);
const x = d3.scaleLinear().range([0, width]);
const y = d3.scaleLinear().range([0, height]);
const initialCondition = Array(100).fill(0.0).map((_, i) => {
const x = i * 0.1 - 5;
return {
x,
y: Math.exp(- x * x)
}
});
const xAxis = d3.axisBottom(x).ticks(initialCondition.length / 10.0);
const yAxis = d3.axisLeft(y).ticks(5);
const dataset = new BehaviorSubject(initialCondition);
x.domain(d3.extent(initialCondition, d => d.x));
y.domain([
d3.max(initialCondition, d => d.y),
d3.min(initialCondition, d => d.y),
]);
const valueLine = d3
.line()
.x(d => x(d.x))
.y(d => y(d.y));
svg
.append('g')
.attr('class', 'axis')
.attr('transform', `translate(0, ${height})`)
.call(xAxis);
svg
.append('g')
.attr('class', 'axis')
.call(yAxis);
dataset.subscribe(data => {
svg.select('.line').remove();
svg.append('path')
.attr('class', 'line')
.attr('d', valueLine(data));
});
const laplacian1D = (data, dx) => {
const result = [];
for (let i = 0; i < data.length; i += 1) {
if (i === 0) {
const v = (data[data.length - 1] + data[i + 1] - 2 * data[i]) / (dx * dx);
result.push(v);
} else if (i === data.length - 1) {
const v = (data[i - 1] + data[0] - 2 * data[i]) / (dx * dx);
result.push(v);
} else {
const v = (data[i - 1] + data[i + 1] - 2 * data[i]) / (dx * dx);
result.push(v);
}
}
return result;
};
const D = 1.0; // diffusion parameter
const dt = 0.001;
const update = (current) => {
const lapl = laplacian1D(current.map(({_, y}) => y), 0.1);
const next = [];
for (let i = 0; i < current.length; i += 1) {
const {x, y} = current[i];
const nextY = y + (D * lapl[i]) * dt;
next.push({ x, y: nextY });
}
return next;
};
interval(0)
.pipe(
take(10000)
)
.subscribe(n => {
const current = dataset.value;
const next = update(current);
dataset.next(next);
});
<script src="https://d3js.org/d3.v5.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.2.0/rxjs.umd.js"></script>
body {
font-family: system-ui, "Helvetica Neue", Helvetica, sans-serif;
font: 10px;
background-color: hsl(195, 45%, 18%);
}
svg {
margin-left: 20px;
background: hsl(195, 45%, 18%);
}
.axis line,
.axis path {
stroke: white;
}
.axis text {
fill: white;
}
.line {
stroke: hsl(72, 75%, 66%);
stroke-width: 3;
fill: none;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment