# All the code together

Up a level : Themodynamics
Previous page : Motion in the ocean… I mean in the atmosphere The whole program

I have by purpose not used any frameworks or external modules, and also no OOP, even if I use objects. The reasons are that I can use it in the Programming 1 course I hold, where OOP is not part of the course, and also because I am not a great fan of OOP.  Ok, here is the code:

```'use strict';

/**************************************************
*
*  A simulation of an atmosphere 1.4
* By Mauritz Blomqvist 2021-02-12.
* This is free to use - but I'm happy if you add
* a link to this page
* https://properhoc.com/physics/themodynamics/a-simulation-of-an-atmosphere/
* in your code.
*
* This basically simulates a slice of an
* atmosphere from the ground up to the
* vacuum of space.
*
* In this 3000 "atoms", particles, are
* undergoing totally elastic collision with
* each other and the walls.
* The particles are also influenced by gravity
* so if they move upward they will slow down
* until they eventually start to fall down again.
*
* The gas is initially in the lower end of the
* atmosphere, and then they are "released".
* After a minute or so the distribution of
* particles keep somewhat constant.
*
**************************************************/

// Initialization of the canvas.
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
canvas.style = 'border:1px solid #0F0000;';

// The slice of space is 600 pixels wide
// and 6000 pixels high.
canvas.width = 600;
canvas.height = 6000;

// Number of particles.
let n = 3000;

// Free fall acceleration * dt.
let gDt = 0.01;

// The size of one atom  - and related variables.
let radius = 2;
let diameter = 2 * radius;
let diameter2 = (2 * radius) ** 2;

// Initial speed of the atoms.
let v0max = 3;

// To speed up the calculations of the
// particle-particle interactions the particles are
// sorted in vertical slots of the same width
// as the diameter of one atom (or slightly larger).
// Then we only need to check the slot and
// adjacent slots for
let nSlots = Math.ceil(canvas.width / diameter);

let slots;

// A click on the restart button
// will create new particles placed
// in the bottom part of the canvas.
document
.getElementById('restart')
.addEventListener('click', () => createParticles(n));

// This function is used to check if new particles overlap.
function same(x, y) {
for (let i = 0; i < particles.length; i++) {
let d = Math.sqrt((particles[i].x - x) ** 2 + (particles[i].y - y) ** 2);
if (d <= 2 * radius) return true;
}
return false;
}

// This will create new particles.
// They will be given a random direction of
// motion, and a random position within the lowest 500
// pixels of the canvas.
// If a new particle overlaps with any already existing
// a new position is tried until the particle
// is placed at a previously empty position.
let particles;
function createParticles(n) {
particles = [];
let particle;

for (let i = 0; i < n; i++) {
let dir = Math.random() * 2 * Math.PI;
do {
particle = {
x: Math.random() * (canvas.width - 2 * radius) + radius,
y: canvas.height - Math.random() * (500 - 2 * radius) + radius,
vx: v0max * Math.cos(dir),
vy: v0max * Math.sin(dir),
};
} while (same(particle.x, particle.y));
particles.push(particle);
}
}
createParticles(n);

// This will draw particle number i as a small circle.
function drawParticle(i) {
ctx.beginPath();
ctx.arc(particles[i].x, particles[i].y, radius, 0, 2 * Math.PI);
ctx.stroke();
}

// This will draw all particles. Particle
// nr 0 will be red, all the rest will
// be blue.
function draw() {
ctx.strokeStyle = 'RED';
drawParticle(0);
ctx.strokeStyle = 'BLUE';
for (let i = 1; i < n; i++) {
drawParticle(i);
}
}

// This function moves the particles
// and checks if a particle will bounce on a
// wall. If so it will change the direction
// of the perpendicular component of the
// motion. If the particle moves in the vertical
// direction the velocity will change due to
// gravity.
// As the particle moves say downward, it will change
// its velocity by gdt, but the average velocity will be
// (vOld+vNew)/2=(vOld+vOld+gdt)/2=vOld+gdt/2.
// This can be seen in hte code in a few places.
function move() {
for (let i = 0; i < n; i++) {
particles[i].x += particles[i].vx;
particles[i].y += particles[i].vy + gDt / 2;

if (particles[i].y < radius) {
if (particles[i].vy < 0) particles[i].vy *= -1;
particles[i].y += particles[i].vy - gDt / 2;
} else if (particles[i].y > canvas.height - radius) {
if (particles[i].vy > 0) particles[i].vy *= -1;
particles[i].y += particles[i].vy - gDt / 2;
} else particles[i].vy += gDt;

if (particles[i].x < radius) {
if (particles[i].vx < 0) particles[i].vx *= -1;
particles[i].x += particles[i].vx;
} else if (particles[i].x > canvas.width - radius) {
if (particles[i].vx > 0) particles[i].vx *= -1;
particles[i].x += particles[i].vx;
}
}
}

// This is to check if particle i and j
// has collided. The horizontal distance between
// the particles is checked to see if a collision
// is possible, if so, then the actual distance is
// checked. If a collision is still
// possible then it is checked if the particles are moving
// toward each other => collision, or not.
// Then the calculations to simulate
// a totally elastic collision is done.
function collision(i, j) {
let dy = particles[i].y - particles[j].y;
if (Math.abs(dy) < diameter) {
let dx = particles[i].x - particles[j].x;
let dy = particles[i].y - particles[j].y;
let d2 = dx ** 2 + dy ** 2;
if (d2 < diameter2) {
let dvx = particles[j].vx - particles[i].vx;
let dvy = particles[j].vy - particles[i].vy;
let dvs = dx * dvx + dy * dvy;
if (dvs > 0) {
dvs = dvs / d2;
dvx = dvs * dx;
dvy = dvs * dy;
particles[i].vx += dvx;
particles[i].vy += dvy;
particles[j].vx -= dvx;
particles[j].vy -= dvy;
}
}
}
}

// In this function particle-particle interactions
// is checked. First the particles will
// be placed in vertical slots with a width
// equal to (or slightly larger than) the
// radius of the particles.
// Then we loop over the slots, checking for
// collisions among particles in the same slot,
// and then with particles in the slot to the left.
// I.e. the slots are checked all in 0 against all in 0,
// all in 0 against all in 1, all in 1 against all in 1,
// i.e. 0-0, 0-1, 1-1, 1-2, 2-2 and so on until the last slot
// where we of course do not check against the non existent
// next slot.
// In this way we ensure that all possible pairs of particles
// that could possibly collide are checked.
function particleParticle() {
slots = Array(nSlots)
.fill(null)
.map(() => []);
// Place the particles in the correct slot.
for (let i = 0; i < n; i++) {
let s = Math.floor(particles[i].x / diameter);
s = Math.max(s, 0);
s = Math.min(s, nSlots - 1);
slots[s].push(i);
}
for (let s = 0; s < nSlots; s++) {
// Check all pairs of particles in the current slot.
for (let i = 0; i < slots[s].length - 1; i++) {
for (let j = i + 1; j < slots[s].length; j++) {
collision(slots[s][i], slots[s][j]);
}
}
// Check all particles in the current slot
// against all particles in the slot to the right
// unless we are at the last slot.
if (s !== nSlots - 1) {
for (let i = 0; i < slots[s].length; i++) {
for (let j = 0; j < slots[s + 1].length; j++) {
collision(slots[s][i], slots[s + 1][j]);
}
}
}
}
}

// Checks if the Escape key is pressed, if so
// set running to false, that will cause
// the main loop to halt.
// If the escape key is pressed again the
// main loop is called again.
let key = '';
let running = true;
function keyDown(event) {
key = event.key;
if (key === 'Escape') {
if (running) {
running = false;
} else {
running = true;
requestAnimationFrame(theMainLoop);
}
}
}

// The main loop. The canvas is cleared,
// Then the particles are moved, and collisions
// with the walls are done.
// Next particle-particle interactions are checked
// and done.
// Then the particles are drawn.
// If the running flag is set the main loop
// is called again.
function theMainLoop() {
ctx.clearRect(0, 0, canvas.width, canvas.height);

move();

particleParticle();

draw();

if (running) requestAnimationFrame(theMainLoop);
}

requestAnimationFrame(theMainLoop);```

And the html:

```<!DOCTYPE html>
<html lang="en">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Atmosphere</title>
<body>
<h2>A simulation of an atmosphere</h2>
<p>Scroll down to see the lower end of the simulated atmosphere.</p>
<p>For an explanation see <a href="https://properhoc.com/physics/themodynamics/a-simulation-of-an-atmosphere/"> here </a>.</p>
<canvas id="canvas"></canvas>
<br>
<p id="p1"></p>
<button id="restart">Restart</button>
<script src="atmosphere4.js"></script>
</body>
</html>``` Up a level : Themodynamics
Previous page : Motion in the ocean… I mean in the atmosphere Last modified: Feb 12, 2021 @ 17:59