Computing Stories: Scintillating Simulations

In previous articles I have sometimes used the word simulation to describe my p5.js sketches. But what is a simulation? What does it mean to create a simulation of a natural phenomena? Some movies such as the Matrix have portrayed the human condition as a simulation. The conspiracy theory of a higher set of beings who generated a contrived context for humans might be a bit much for me. But if you take out the conspiracy and the higher beings perhaps thinking of the world we live in as a simulation has some merit. According to Physics the universe is made up of a collection of matter and energy which is in a particular state. Over time this state changes with apparent compliance to certain universal laws that have been defined by scientists. So we can call the progression of the universe through these states a simulation on an immense scale. Instead of the rules defined in a p5 sketch determining the change of state from frame to frame the universe follows its own laws and changes the state of matter and energy with the passing of time.

Now consider a particular subset of the matter and energy in the universe. The DNA that codes for life as we understand it progresses through a series of states that result in particular changes over time. Darwin called this progression evolution. The progression of DNA is a strong analogy for computer based simulations as DNA is literally a code that gets processed. Where p5.js is processed in the browser resulting in certain outcomes on the screen and in the computers speakers, DNA gets processed in the cells of living things producing the living beings that inhabit our Earth.

So you could say that simulation lies at the core of life itself. In fact the way we make sense of the world can be thought of as simulation. By this I mean that we construct models of the world in our brain and then use information from our senses to modify that model and refine it. For example when we view a three dimensional scene only part of what we perceive is coming from sensory input. Much of it is constructed by our neurons in other words a simulation. Our brain works to make the simulation sensible even when it conflicts with the sensory input. For example when we see a ball bouncing the visual input reaches our eyes long before the sound of the bounce hits our ears but our brain synchronizes the scene and they seem simultaneous as we perceive it. This is one reason eye witness accounts can be discrepant . So you could say that creating simulations and using computers to develop simulations closely aligns with the way our brains work. It is certainly a powerful way to think more deeply about the world around us as the process of constructing simulations leads to wonderful thinking. It also opens up new ways to introduce aesthetics and the arts into scientific thinking increasing the beauty of science.

When the pandemic closed my school this past spring a group of high school students approached me about working together on a coding project in their spare time. One of the students suggested we build a science simulation. We ended up talking for an hour about what would be fun to simulate and settled on gravity. Interestingly computers were first developed to deal with the challenges of taming the complex effects of the gravitational force. One of the first computers, the military funded ENIAC was developed to quickly compute artillery firing tables. At our school all students take Physics in 9th grade so this group of eager coders was well aware that acceleration due to gravity at the Earth’s surface is constant. The question is how do you use this information to model the behavior of objects? Here is how we did it.

First we drew a circle to simulate a falling object.

ellipse(width/2, y, 20);

Then we defined a variable for the y position

let y = 100;

To simulate gravity we have to keep track of the y velocity which we called vy.

let vy = 0;

In the draw loop we changed the y velocity by a constant every frame. For example

vy += 0.01 // without units;

Now you might be concerned that we have not been careful about the units. But the reality is that the units are impacted by the time of one simulation frame as well as the size of a screen pixel. The overall shape of the motion is correct its just not scaled to standard units. If we wanted to predict the position of a falling object in real space we would need to be careful with our units. However, for the purposes of this simulation we just have to make sure it stays on the screen long enough to see it.

Next the students wanted the “ball” to bounce off the floor. So we wrote this statement.

if (y>height) {
vy* = -1;
}

This reverses the velocity when it hits the ground. Here is what the simulation looks like at this point.

To make this simulation two dimensional we could add an x variable and vx variable. Instead I showed the students how to use vectors in p5.

let position = createVector(100, width/2);
let velocity = createVector(4,0);

Now we can rewrite our sketch to run with vectors as shown below.

function checkBoundaries() {
if (position.x < 0 || position.x > width) {
velocity.x *= -1;
}
if (position.y < 0 || position.y > height) {
velocity.y *= -1;
}
}
function draw() {
velocity.y += 0.01;
position.add(velocity);
checkBoundaries();
ellipse(pos.x,pos.y,20);
}

Now we have completed a simulation of a ball falling due to gravity in a vacuum with a perfectly elastic bounce. The beauty of computational modeling is that once you go through the effort to program one ball correctly you can make more of them fairly easily. In order to leverage that ability I showed the students how to make a ball object

