// http://www.cs.unc.edu/~andrewz/comp203/hw1/index.html /* g++ gravitytest1.cpp ./a.out > gravitytest1.out gnuplot gnuplot> set yrange[-1:7]; gnuplot> set xrange[-1:7]; gnuplot> plot 'gravitytest1.out' using 1:2, 'gravitytest1.out' using 3:4, \ > 'gravitytest1.out' using 5:6; */ #include #include #include #include //#define NUM_PARTICLES 1000 //#define NUM_ITERATIONS 300 #define NUM_PARTICLES 3 #define NUM_ITERATIONS 100 typedef struct _particle { double m; // particle mass double x; // x-coordinate double y; // y-coordinate double vx; // x-velocity double vy; // y-velocity double fx; // force accumulation on x double fy; // force accumulation on y } particle; class NbodyParticleSystem { public: particle *P; // Dynamic array of particles double G; // Gravity constant int numParticles; // Current number of particles in array NbodyParticleSystem(int n) : numParticles(n) { P = new particle[n]; } ~NbodyParticleSystem() { delete[] P; } void UpdateSystemFast(double dt); // Delta t void UpdateSystemSlow(double dt); // Delta t void InitializeSystem(int config); // Setup the particles int CheckMomentum(); // Momentum of the System ~= 0 }; /*********************************************************************/ /** Andrew Zaferakis **/ /** UNC Chapel Hill **/ /** COMP 203 Spring 2000 **/ /** Programming Homework 1 **/ /** N-body particle system **/ /** File: nbody_particle.cpp **/ /*********************************************************************/ #define PI 3.1415927 #define G 6.673E-11 #define EPSILON 0.0001 #define cube(a) a*a*a #define square(a) a*a void NbodyParticleSystem::UpdateSystemFast(double dt) { double xdist, ydist, delta_vx, delta_vy, scalar; for (int i = 0; i < numParticles; i++) P[i].fx = P[i].fy = 0; for (int i = 0; i < numParticles; i++) { for (int j = i+1; j < numParticles; j++) { xdist = P[j].x - P[i].x; ydist = P[j].y - P[i].y; scalar = G * P[i].m * P[j].m / (cube(sqrt(square(xdist) + square(ydist))) + EPSILON); P[i].fx += scalar * xdist; P[i].fy += scalar * ydist; P[j].fx -= scalar * xdist; // must reverse the subtraction for jth P[j].fy -= scalar * ydist; } } for (int i = 0; i < numParticles; i++) { delta_vx = P[i].fx * dt / P[i].m; // Finalize the ith body, not the jth delta_vy = P[i].fy * dt / P[i].m; P[i].x += (P[i].vx + delta_vx / 2) * dt; P[i].y += (P[i].vy + delta_vy / 2) * dt; P[i].vx += delta_vx; P[i].vy += delta_vy; } } void NbodyParticleSystem::UpdateSystemSlow(double dt) { double xdist, ydist, delta_vx, delta_vy, scalar; for (int i = 0; i < numParticles; i++) { P[i].fx = P[i].fy = 0; for (int j = 0; j < numParticles; j++) { xdist = P[j].x - P[i].x; ydist = P[j].y - P[i].y; scalar = G * P[i].m * P[j].m / (cube(sqrt(square(xdist) + square(ydist))) + EPSILON); P[i].fx += scalar * xdist; P[i].fy += scalar * ydist; } } for (int i = 0; i < numParticles; i++) { delta_vx = P[i].fx * dt / P[i].m; delta_vy = P[i].fy * dt / P[i].m; P[i].x += (P[i].vx + delta_vx / 2) * dt; P[i].y += (P[i].vy + delta_vy / 2) * dt; P[i].vx += delta_vx; P[i].vy += delta_vy; printf("\t%f\t%f", P[i].x, P[i].y); } printf("\n"); } void NbodyParticleSystem::InitializeSystem(int config) { int i; double tmp; if (config == 1) for (i = 0; i < numParticles; i++) { P[i].m = 1.0; P[i].x = P[i].y = ((double)i) / ((double)numParticles); P[i].vx = P[i].vy = P[i].fx = P[i].fy = 0; } else if (config == 2) for (i = 0; i < numParticles; i++) { tmp = ((double)i) / ((double)numParticles); P[i].m = ((double)(numParticles - i))/ ((double)numParticles); P[i].x = 0.5 * (1 + tmp) * cos(2*PI*tmp); P[i].y = 0.5 * (1 + tmp) * sin(2*PI*tmp); P[i].vx = P[i].vy = P[i].fx = P[i].fy = 0; } P[0].m = 100000000; P[0].x = 0.0; P[0].y = 0.0; P[0].vx = 0.0; P[0].vy = 0.0; P[1].m = 100000000; P[1].x = 5.0; P[1].y = 0.0; P[1].vx = 0.0; P[1].vy = 0.0; P[2].m = 100000000; P[2].x = 2.5; P[2].y = 4.33; P[2].vx = 0.0; P[2].vy = 0.0; } int NbodyParticleSystem::CheckMomentum() { double momentum_x = 0; double momentum_y = 0; for (int i = 0; i < numParticles; i++) { momentum_x += P[i].m * P[i].vx; momentum_y += P[i].m * P[i].vy; } return ((momentum_x <= 0.01) && (momentum_x >= -0.01) && \ (momentum_y <= 0.01) && (momentum_y >= -0.01)) ? 1 : 0; } /*********************************************************************/ /** Main **/ /*********************************************************************/ int main(int argc, char *argv[]) { NbodyParticleSystem p(NUM_PARTICLES); p.InitializeSystem(2); // Check the system and report what we find fprintf(stderr, "Initializing: Particles = %d\n", NUM_PARTICLES); fprintf(stderr, " N-body using %i bodies and %i iterations of timestep 1\n", NUM_PARTICLES, NUM_ITERATIONS); // Begin the timetrials! fprintf(stderr, "Starting: Number of Iterations = %i\n", NUM_ITERATIONS); for (int i = 0; i < NUM_ITERATIONS; i++) p.UpdateSystemSlow(1); }