www.xbdev.net
xbdev - software development
Sunday July 21, 2024
Home | Contact | Support | JavaScript... so much power in such a few lines of code..
     
 

JavaScript...

so much power in such a few lines of code..

 



Quick introduction in to basic fluid (and gas) dynamics with a practical emphasis (not just theory but actually implementing and seeing things work).

Keywords: smoke, gas, dynamics, grid, simulation, real-time, animation, vortex, diffuse

Fluids are really cool and also very common - they're all around you! The human body is 65% water, and the Earth is 2/3 water.. while gasses are like fluids brother - they have a very similar set of properties - like air, smoke and clouds.

If you drop in in water or watch smoke float up into the sky - I'm sure you noticed the patterns of similarity?

Anyhow, fluid and gas dynamics are all around you! The're magical and beautiful - and you can emulate their characteristics in code.

So how do you go about simulating these things? Is it hard?

Well fluid dynamics is a big area! With lots of different models - with levels of accuracy and computation cost - however, for the most part of this tutorial I'll focus on `visually' realistic simulations that make numerical approximations. Looks and moves correctly! Also fast and we can interact with it in real-time.


Fluids and gases are everywhere! They
Fluids and gases are everywhere! They're inside you, they're all around you, they are both simple and complex. Their beauty and magic in static and dynamic form are beyond words.


Few concepts and their details - which we're going to try and include:

Diffusion: In a cup of tea, sugar molecules diffuse from areas of high concentration to low concentration, sweetening the drink evenly.
Vortex: A whirlpool forms when water rushes down a drain, creating a swirling vortex of water.
Buoyancy: A ship floats because its weight is less than the weight of water it displaces, thanks to buoyancy.
Viscosity: Honey flows slowly due to its high viscosity, resisting deformation and sticking to surfaces.


Simple Discrate Fluid/Gas Simulation Demo


The code uses JavaScript for the fluid/gas dynamics - as it's easy to follow and can run anywhere (just need a web browser). Focus on 2D simulations - so that it doesn't get overy complex. But it should be enough to show swirly ink-like animation patterns.

The concept implementation has been broken down into key functions - each performing a specific task (like diffusion and buoyancy).

The full code is also implemented on a demo page (LINK).




Smoke and Gas Simulation Output - screenshot from smoke.xbdev.net - test the demo out live.
Smoke and Gas Simulation Output - screenshot from smoke.xbdev.net - test the demo out live.




The following gives the full working code (simplfied) that can run from a single file (no external libraries or resources required).

<!DOCTYPE html>
<
html lang="en">
<
head>
<
meta charset="UTF-8">
<
meta name="viewport" content="width=device-width, initial-scale=1.0">
<
title>Fluid and Gas Dynamics Simulation XBDEV Educational Tech Demo</title>
<
style>
    
canvas {
        
border1px solid black;
    }
</
style>
</
head>
<
body>
<
canvas id="canvas" width="400" height="400"></canvas>
<
script>
    
// Get the canvas element and its context
    
const canvas document.getElementById('canvas');
    const 
ctx canvas.getContext('2d');

    
// Define the size of the grid
    
const resolution 2.0;
    const 
cols canvas.width resolution;
    const 
rows canvas.height resolution;

    
// Create arrays to hold the density, u velocity, and v velocity
    
let density = new Array(cols).fill(0).map(() => new Array(rows).fill(0));
    
let u = new Array(cols).fill(0).map(() => new Array(rows).fill(0));
    
let v = new Array(cols).fill(0).map(() => new Array(rows).fill(0));

    
// Initialize density with a letter pattern
        
const letter "G"// Change the letter here
        
ctx.font "bold 150px Arial";
        
ctx.fillText('X'50150);

        
// Convert the letter on canvas to the density array
        
const imageData ctx.getImageData(00canvas.widthcanvas.height);
        for (
let i 0colsi++) {
            for (
let j 0rowsj++) {
                if (
imageData.data[(imageData.width) + (4) + 3] > 128
                {
                    
density[i][j] = 1.0;
                }

            }
        }

    
// initial velcoity
    
for (let i 0colsi++) {
        for (
let j 0rowsj++) {
            const 
resolution canvas.width 2;
            const 
resolution canvas.height 2;
            
// Introduce some randomness to the velocity initialization
            
u[i][j] = Math.cos*  cols ) * Math.sincols ) * 0.1;
            
v[i][j] = Math.sin16 cols ) * Math.sincols ) * 0.5;
        }
    }


    
// Function to update the simulation
    
