package nbody; class Body { float G; int NUMPLANETS; float x, y; float ax, ay; float mass; float radius; array [Body] planets; int myIndex; Semaphore mySem; boolean sticky; constructor(float x_, float y_, float mass_, float radius_, float ax_, float ay_, int index, Semaphore sem) { G = -9.7; NUMPLANETS = 64; sticky = false; x = x_; y = y_; mass = mass_; radius = radius_; ax = ax_; ay = ay_; planets = new Body[NUMPLANETS]; myIndex = index; mySem = sem; } void assignBody( int index, Body partner ) { planets[index] = partner; } void move(){ int size = NUMPLANETS; float dy,dx,rad,g,force,tempx,tempy; x = x + ax; y = y + ay; int jj = 0; while( jj < size ) { if((myIndex != jj)) { Body body = planets[jj]; dx = x - body.x; dy = y - body.y; rad = dx*dx + dy*dy; if(rad <= (radius*radius + body.radius*body.radius)) { if(sticky){ tempy = body.ay; tempx = body.ax; force = body.mass * body.ax; body.ax = body.ax - force / mass; force = body.mass * body.ay; body.ay = body.ay - force / mass; force = mass * tempx; ax = ax - force / body.mass; force = mass * tempy; ay = ay - force / body.mass; } else{ tempy = ay; tempx = ax; force = body.mass * body.ax; ax = ax + force / mass; force = body.mass * body.ay; ay = ay + force / mass; force = mass * tempx; body.ax = body.ax + force / body.mass; force = mass * tempy; body.ay = body.ay + force / body.mass; } } g = G * body.mass / rad; rad = sqrt(rad); ax = ax + g * (dx/rad); ay = ay + g * (dy/rad); } jj = jj + 1; } mySem.signal(); } } class SimEngine { int NUMPLANETS; float xsize; float ysize; float G; array[Body] bodies; array[Semaphore] sem0; array[Semaphore] sem1; array[Semaphore] sem2; array[Semaphore] sem3; array[Semaphore] sem4; array[Semaphore] sem5; int numIter; int iter; constructor() { int i; int j; Semaphore sem; Semaphore semA; Semaphore semB; NUMPLANETS = 64; xsize = 400.0; ysize = 400.0; G = -9.7; numIter = 100; iter = 0; bodies = new Body[NUMPLANETS]; sem0 = new Semaphore[NUMPLANETS/2]; i = 0; while( i < NUMPLANETS ) { sem = new Semaphore(false, this, true); if( i == 20 ) { bodies[i] = new Body(frandom() * xsize, frandom() * ysize, 500.0, 5.0, 0.0, 0.0, i, sem); } else { bodies[i] = new Body(frandom() * xsize, frandom() * ysize, 1.0, 1.0, 0.0001 * G * G, 0.0001 * G * G, i, sem); } i = i + 1; bodies[i] = new Body(frandom() * xsize, frandom() * ysize, 1.0, 0.01, 0.0001 * G * G, 0.0001 * G * G, i, sem); i = i + 1; sem.assignLeaves(bodies[i-2],bodies[i-1]); sem0[i/2 - 1] = sem; } i = 0; while( i < NUMPLANETS ) { j = 0; while( j < NUMPLANETS ) { Body b; b = bodies[i]; b.assignBody(j, bodies[j]); j = j + 1; } i = i + 1; } i = 0; sem1 = new Semaphore[NUMPLANETS/4]; while( i < NUMPLANETS / 2 ) { sem = new Semaphore(false, this, false); semA = sem0[i]; i = i + 1; semB = sem0[i]; i = i + 1; sem.assignChildren(semA, semB); semA.assignParent(sem); semB.assignParent(sem); sem1[i/2 - 1] = sem; } i = 0; sem2 = new Semaphore[NUMPLANETS/8]; while( i < NUMPLANETS / 4 ) { sem = new Semaphore(false, this, false); semA = sem1[i]; i = i + 1; semB = sem1[i]; i = i + 1; sem.assignChildren(semA, semB); semA.assignParent(sem); semB.assignParent(sem); sem2[i/2 - 1] = sem; } i = 0; sem3 = new Semaphore[NUMPLANETS/16]; while( i < NUMPLANETS / 8 ) { sem = new Semaphore(false, this, false); semA = sem2[i]; i = i + 1; semB = sem2[i]; i = i + 1; sem.assignChildren(semA, semB); semA.assignParent(sem); semB.assignParent(sem); sem3[i/2 - 1] = sem; } i = 0; sem4 = new Semaphore[NUMPLANETS/32]; while( i < NUMPLANETS / 16 ) { sem = new Semaphore(false, this, false); semA = sem3[i]; i = i + 1; semB = sem3[i]; i = i + 1; sem.assignChildren(semA, semB); semA.assignParent(sem); semB.assignParent(sem); sem4[i/2 - 1] = sem; } i = 0; sem5 = new Semaphore[NUMPLANETS/64]; while( i < 2 ) { sem = new Semaphore(true, this, false); semA = sem4[i]; i = i + 1; semB = sem4[i]; i = i + 1; sem.assignChildren(semA, semB); semA.assignParent(sem); semB.assignParent(sem); sem5[i/2 - 1] = sem; } } void signal() { if( iter < numIter ) { iter = iter + 1; Semaphore s = sem5[0]; s.go(); } else { prints("done"); } } void step() { iter = numIter; Semaphore s = sem5[0]; s.go(); } void start() { iter = 0; Semaphore s = sem5[0]; s.go(); } } class Semaphore { int semCount; Semaphore parent; boolean top; boolean bottom; SimEngine se; Body child1, child2; Semaphore sem1, sem2; constructor(boolean isTop, SimEngine eng, boolean isBot) { semCount = 0; top = isTop; se = eng; bottom = isBot; } void assignParent( Semaphore par ) { parent = par; } void assignChildren( Semaphore s1, Semaphore s2 ) { sem1 = s1; sem2 = s2; } void assignLeaves( Body c1, Body c2 ) { child1 = c1; child2 = c2; } void go() { if( bottom ) { child1.move(); child2.move(); } else { sem1.go(); sem2.go(); } } void signal() { semCount = semCount + 1; if( semCount == 2 ) { semCount = 0; if( !top ) { parent.signal(); } if( top ) { se.signal(); } } } } float frandom() { return frand(); } void main() { SimEngine se; prints("init nbody..."); se = new SimEngine(); prints("starting nbody..."); se.start(); }