I'm playing with a Heat Equation on 2D Canvas with additional heat source in a form of a donut. The result I got some "acidic" pattern around this donut.
const width = 200; // width of the grid
const height = 200; // height of the grid
const dt = 0.25; // time step
const dx = 1; // space step in the x-direction
const dy = 1; // space step in the y-direction
const alpha = 0.25; // thermal diffusivity
const Q = [];
// Heat of the heat source
const Q0 = 80;
const r1 = 8;
const r2 = 12;
for (let i = 0; i < width - 1; i ) {
Q[i] = [];
for (let j = 0; j < height - 1; j ) {
// Calculate the distance from the center of the region
const r = Math.sqrt((i - width / 2) ** 2 (j - height / 2) ** 2);
Q[i][j] = (r1 < r && r < r2) ? Q0 : 0;
}
}
let grid = []; // array to store the grid
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
// Initialize the grid with random temperatures
for (let i = 0; i < width; i ) {
grid[i] = [];
for (let j = 0; j < height; j ) {
grid[i][j] = 50
}
}
function updateGrid() {
// Update the temperature of each cell based on the heat equation
for (let i = 1; i < width - 1; i ) {
for (let j = 1; j < height - 1; j ) {
const d2Tdx2 = (grid[i 1][j] - 2 * grid[i][j] grid[i - 1][j]) / (dx ** 2);
const d2Tdy2 = (grid[i][j 1] - 2 * grid[i][j] grid[i][j - 1]) / (dy ** 2);
grid[i][j] = grid[i][j] alpha * dt * (d2Tdx2 d2Tdy2) (Q[i][j] * dt);
}
}
}
// This function is called repeatedly to update the grid and render it
function main() {
updateGrid();
renderGrid();
requestAnimationFrame(main);
}
// This function render the grid
function renderGrid() {
// Clear the canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Iterate over the grid and draw each cell
for (let i = 0; i < width; i ) {
for (let j = 0; j < height; j ) {
let hue = ((100 - grid[i][j]) / 100) * 240;
//ctx.fillStyle = `rgb(${temp}, ${temp}, ${temp})`;
ctx.fillStyle = `hsl(${hue}, 100%, 50%)`;
ctx.fillRect(i * dx, j * dy, dx, dy);
}
}
}
// Start the simulation
main();
Tried different approaches, like playing with hsl colors, initial parameters but something definitely missing there.
What I aslo noticed is that during debuging, some values seems to be blowing up and I think that's the root of the problem but can't find the source of it, I have tried to found more information about this behaviour of differential equiations and why this can happen but couldn't apply it to the source code.
CodePudding user response:
during calculation values in grid can go over 100, thus making formula ((100 - grid[i][j]) / 100) * 240;
produce negative values
the simples way to fix is to limit values:
grid[i][j] = Math.min(100, grid[i][j] alpha * dt * (d2Tdx2 d2Tdy2) (Q[i][j] * dt));
const width = 200; // width of the grid
const height = 200; // height of the grid
const dt = 0.25; // time step
const dx = 1; // space step in the x-direction
const dy = 1; // space step in the y-direction
const alpha = 0.25; // thermal diffusivity
const Q = [];
// Heat of the heat source
const Q0 = 80;
const r1 = 8;
const r2 = 12;
for (let i = 0; i < width - 1; i ) {
Q[i] = [];
for (let j = 0; j < height - 1; j ) {
// Calculate the distance from the center of the region
const r = Math.sqrt((i - width / 2) ** 2 (j - height / 2) ** 2);
Q[i][j] = (r1 < r && r < r2) ? Q0 : 0;
}
}
let grid = []; // array to store the grid
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
// Initialize the grid with random temperatures
for (let i = 0; i < width; i ) {
grid[i] = [];
for (let j = 0; j < height; j ) {
grid[i][j] = 50
}
}
function updateGrid() {
// Update the temperature of each cell based on the heat equation
for (let i = 1; i < width - 1; i ) {
for (let j = 1; j < height - 1; j ) {
const d2Tdx2 = (grid[i 1][j] - 2 * grid[i][j] grid[i - 1][j]) / (dx ** 2);
const d2Tdy2 = (grid[i][j 1] - 2 * grid[i][j] grid[i][j - 1]) / (dy ** 2);
grid[i][j] = Math.min(100, grid[i][j] alpha * dt * (d2Tdx2 d2Tdy2) (Q[i][j] * dt));
}
}
}
// This function is called repeatedly to update the grid and render it
function main() {
updateGrid();
renderGrid();
requestAnimationFrame(main);
}
// This function render the grid
function renderGrid() {
// Clear the canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Iterate over the grid and draw each cell
for (let i = 0; i < width; i ) {
for (let j = 0; j < height; j ) {
let hue = (100 - grid[i][j]) / 100 * 240;
//ctx.fillStyle = `rgb(${temp}, ${temp}, ${temp})`;
ctx.fillStyle = `hsl(${hue}, 100%, 50%)`;
ctx.fillRect(i * dx, j * dy, dx, dy);
}
}
}
// Start the simulation
main();
<canvas width="500" height="500" id="canvas"></canvas>