00001
00002
00003
00004
00005 #include "sdyn.h"
00006
00007 void predict_step(sdyn * b,
00008 real dt)
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,
00018 real new_dt,
00019 real prev_new_dt)
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,
00034 real & t,
00035 real eps,
00036 real eta,
00037 real & dt,
00038 real max_dt,
00039 real dt_old,
00040 int & end_flag,
00041 tfp the_tfp,
00042 int n_iter,
00043 int x_flag,
00044 int s_flag)
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,
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
00069 real new_dt_piet = dt + 0.5 * (end_point_dt - dt) * (new_dt/prev_new_dt);
00070
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,
00093 real eps)
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;
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;
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
00195
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
00229
00230
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
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
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,
00290 real delta_t,
00291 real dt_out,
00292 real dt_snap,
00293 real snap_cube_size,
00294 real eps,
00295 real eta,
00296 int x_flag,
00297 char * timestep_name,
00298 int s_flag,
00299 int n_iter,
00300 real n_max,
00301 real cpu_time_check,
00302 real dt_print,
00303 sdyn_print_fp
00304 print)
00305 {
00306 real t = b->get_time();
00307
00308 real t_end = t + delta_t;
00309 real t_out = t + dt_out;
00310 real t_snap = t + dt_snap;
00311 real t_print = t + dt_print;
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) {
00335
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);
00357 for_all_daughters(sdyn, b, bi)
00358 bi->set_time(t);
00359
00360 n_steps += 1;
00361 count_steps++;
00362
00363
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
00373
00374 if (t >= t_print && print != NULL) {
00375 (*print)(b);
00376 t_print += dt_print;
00377 }
00378
00379
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
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398 put_node(cout, *b);
00399
00400 cout << flush;
00401 t_snap += dt_snap;
00402 }
00403
00404
00405
00406
00407
00408 if (count_steps >= N_STEP_CHECK) {
00409 count_steps = 0;
00410
00411
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);
00432 cerr.precision(p);
00433 }
00434
00435 #ifdef TOOLBOX
00436
00437 main(int argc, char **argv)
00438 {
00439 sdyn* b;
00440 int n_iter = 1;
00441 real n_max = -1;
00442
00443 real delta_t = 10;
00444 real eta = 0.02;
00445
00446
00447 real dt_out = VERY_LARGE_NUMBER;
00448
00449 real dt_snap = VERY_LARGE_NUMBER;
00450
00451 real snap_cube_size = 10;
00452
00453 real cpu_time_check = 3600;
00454
00455 real eps = 0.0;
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;
00470 bool t_flag = FALSE;
00471 bool x_flag = TRUE;
00472
00473
00474
00475
00476
00477
00478 bool z_flag = FALSE;
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
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;
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