function update() {
        
// Apply diffusion
        
let diff 0.01;
        
diffuse(diffu);
        
diffuse(diffv);
      
        
applyBuoyancy(densityv);

        
// Apply curl
        
curl();

        
// Advect density
        
advect(densityuv);

        
// Draw the updated fields
        
render();
        
        
// Request animation frame for continuous update
        
requestAnimationFrame(update);
    }

  
    
// Function to apply diffusion
    
function diffuse(difffield) {
        const 
dt 0.1// Time step
        
const visc 0.0001// Viscosity
        
const amount dt visc * (cols 2) * (rows 2) * diff;

        for (
let k 010k++) { // Iterations for stability
            
for (let i 1cols 1i++) {
                for (
let j 1rows 1j++) {
                    
field[i][j] = (field[i][j] + amount * (
                        
field[1][j] + field[1][j] +
                        
field[i][1] + field[i][1])) / (amount);
                }
            }
        }
    }

      
// Function to apply buoyancy force
    
function applyBuoyancy(densityv) {
        const 
gravity 0.05// Strength of gravity
        
const buoyancyAlpha 0.1// Buoyancy coefficient for density difference
        
const buoyancyBeta 0.1// Buoyancy coefficient for vertical velocity
        
const ambientTemperature 0// Ambient temperature

        
for (let i 0colsi++) {
            for (
let j 0rowsj++) {
                const 
densityDifference density[i][j] - ambientTemperature;
                const 
buoyancyForce = -buoyancyAlpha densityDifference buoyancyBeta v[i][j];

                
// Apply buoyancy force to vertical velocity
                
v[i][j] += buoyancyForce gravity;
            }
        }
    }

  

 
    
// Function to apply curl
    
function curl() {
        const 
dt 0.1// Time step
        
const curlCoefficient 1.0;

        for (
let i 1cols 1i++) {
            for (
let j 1rows 1j++) {
                const 
du_dy = (u[i][1] - u[i][1]) / (resolution);
                const 
dv_dx = (v[1][j] - v[1][j]) / (resolution);

                const 
curl dv_dx du_dy;
                
u[i][j] += -curl dt curlCoefficient;
                
v[i][j] +=  curl dt curlCoefficient;
            }
        }
    }

  
  
// Function to advect the density field
function advect(fielduv) {
    const 
dt 0.1// Time step

    
const temp = new Array(cols).fill(0).map(() => new Array(rows).fill(0));

    for (
let b=0b<7b++)
    for (
let i 1cols 1i++) {
        for (
let j 1rows 1j++) {
            
let x u[i][j] * dt resolution;
            
let y v[i][j] * dt resolution;

            
// Add some diffusion-like behavior
            //x += (Math.random() * 2 - 1) * 0.1; // Introduce random noise in x direction
            //y += (Math.random() * 2 - 1) * 0.1; // Introduce random noise in y direction

            // Clamp advection position to canvas boundaries
            
if (0.50.5;
            if (
cols 0.5cols 0.5;
            if (
0.50.5;
            if (
rows 0.5rows 0.5;

            const 
i0 Math.floor(x);
            const 
i1 i0 1;
            const 
j0 Math.floor(y);
            const 
j1 j0 1;

            const 
s1 i0;
            const 
s0 s1;
            const 
t1 j0;
            const 
t0 t1;

            
field[i][j] = s0 * (t0 field[i0][j0] + t1 field[i0][j1]) +
                          
s1 * (t0 field[i1][j0] + t1 field[i1][j1]);
        }
    }
}

  
  

    
// Function to render the fields
    
function render() {
        
ctx.clearRect(00canvas.widthcanvas.height);

        for (
let i 0colsi++) {
            for (
let j 0rowsj++) {
                const 
resolution;
                const 
resolution;

                
// Draw density
                
ctx.fillStyle = `rgba(0, 0, 0, ${density[i][j]})`;
                
ctx.fillRect(xyresolutionresolution);

                
/*
                // Draw velocity vectors
                ctx.beginPath();
                ctx.moveTo(x + resolution / 2, y + resolution / 2);
                ctx.lineTo(x + resolution / 2 + u[i][j] * 10, y + resolution / 2 + v[i][j] * 10);
                ctx.strokeStyle = 'blue';
                ctx.lineWidth = 2;
                ctx.stroke();
                */
            
}
        }
    }

    
// Start the simulation
    
update();
</
script>
</
body>
</
html>





Terms/Abbreviations/Glossary


CFD - Computational Fluid Dynamics
PDEs - Partial Differential Equations
FDM - Finite Difference Methods



Resources and Links


• Example test demo runnning [LINK]


 
Advert (Support Website)

 
 Visitor:
Copyright (c) 2002-2024 xbdev.net - All rights reserved.
Designated articles, tutorials and software are the property of their respective owners.