int main(int argc, char *argv[]) { struct particle **arr; int dimensions = 1; float step = 0.1; int num_particles = 2; int num_iterations = 10; int threads = 1; if(argc < 4) { fprintf(stderr,"Usage ./particle_simulator #of_particles #of_iterations threads [one_dim / two_dim](default: one_dim)\n"); //return 1; } else { num_particles = strtoll(argv[1],NULL,10); num_iterations = strtoll(argv[2],NULL,10); threads = strtoll(argv[3],NULL,10); } if(argc > 4 && strcmp(argv[4],"two_dim") == 0) dimensions = 2; arr = generate_particles(num_particles); int i, j; //printf("Iteration, ParticleID, ParticleX, ParticleY\n"); //print_particles(num_particles,arr,0); omp_set_num_threads(threads); for(i = 1; i <= num_iterations; i++) { #pragma omp parallel for for(j = 0; j < num_particles; j++) { calculate_acceleration(arr[j],num_particles,arr,dimensions); } for(j = 0; j < num_particles; j++) { update_vel_position(arr[j],step); } //print_particles(num_particles,arr,i); } free_particles(num_particles,arr); }
/** * Solves the system of ordinary differential equations governing Tux's * movement. Based on Matlab's ode23.m, (c) The MathWorks, Inc. */ static void solve_ode_system(Player& plyr, float timestep) { ODESolver x, y, z, vx, vy, vz; // estimates of derivs bool done = false; float speed; float pos_err[3], vel_err[3], tot_pos_err, tot_vel_err; float err=0, tol=0; int i; // Select an initial time step float h = ode_time_step; if(h < 0){ h = adjust_time_step_size( timestep, plyr.vel ); } float t0 = 0; float tfinal = timestep; float t = t0; // initialize state ppogl::Vec3d new_pos = plyr.pos; ppogl::Vec3d new_vel = plyr.vel; ppogl::Vec3d new_f = plyr.net_force; // loop until we've integrated from t0 to tfinal while (!done) { if ( t >= tfinal ) { PP_WARNING( "t >= tfinal in solve_ode_system()" ); break; } // extend h by up to 10% to reach tfinal if ( 1.1 * h > tfinal - t ) { h = tfinal-t; PP_ASSERT( h >= 0., "integrated past tfinal" ); done = true; } PP_LOG( DEBUG_ODE, "h: " << h ); ppogl::Vec3d saved_pos = new_pos; ppogl::Vec3d saved_vel = new_vel; ppogl::Vec3d saved_f = new_f; // Loop until error is acceptable bool failed = false; for(;;){ // Store initial conditions x.initODEData(new_pos.x(), h); y.initODEData(new_pos.y(), h); z.initODEData(new_pos.z(), h); vx.initODEData(new_vel.x(), h); vy.initODEData(new_vel.y(), h); vz.initODEData(new_vel.z(), h); // We assume that the first estimate in all ODE solvers is equal // to the final value of the last iteration x.updateEstimate(0, new_vel.x()); y.updateEstimate(0, new_vel.y()); z.updateEstimate(0, new_vel.z()); vx.updateEstimate(0, new_f.x() / TUX_MASS); vy.updateEstimate(0, new_f.y() / TUX_MASS); vz.updateEstimate(0, new_f.z() / TUX_MASS); // Update remaining estimates for ( i=1; i < ODESolver::numEstimates(); i++ ) { new_pos.x() = x.nextVal(i); new_pos.y() = y.nextVal(i); new_pos.z() = z.nextVal(i); new_vel.x() = vx.nextVal(i); new_vel.y() = vy.nextVal(i); new_vel.z() = vz.nextVal(i); x.updateEstimate(i, new_vel.x()); y.updateEstimate(i, new_vel.y()); z.updateEstimate(i, new_vel.z()); new_f = calc_net_force( plyr, new_pos, new_vel ); vx.updateEstimate(i, new_f.x() / TUX_MASS); vy.updateEstimate(i, new_f.y() / TUX_MASS); vz.updateEstimate(i, new_f.z() / TUX_MASS); } // Get final values new_pos.x() = x.finalEstimate(); new_pos.y() = y.finalEstimate(); new_pos.z() = z.finalEstimate(); new_vel.x() = vx.finalEstimate(); new_vel.y() = vy.finalEstimate(); new_vel.z() = vz.finalEstimate(); // Calculate the error pos_err[0] = x.estimateError(); pos_err[1] = y.estimateError(); pos_err[2] = z.estimateError(); vel_err[0] = vx.estimateError(); vel_err[1] = vy.estimateError(); vel_err[2] = vz.estimateError(); tot_pos_err = 0.; tot_vel_err = 0.; for ( i=0; i<3; i++ ) { pos_err[i] *= pos_err[i]; tot_pos_err += pos_err[i]; vel_err[i] *= vel_err[i]; tot_vel_err += vel_err[i]; } tot_pos_err = sqrt( tot_pos_err ); tot_vel_err = sqrt( tot_vel_err ); PP_LOG(DEBUG_ODE, "pos_err: " << tot_pos_err << ", vel_err: " << tot_vel_err ); if ( tot_pos_err / MAX_POSITION_ERROR > tot_vel_err / MAX_VELOCITY_ERROR ) { err = tot_pos_err; tol = MAX_POSITION_ERROR; } else { err = tot_vel_err; tol = MAX_VELOCITY_ERROR; } // Update h based on error if ( err > tol && h > MIN_TIME_STEP + EPS ) { done = false; if ( !failed ) { failed = true; h *= MAX( 0.5, 0.8 * pow( tol/err, float(ODESolver::timeStepExponent()) ) ); } else { h *= 0.5; } h = adjust_time_step_size( h, saved_vel ); new_pos = saved_pos; new_vel = saved_vel; new_f = saved_f; } else { // Error is acceptable or h is at its minimum; stop break; } } // Update time t = t + h; ppogl::Vec3d tmp_vel = new_vel; speed = tmp_vel.normalize(); // only generate particles if we're drawing them if(GameConfig::drawParticles){ generate_particles( plyr, h, new_pos, speed ); } // Calculate the final net force new_f = calc_net_force( plyr, new_pos, new_vel ); // If no failures, compute a new h if(!failed){ double temp = 1.25 * pow(double(err) / tol,double(ODESolver::timeStepExponent())); if ( temp > 0.2 ) { h = h / temp; } else { h = 5.0 * h; } } // Clamp h to constraints h = adjust_time_step_size( h, new_vel ); // Important: to make trees "solid", we must manipulate the // velocity here; if we don't and Tux is moving very quickly, // he can pass through trees adjust_for_model_collision(plyr, new_pos, new_vel); // Try to collect items here check_item_collection( plyr, new_pos ); } // Save time step for next time ode_time_step = h; plyr.vel = new_vel; plyr.pos = new_pos; plyr.net_force = new_f; }