// Program for velocity and density distribution
// inelastic collisions - Arshad Kudrolli
//
// Event driven simulation of particles in one dimension colliding
// inelastically. The particle-particle collisions are inelastic,
// particle-left wall is elastic, and particle right wall imparts
// random velocity.
//
// The program resets if a numerical error is detected.
//
// Some of the program structure is from a program written by
// Kelly Jo Brown found in www.gamelan.com.
import java.awt.*;
import java.applet.*;
import java.lang.*;
public class inelastic extends Applet implements Runnable{
Graphics img;
Image screen, ball;
double x[]; // x position of particles
double y[]; // y position
double v[]; // velocity of particles
double vold[];
double t[]; // time between events
double terr = 1.0e-15; // underestimate of time to prevent crossings
int unit=1;
int zero=0;
int two =2;
int offset = 33; // size of the particle gif 23
double max_v = 10.0; //max value of velocity at right wall.
double time = (double)unit; //time intervel after which positions are evaluated.
int pause=50; // wait time between frames
int caught=0,flag;
int num_par=5; // number of particles
int L = 520 - num_par * offset;
int px,py,tempx,tempy,slide=5,slide2=num_par*10;
int num_c =0; // number of collisions
double r = 1.0 - (double)slide/100.0;
double e= (1.0 - r)/2.0;
// e between 0 and 0.5
Thread kicker = null;
MediaTracker tracker;
public void run()
{
int i;
double rad,delta_angle,radius;
Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
while(kicker != null)
{
// calculate time to the next collision - left wall
if ( v[0] > 1e-20 || v[0] < -1e-20) {
t[0] = - x[0]/v[0];
}
else {
t[0] = 1e10;
}
// interparticle collision times
for (i=1; i < num_par; i++) {
if ( x[i] - x[i-1] < (double)zero ) {
flag = 1;
}
t[i] = - (x[i] - x[i-1])/(v[i] - v[i-1]);
}
if ( x[0]< (double)zero ) {
flag = 1;
}
if ( flag == 1) {
init();
}
// collision with right wall
if ( v[num_par-1] > 1e-20 || v[num_par-1] < -1e-20) {
t[num_par] = ((double)L - x[num_par-1])/v[num_par-1];
}
else {
t[num_par] = 1e10;
}
// check which event will occur first
double tmin =1.0e30;
int event = -1;
for (i=0; i< num_par+1; i++) {
if (t[i] > (double)zero && t[i] < tmin ) {
tmin = t[i];
event = i;
}
// System.out.print(x[i]+" "); //check
}
// System.out.println(event); //check
if ( tmin > time) {
// calculate the position after time.
for(i=0;i<num_par;i++)
{
x[i] = x[i] + v[i] * time;
y[i]= 200;
vold[i] = v[i];
}
}
else {
// Side wall conditions - give random kick at right wall.
if ( event == num_par ) {
// v[num_par-1] = - Math.round(Math.random()*max_v - 1.0);
v[num_par-1] = - (Math.random()*max_v);
}
// Side wall condition - elastic collision.
else if ( event == 0 ) {
v[0] = -v[0];
}
// Interparticle collisions.
else {
v[event] = (e * vold[event] + ((double)unit-e) * vold[event-1]);
v[event-1] = (((double)unit-e)*vold[event] + e * vold[event-1]);
num_c++;
}
// Calculate the positions just after collision
for(i=0;i<num_par;i++)
{
// x[i] = x[i] + vold[i] * (tmin - terr);
x[i] = x[i] + vold[i] * (tmin -terr) + 1e-15*(double)(i+1);
y[i]= 200;
vold[i] = v[i];
}
if (x[num_par -1] > (double)L)
{
if ( num_par > 1 )
{
if ( x[num_par-2] < ((double)L - 1e-15))
{
x[num_par -1] = (double)L - 1e-15;
}
else {
x[num_par -1] = (double)L - ((double)L - x[num_par-
2])/(double)two;
}
}
else {
x[num_par -1] = (double)L - 1e-15;
}
v[num_par-1] = - Math.random()* max_v;
vold[num_par-1] = v[num_par-1];
}
}
repaint();
try {Thread.sleep(pause);} catch (InterruptedException e){};
}
}
public void init()
{
int i;
flag =0;
num_c=0;
x=new double[20];
y=new double[20];
v=new double[20];
vold = new double[20];
t = new double[20];
for(i=0;i<num_par;i++)
{
x[i]=( (double)(i+1) * (double)L / (double)(num_par+unit));
v[i]= ((double)unit/(double)two - Math.random())*max_v;
y[i]= 200;
}
// Load images
ball=getImage(getDocumentBase(),"ball.gif");
// Add tracker to see if images loaded
tracker = new MediaTracker(this);
tracker.addImage(ball,0);
}
public void start()
{
if(kicker == null)
{
kicker = new Thread(this);
kicker.start();
}
}
public void stop()
{
kicker = null;
}
public boolean mouseDown(Event evt, int x, int y)
{
if(y > 101)
{
if(kicker==null)
start();
else
kicker=null;
}
else if ( y > 40 && y < 70 && x < 90 && x > 40 )
{
// num_c =0;
init();
}
return true;
}
public boolean mouseDrag(Event evt, int x, int y)
{
// Clicked on slidebar, slide it
if(x>450 && x<500 && y>0 && y<101)
{
slide=y;
e=(double)(slide/200.0);
// num_c =0;
}
else if (x > 350 && x < 380 && y >0 && y < 101) {
slide2 = y;
num_par = (int)(110 - y)/10;
num_c =0;
L = 520 - offset * num_par;
init();
}
return true;
}
public final synchronized void update(Graphics g)
{
String str;
int i;
if(screen == null)
{
screen = createImage(520,300);
img = screen.getGraphics();
}
// Fill black background
img.setColor(Color.black);
img.fillRect(0,100,520,199);
// Fill white background
img.setColor(Color.white);
img.fillRect(0,0,520,99);
// Fill blue top bar
img.setColor(Color.blue);
img.fillRect(0,0,300,10);
// Fill bar for r
img.setColor(Color.red);
img.fillRect(450,0,30,100);
img.fillRect(40,40,50,30);
img.setColor(Color.lightGray);
img.fillRect(350,0,30,100);
img.setColor(Color.black);
img.drawRect(450,0,30,100);
img.drawRect(350,0,30,100);
img.drawRect(40,40,50,30);
if(tracker.statusID(0,true)!=MediaTracker.COMPLETE)
{
img.drawString("Please Wait Loading Graphics",20,160);
}
else
{
// print the inelastic value to screen
r = 1.0 - e * 2.0 ;
img.drawString("r = "+r,399,49);
img.drawString("N = "+num_par,299,49);
img.drawString("Max = 1",400,10);
img.drawString("Min = 0",400,90);
img.setColor(Color.white);
img.drawString("Number of Collisions = "+num_c,149,149);
img.drawString("v_0 = "+v[0],20,279);
img.drawString("v_N = "+v[num_par-1],280,279);
img.drawString("Reset",45,59);
img.setColor(Color.black);
for(i=0;i<num_par;i++)
{
int xx = (int)x[i] + i*offset;
int yy = (int)y[i];
img.drawImage(ball,xx,yy,this);
}
img.drawRect(448, slide, 34, 2);
img.drawRect(348, slide2, 34, 2);
}
paint(img);
g.drawImage(screen,0,0,null);
}
}