00001
00017
00018 #include "sdyn.h"
00019
00020 #ifndef TOOLBOX
00021
00022 void predict_step(sdyn * b,
00023 real dt)
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,
00033 real new_dt,
00034 real prev_new_dt)
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,
00049 real & t,
00050 real eps,
00051 real eta,
00052 real dt,
00053 real max_dt,
00054 int & end_flag,
00055 int & coll_flag,
00056 tfp the_tfp,
00057 int n_iter,
00058 int x_flag,
00059 int s_flag)
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,
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,
00098 real eps)
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;
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;
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
00200
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
00234
00235
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
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
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,
00294 real delta_t,
00295 real dt_out,
00296 real dt_snap,
00297 real snap_cube_size,
00298 real eps,
00299 real eta,
00300 int x_flag,
00301 char * timestep_name,
00302 int s_flag,
00303 int n_iter,
00304 real n_max,
00305 real cpu_time_check,
00306 real dt_print,
00307 sdyn_print_fp
00308 print)
00309 {
00310
00311 bool terminate = false;
00312
00313 real t = b->get_time();
00314 real tr = t + (real)b->get_time_offset();
00315
00316 real t_end = t + delta_t;
00317 real t_out = t + dt_out;
00318 real t_snap = t + dt_snap;
00319 real t_print = t + dt_print;
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)
00343 {
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);
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
00374 terminate = false;
00375 return terminate;
00376 }
00377
00378
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
00389
00390 if (t >= t_print && print != NULL)
00391 {
00392 (*print)(b);
00393 t_print += dt_print;
00394 }
00395
00396
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
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415 put_node(cout, *b);
00416
00417 cout << flush;
00418 t_snap += dt_snap;
00419 }
00420
00421
00422
00423
00424
00425 if (count_steps >= N_STEP_CHECK) {
00426 count_steps = 0;
00427
00428
00429 if (b->get_n_steps() > MAX_N_STEPS) {
00430
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);
00457
00458 return terminate;
00459
00460 }
00461
00462 #else
00463
00464 main(int argc, char **argv)
00465 {
00466 sdyn* b;
00467 int n_iter = 1;
00468 real n_max = -1;
00469
00470 real delta_t = 10;
00471 real eta = 0.02;
00472
00473
00474 real dt_out = VERY_LARGE_NUMBER;
00475
00476 real dt_snap = VERY_LARGE_NUMBER;
00477
00478 real snap_cube_size = 10;
00479
00480 real cpu_time_check = 3600;
00481
00482 real eps = 0.0;
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;
00494 bool t_flag = FALSE;
00495 bool x_flag = TRUE;
00496
00497
00498
00499
00500
00501
00502 bool z_flag = FALSE;
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
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;
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