Main Page   Class Hierarchy   Data Structures   File List   Data Fields   Globals  

low_n_evolve.C

Go to the documentation of this file.
00001 
00017 
00018 #include "sdyn.h"
00019 
00020 #ifndef TOOLBOX
00021 
00022 void predict_step(sdyn * b,          // n-body system pointer
00023                   real dt)         // timestep
00024     {
00025     if(b->get_oldest_daughter() !=NULL)
00026         for_all_daughters(sdyn, b, bb)
00027             predict_step(bb,dt);
00028     else
00029         b->taylor_pred_new_pos_and_vel(dt);
00030     }
00031 
00032 void correct_step(sdyn * b,          // n-body system pointer
00033                   real new_dt,       // new timestep
00034                   real prev_new_dt)  // previous new timestep
00035     {
00036     if(b->get_oldest_daughter() !=NULL)
00037         for_all_daughters(sdyn, b, bb)
00038             correct_step(bb, new_dt, prev_new_dt);
00039     else
00040         {
00041         b->correct_new_acc_and_jerk(new_dt, prev_new_dt);
00042         b->correct_new_pos_and_vel(new_dt);
00043         }
00044     }
00045 
00046 typedef  real  (*tfp)(sdyn *, real);
00047 
00048 void step(sdyn * b,        // sdyn array                   
00049           real & t,        // time                         
00050           real eps,        // softening length             
00051           real eta,        // time step parameter
00052           real dt,         // time step of the integration 
00053           real max_dt,     // maximum time step (till end of the integration)
00054           int & end_flag,  // to flag that integration end is reached
00055           int & coll_flag,  // to flag that collision has occured
00056           tfp the_tfp,     // timestep function pointer
00057           int n_iter,      // number of iterations
00058           int x_flag,      // exact-time termination flag
00059           int s_flag)      // symmetric timestep ?
00060 {
00061     int collision_flag = 0;
00062 
00063     predict_step(b, dt);
00064 
00065     real new_dt = dt;
00066     for (int i = 0; i <= n_iter; i++) {
00067 
00068         real prev_new_dt = new_dt;
00069         b->calculate_new_acc_and_jerk_from_new(b, eps*eps, n_iter - i,  // hack
00070                                                collision_flag);
00071         if (i < n_iter && s_flag) {
00072 
00073             real end_point_dt = the_tfp(b, eta);
00074 
00075             new_dt = 0.5 * (dt + end_point_dt);
00076             new_dt = dt + 0.5 * (end_point_dt - dt) * (new_dt/prev_new_dt);
00077 
00078             if (x_flag) {
00079 
00080                 if (new_dt >= max_dt) {
00081                     end_flag = 1;
00082                     new_dt = max_dt;
00083                 } else
00084                     end_flag = 0;
00085             }
00086         }
00087         correct_step(b, new_dt, prev_new_dt);
00088     }
00089 
00090     for_all_daughters(sdyn, b, bb) bb->store_new_into_old();
00091     t += new_dt;
00092 
00093     if (collision_flag) end_flag = 1;
00094     coll_flag = collision_flag;
00095 }
00096 
00097 void initialize(sdyn * b,        // sdyn array                   
00098                 real eps)        // softening length             
00099 {
00100     predict_step(b, 0);
00101 
00102     int collision_flag;
00103     b->calculate_new_acc_and_jerk_from_new(b, eps*eps, 1, collision_flag);
00104 
00105     for_all_daughters(sdyn, b, bb) bb->store_new_into_old();
00106 }
00107 
00108 real  constant_timestep(sdyn * b, real eta)
00109 {
00110     if (b == NULL) eta = 0; // To keep the HP compiler happy.
00111     return  eta;
00112 }
00113 
00114 real  dynamic_timestep(sdyn * b, real eta)
00115     {
00116     real global_min_encounter_time_sq = VERY_LARGE_NUMBER;
00117     real global_min_free_fall_time_sq = VERY_LARGE_NUMBER;
00118 
00119     for_all_daughters(sdyn, b, bb)
00120         {
00121         global_min_encounter_time_sq =
00122             min(global_min_encounter_time_sq, bb->get_min_encounter_time_sq());
00123         global_min_free_fall_time_sq =
00124             min(global_min_free_fall_time_sq, bb->get_min_free_fall_time_sq());
00125         }
00126 
00127     return  eta *
00128         sqrt(min(global_min_encounter_time_sq, global_min_free_fall_time_sq));
00129     }
00130 
00131 tfp timestep_function_ptr(char * timestep_name)
00132     {
00133     if (streq(timestep_name, "constant_timestep"))
00134         return constant_timestep;
00135     else if (streq(timestep_name, "dynamic_timestep"))
00136         return dynamic_timestep;
00137     else
00138         {
00139         cerr << "timestep_function_ptr: no timestep function implemented"
00140              << " with name `" << timestep_name << "'" << endl;
00141         exit(1);
00142         }
00143     return NULL; // To keep HP g++ happy!
00144     }
00145 
00146 real calculate_energy(sdyn * b, real & ekin, real & epot)
00147     {
00148     ekin = epot = 0;
00149     for_all_daughters(sdyn, b, bb)
00150         {
00151         epot += bb->get_mass() * bb->get_pot();
00152         ekin += 0.5 * bb->get_mass() * (bb->get_vel() * bb->get_vel());
00153         }
00154     epot *= 0.5;
00155 
00156     return ekin + epot;
00157     }
00158 
00159 real calculate_energy_from_scratch(sdyn * b, real & ekin, real & epot)
00160 {
00161     ekin = epot = 0;
00162 
00163     for_all_daughters(sdyn, b, bi) {
00164         ekin += bi->get_mass() * bi->get_vel() * bi->get_vel();
00165         real depot = 0;
00166         for (sdyn* bj = bi->get_younger_sister(); bj != NULL;
00167              bj = bj->get_younger_sister())
00168             depot -= bj->get_mass() / abs(bi->get_pos() - bj->get_pos());
00169         epot += bi->get_mass() * depot;
00170     }
00171     ekin *= 0.5;
00172 
00173     return ekin + epot;
00174 }
00175 
00176 void  start_up(sdyn * b, real & n_steps)
00177     {
00178     if(b->get_oldest_daughter() !=NULL)
00179         {
00180         n_steps = b->get_n_steps();
00181         if (n_steps == 0)
00182             b->prepare_root();
00183 
00184         for_all_daughters(sdyn, b, bb)
00185             start_up(bb, n_steps);
00186         }
00187     else
00188         {
00189         if (n_steps == 0)
00190             b->prepare_branch();
00191         }
00192     }
00193 
00194 void  clean_up(sdyn * b, real n)
00195     {
00196     b->set_n_steps(n);
00197     }
00198 
00199 // system_in_cube: return TRUE if most of the (top-level) nodes in the
00200 //                 system are contained within the specified cube.
00201 
00202 #define MOST 0.75
00203 
00204 local bool system_in_cube(sdyn* b, real cube_size) {
00205 
00206     int n = 0;
00207     for_all_daughters(sdyn, b, bi) n++;
00208 
00209     int n_in = 0;
00210     for_all_daughters(sdyn, b, bb) {
00211         int in = 1;
00212         for (int k = 0; k < 3; k++)
00213             if (abs(bb->get_pos()[k]) > cube_size) in = 0;
00214         n_in += in;
00215     }
00216 
00217     if (n_in >= MOST * n)
00218         return TRUE;
00219     else
00220         return FALSE;
00221 }
00222 
00223 local void copy_node_partial(sdyn*b, sdyn* c)
00224 {
00225     c->set_index(b->get_index());
00226     c->set_mass(b->get_mass());
00227     c->set_time(b->get_time());
00228     c->set_pos(b->get_pos());
00229     c->set_vel(b->get_vel());
00230 }
00231 
00232 local sdyn* copy_flat_tree(sdyn* b)
00233 // Make a partial copy of the flat tree with b as root, and return a
00234 // pointer to it.  Intention is for use with xstarplot, so only 
00235 // copy pointers, index, mass, time, pos, and vel.
00236 {
00237     sdyn* root = new sdyn;
00238 
00239     root->set_parent(NULL);
00240     root->set_elder_sister(NULL);
00241     root->set_younger_sister(NULL);
00242     copy_node_partial(b, root);
00243 
00244     sdyn* s = NULL;
00245     for_all_daughters(sdyn, b, bi) {
00246         sdyn* ci = new sdyn;
00247         ci->set_parent(root);
00248         ci->set_oldest_daughter(NULL);
00249         ci->set_younger_sister(NULL);
00250         ci->set_elder_sister(s);
00251         if (s)
00252             s->set_younger_sister(ci);
00253         else
00254             root->set_oldest_daughter(ci);
00255         copy_node_partial(bi, ci);
00256         s = ci;
00257     }
00258 
00259     return root;
00260 }
00261 
00262 local void delete_node(sdyn* b)
00263 // Recursively delete node b and its descendents.
00264 {
00265     sdyn* bi = b->get_oldest_daughter();
00266     while (bi) {
00267         sdyn* tmp = bi->get_younger_sister();
00268         delete_node(bi);
00269         bi = tmp;
00270     }
00271     delete b;
00272 }
00273 
00274 // pp: Recursively pretty-print a node:
00275 
00276 void pp(sdyn* b, ostream & s, int level = 0) {
00277 
00278     s.precision(4);
00279 
00280     for (int i = 0; i < 2*level; i++) s << " ";
00281 
00282     b->pretty_print_node(s);
00283     s << " \t"<< b->get_mass() << " \t"
00284       << b->get_pos() << "   "
00285       << b->get_vel() <<endl;
00286 
00287     for_all_daughters(sdyn, b, daughter) pp(daughter, s, level + 1);    
00288 }
00289 
00290 
00291 #define N_STEP_CHECK 1000 // Interval for checking CPU time
00292 
00293 bool low_n_evolve(sdyn * b,       // sdyn array
00294                   real delta_t,   // time span of the integration
00295                   real dt_out,    // output time interval
00296                   real dt_snap,   // snapshot output interval
00297                   real snap_cube_size,
00298                   real eps,       // softening length 
00299                   real eta,       // time step parameter
00300                   int x_flag,     // exact-time termination flag
00301                   char * timestep_name,
00302                   int s_flag,     // symmetric timestep ?
00303                   int n_iter,     // number of iterations
00304                   real n_max,     // if > 0: max. number of integration steps
00305                   real cpu_time_check,
00306                   real dt_print,  // external print interval
00307                   sdyn_print_fp   // pointer to external print function
00308                        print)
00309     {
00310 
00311     bool terminate = false;
00312 
00313     real t = b->get_time();
00314     real tr = t + (real)b->get_time_offset();  // total real time in N-body units
00315 
00316     real t_end = t + delta_t;      // final time, at the end of the integration
00317     real t_out = t + dt_out;       // time of next diagnostic output
00318     real t_snap = t + dt_snap;     // time of next snapshot;
00319     real t_print = t + dt_print;   // time of next printout;
00320 
00321     real n_steps;
00322     int count_steps = 0;
00323     real cpu_init = cpu_time();
00324     real cpu_save = cpu_init;
00325 
00326     tfp  the_tfp = timestep_function_ptr(timestep_name);
00327 
00328     start_up(b, n_steps);
00329     initialize(b, eps);
00330 
00331     cerr.precision(16);
00332 
00333     real ekin, epot;
00334     calculate_energy(b, ekin, epot);
00335 
00336     if (t_out <= t_end && n_steps == 0)
00337         {
00338           cerr << "Time = " << t << " " << tr << "  n_steps = " << n_steps
00339             << "  Etot = " << ekin + epot << endl;
00340         }
00341 
00342     if (b->get_n_steps() == 0)             // should be better interfaced
00343         {                                  // with start_up ; to be done
00344         b->set_e_tot_init(ekin + epot);
00345         b->clear_de_tot_abs_max();
00346         }
00347 
00348     int end_flag = 0;
00349     int coll_flag = 0;
00350     while (t < t_end && !end_flag)
00351         {
00352         real max_dt = t_end - t;
00353         real dt = the_tfp(b, eta);
00354 
00355         end_flag = 0;
00356         if (dt > max_dt && x_flag)
00357             {
00358             end_flag = 1;
00359             dt = max_dt;
00360             }
00361 
00362         step(b, t, eps, eta, dt, max_dt, end_flag, coll_flag, 
00363              the_tfp, n_iter,
00364              x_flag, s_flag);
00365         b->set_time(t);                  // should be prettified some time soon
00366         for_all_daughters(sdyn, b, bi)
00367             bi->set_time(t);
00368 
00369         n_steps += 1;
00370         count_steps++;
00371 
00372         if(coll_flag>=1) {
00373           //cerr << "Collision has occured: " << coll_flag << endl;
00374           terminate = false;
00375           return terminate;
00376         }
00377 
00378 //      Check for (trivial) output to cerr...
00379 
00380         if (t >= t_out && n_steps==0)
00381             {
00382             calculate_energy(b, ekin, epot);
00383             cerr << "Time = " << t << " " << tr << "  n_steps = " << n_steps
00384                  << "  Etot = " << ekin + epot << endl;
00385             t_out += dt_out;
00386             }
00387 
00388 //      ...and (not-so-trivial) output handled elsewhere.
00389 
00390         if (t >= t_print && print != NULL) 
00391             {
00392             (*print)(b);
00393             t_print += dt_print;
00394             }
00395 
00396 //      Output a snapshot to cout at the scheduled time.
00397 
00398         if(n_max > 0 && n_steps >= n_max)
00399             end_flag = 1;
00400 
00401         if (t >= t_snap && system_in_cube(b, snap_cube_size)) {
00402 
00403             // Looks like we can't just make a tree and flatten it
00404             // again before continuing--better to work with a copy.
00405 
00406 /*          sdyn* c = copy_flat_tree(b);
00407 
00408             bool dynamics = FALSE;
00409             bool stability = FALSE;
00410             int k_max = 2;
00411             make_tree(c, dynamics, stability, k_max, 0);
00412             put_node(cout, *c);
00413             delete_node(c);
00414 */
00415             put_node(cout, *b);
00416 
00417             cout << flush; 
00418             t_snap += dt_snap;
00419         }
00420 
00421         // Check the number of steps and the CPU time every N_STEP_CHECK steps.
00422         // Note that the printed CPU time is the time since this routine was
00423         // entered.
00424 
00425         if (count_steps >= N_STEP_CHECK) {
00426             count_steps = 0;
00427 
00428             // added (SPZ: 12 Oct 2000)
00429             if (b->get_n_steps() > MAX_N_STEPS) {
00430               //return;
00431               cerr << "Terminate after " << b->get_n_steps() 
00432                    << " steps" << endl;
00433               terminate = true;
00434               }
00435 
00436             if (cpu_time() - cpu_save > abs(cpu_time_check)) {
00437                 cpu_save = cpu_time();
00438                 calculate_energy(b, ekin, epot);
00439                 cerr.precision(6);
00440                 cerr << "low_n3_evolve:  CPU time = " << cpu_save - cpu_init;
00441                 cerr.precision(13);
00442                 cerr << "  time = " << t;
00443                 cerr.precision(6);
00444                 cerr << "  offset = " << b->get_time_offset() << endl;
00445                 cerr << "                n_steps = " << n_steps
00446                      << "  Etot = " << ekin + epot
00447                      << "  dt = " << dt
00448                      << endl << flush;
00449 
00450                 if (cpu_time_check < 0) return terminate;
00451 
00452                 }
00453             }
00454         }
00455  
00456    clean_up(b, n_steps);       // too late for snapshot?
00457 
00458     return terminate;
00459 
00460     }
00461 
00462 #else
00463 
00464 main(int argc, char **argv)
00465 {
00466     sdyn* b;             // pointer to the nbody system
00467     int   n_iter = 1;    // number of iterations (0: explicit; >=1: implicit)
00468     real  n_max = -1;    // if > 0: maximum number of integration steps
00469     
00470     real  delta_t = 10;   // time span of the integration
00471     real  eta = 0.02;    // time step parameter (for fixed time step,
00472                          //   equal to the time step size; for variable
00473                          //   time step, a multiplication factor)
00474     real  dt_out = VERY_LARGE_NUMBER;
00475                          // output time interval
00476     real  dt_snap = VERY_LARGE_NUMBER;
00477                          // snap output interval
00478     real snap_cube_size = 10;
00479 
00480     real  cpu_time_check = 3600;
00481 
00482     real  eps = 0.0;     // softening length               
00483     char  *timestep_name = "dynamic_timestep";
00484 
00485     bool  a_flag = FALSE;
00486     bool  d_flag = FALSE;
00487     bool  D_flag = FALSE;
00488     bool  e_flag = FALSE;
00489     bool  f_flag = FALSE;
00490     bool  n_flag = FALSE;
00491     bool  q_flag = FALSE;
00492     bool  r_flag = FALSE;
00493     bool  s_flag = TRUE;    // symmetric timestep ?
00494     bool  t_flag = FALSE;
00495     bool  x_flag = TRUE;    // if true: termination at the exact time of
00496                             //          of the final output, by
00497                             //          adjustment of the last time step;
00498                             // if false: no adjustment of the last time step,
00499                             //           as a consequence the time of final
00500                             //           output might be slightly later than
00501                             //           the time specified.
00502     bool  z_flag = FALSE;     // to specify termination after n_max steps
00503 
00504     check_help();
00505 
00506     extern char *poptarg;
00507     int c;
00508     char* param_string = "A:c:C:d:D:e:f:n:qr:st:xz:";
00509 
00510     while ((c = pgetopt(argc, argv, param_string)) != -1)
00511         switch(c)
00512             {
00513             case 'A': a_flag = TRUE;
00514                       eta = atof(poptarg);
00515                       break;
00516             case 'c': cpu_time_check = atof(poptarg);
00517                       break;
00518             case 'C': snap_cube_size = atof(poptarg);
00519                       break;
00520             case 'd': d_flag = TRUE;
00521                       dt_out = atof(poptarg);
00522                       break;
00523             case 'D': D_flag = TRUE;
00524                       dt_snap = atof(poptarg);
00525                       break;
00526             case 'e': e_flag = TRUE;
00527                       eps = atof(poptarg);
00528                       break;
00529             case 'f': f_flag = TRUE;
00530                       timestep_name = poptarg;
00531                       break;
00532             case 'n': n_flag = TRUE;
00533                       n_iter = atoi(poptarg);
00534                       break;
00535             case 'q': q_flag = TRUE;
00536                       break;
00537             case 's': s_flag = FALSE;
00538                       break;
00539             case 't': t_flag = TRUE;
00540                       delta_t = atof(poptarg);
00541                       break;
00542             case 'x': x_flag = FALSE;
00543                       break;
00544             case 'z': z_flag = TRUE;
00545                       n_max = atof(poptarg);
00546                       break;
00547             case '?': params_to_usage(cerr, argv[0], param_string);
00548                       get_help();
00549             }            
00550 
00551     if (!q_flag) {
00552 
00553         // Check input arguments and echo defaults.
00554 
00555         if (!t_flag) cerr << "default delta_t = " << delta_t << "\n";
00556         if (!a_flag) cerr << "default eta = " << eta << "\n";
00557         if (!d_flag) cerr << "default dt_out = " << dt_out << "\n";
00558         if (!e_flag) cerr << "default eps = " << eps << "\n";
00559         if (!f_flag) cerr << "default timestep_name = " << timestep_name
00560                           << "\n";
00561         if (!n_flag) cerr << "default n_iter = " << n_iter << "\n";
00562         if (!s_flag) cerr << "s_flag (symmetric timestep ?) = FALSE" << "\n";
00563         if (x_flag) cerr << "default termination: at exact t_end" << "\n";
00564         if (!z_flag) cerr << "default n_max = " << n_max << "\n";
00565     }
00566 
00567     if (!D_flag) dt_snap = delta_t; // Guarantee output at end
00568 
00569     b = get_sdyn(cin);
00570     b->log_history(argc, argv);
00571 
00572     cpu_init();
00573     low_n_evolve(b, delta_t, dt_out, dt_snap, snap_cube_size,
00574                  eps, eta, x_flag,
00575                  timestep_name, s_flag, n_iter, n_max,
00576                  cpu_time_check);
00577 
00578 }
00579 
00580 #endif

Generated at Sun Feb 24 09:57:07 2002 for STARLAB by doxygen1.2.6 written by Dimitri van Heesch, © 1997-2001