const g = 0.04;class Ball {
constructor(pos,v,r){
this.pos=pos; // position of ball
this.v = v; // velocity of ball
this.r = r; // radius of ball
}

checkBoundaries() {
// find the position of the ball in the next frame
const pos = this.pos.copy().add(this.v.copy().mult(dt));
if (pos.x + this.r > width || pos.x - this.r < 0) {
this.v.x *= -1;
}
if (pos.y + this.r > height || pos.y - this.r < 0) {
this.v.y *= -1;
}
}

update() {
this.checkBoundaries();
this.v.y += g; // acceleration due to gravity
// change position according to velocity
this.pos.add(this.v.copy().mult(dt));
}

show() {
noStroke();
fill(255);
ellipse(this.pos.x,this.pos.y,this.r*2)
}
}

Using objects is a clever way to organize the properties and methods of the code for a defined ball. Once we have written the class definition we can easily instantiate many different balls and they will all follow the same set of rules but with different properties defining their individual position and velocity. For the purposes of aesthetics I also varied the hue and size of the balls. Also I had the brightness change based on the calculated kinetic energy of the ball.

This animation is pretty and colorful. There is also something beautiful about the fact that the aesthetics shows you something about the rules of motion. The students commented that the balls should collide. I asked them to explain more. They said that when two balls collide with each other they bounce in a particular way. We decided to try to model that process. It ended up being much more complex than we at first realized. Luckily after talking about momentum and energy and looking at some algebraic expressions we found the following formulas on Wikipedia.

I decided to check if they worked algebraically and they did so it seemed worth giving it a try. Here is the method we wrote for collision in the Ball class. It is a little complicated but it essentially just articulates the expressions shown above using vector methods.

collide(p) { 
let v1 = this.v.copy();
let v2 = p.v.copy();
let m1 = this.m;
let m2 = p.m;
let x1 = this.pos.copy();
let x2 = p.pos.copy();
let a1 = 2*m2/(m1+m2);
let b1 = v1.copy().sub(v2).dot(x1.copy().sub(x2));
b1 /= x1.copy().sub(x2).magSq();
let c1 = x1.copy().sub(x2).mult(a1*b1);
this.v = v1.copy().sub(c1);
let a2 = 2*m1/(m1+m2);
let b2 = v2.copy().sub(v1).dot(x2.copy().sub(x1));
b2 /= x2.copy().sub(x1).magSq();
let c2 = x2.copy().sub(x1).mult(a2*b2);
p.v = v2.copy().sub(c2);
}

Then we wrote a function in sketch.js to check all the possible pairs of balls for a collision.

function collisions() {
// for each pair of particles determine if they have collided.
for (let i = 0; i < balls.length - 1; i++) {
for (let j = i + 1; j < balls.length; j++) {
let b1 = balls[i];
let b2 = balls[j];
//calc position based on one step in the future
let pos1 = b1.pos.copy().add(b1.v.copy().mult(dt));
let pos2 = b2.pos.copy().add(b2.v.copy().mult(dt));
if (pos1.dist(pos2) < b1.r + b2.r) {
b1.collide(b2);
}
}
}
}

Now we have a more complete simulation that handles gravity, collisions with the walls and collisions between the balls. We put it all together and created a simulation. This simulation also has some aesthetic additions similar to the one above. You can click the screen to start and stop the motion of the balls.

I was very impressed with the work we had done. Figuring out the collision formula was a little tricky for high school students, but overall this was not that difficult a simulation to build. And yet is is incredibly powerful. A model like this can give us insight into ideal gas behavior, Brownian motion and turbulence of a fluid to name a few examples.

The point is that from the fundamental principles that we programmed we created a versatile model that results in various emergent phenomena. The rules that we implemented were the acceleration due to gravity causing the velocity to change every frame. The conservation of energy and momentum which lead to the collision equations we found on Wikipedia and the reversing of the velocity components when a ball hits the outer edge, and finally the updating of position every frame based on the value of the balls velocity. From these simple rules came complex behavior which is enjoyable to watch. In fact all of the balls start from rest but gain a diverse set of velocities in a short amount of time. It was exciting for my students to experience the power of simulation. The enjoyment of experiencing the beauty of our world through observation is not a new idea. What is new is appreciating this beauty through creating computational simulations of it as I did with my students.

exploring the intersection of coding, education and disciplinary knowledge

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store