Main Page   Class Hierarchy   Data Structures   File List   Data Fields   Globals  

test_low_n_evolve.C

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

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