00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00057
00058
00059
00060
00061 #include "scatter3.h"
00062
00063 #ifndef TOOLBOX
00064
00065
00066
00067 #else
00068
00069
00070
00071 #define DEFAULT_A_OUT 10
00072 #define DEFAULT_R_STOP 100
00073
00074 local void make_hier_init(initial_state3 & init)
00075 {
00076 init.m2 = 0.5;
00077 init.m3 = 0.5;
00078 init.r1 = 0;
00079 init.r2 = 0;
00080 init.r3 = 0;
00081
00082 init.sma = 1;
00083 init.ecc = 0;
00084
00085
00086
00087 init.v_inf = 0;
00088 init.rho = 0;
00089
00090 init.a_out = DEFAULT_A_OUT;
00091 init.e_out = 0;
00092 init.r_stop = DEFAULT_R_STOP;
00093
00094 init.tidal_tol_factor = DEFAULT_TIDAL_TOL_FACTOR;
00095 init.eta
00096 = DEFAULT_ETA;
00097
00098 initialize_bodies(init.system);
00099 init.id = get_initial_seed() + get_n_rand();
00100 }
00101
00102
00103
00104 local sdyn3 * init_to_sdyn3(initial_state3 & init)
00105 {
00106 set_kepler_tolerance(2);
00107
00108 kepler k1;
00109
00110 real mean_anomaly = 0;
00111 if (init.ecc == 1)
00112 mean_anomaly = -M_PI;
00113 else
00114 mean_anomaly = randinter(-M_PI, M_PI);
00115
00116 make_standard_kepler(k1, 0, 1, -0.5 / init.sma, init.ecc,
00117 1,
00118 mean_anomaly,
00119 1);
00120
00121 #if 0
00122 cerr << endl << "Inner binary:" << endl;
00123 k1.print_all(cerr);
00124 #endif
00125
00126 if (init.e_out == 1)
00127 err_exit("Linear outer binary not allowed!");
00128
00129 kepler k3;
00130
00131 real m2 = init.m2;
00132 real m3 = init.m3;
00133 real mtotal = 1 + m3;
00134
00135 make_standard_kepler(k3, 0, mtotal, -0.5 * mtotal / init.a_out, init.e_out,
00136 1,
00137 M_PI);
00138 set_orientation(k3, init.phase);
00139
00140 #if 0
00141 cerr << endl << "Outer binary:" << endl << flush;
00142 k3.print_all(cerr);
00143 #endif
00144
00145 sdyn3 * b;
00146 b = set_up_dynamics(m2, m3, k1, k3);
00147
00148
00149
00150 sdyn3 * bb = b->get_oldest_daughter();
00151 bb->set_radius(init.r1);
00152 bb = bb->get_younger_sister();
00153 bb->set_radius(init.r2);
00154 bb = bb->get_younger_sister();
00155 bb->set_radius(init.r3);
00156
00157 return b;
00158 }
00159
00160
00161
00162 local void check_init(initial_state3 & init)
00163 {
00164 if (init.m2 > 1) err_exit("check_init: m1 < 0");
00165 if (init.m2 < 0) err_exit("check_init: m2 < 0");
00166 if (init.m3 < 0) err_exit("check_init: m3 < 0");
00167 if (init.sma <= 0) err_exit("check_init: inner semi-major axis <= 0");
00168 if (init.ecc < 0) err_exit("check_init: inner eccentricity < 0");
00169 if (init.ecc > 1) err_exit("check_init: inner eccentricity > 1");
00170 if (init.a_out <= 0) err_exit("check_init: outer semi-major axis <= 0");
00171 if (init.e_out < 0) err_exit("check_init: outer eccentricity < 0");
00172 if (init.e_out > 1) err_exit("check_init: outer eccentricity > 1");
00173 if (init.r1 < 0) err_exit("check_init: r1 < 0");
00174 if (init.r2 < 0) err_exit("check_init: r2 < 0");
00175 if (init.r3 < 0) err_exit("check_init: r3 < 0");
00176 if (init.eta <= 0) err_exit("check_init: eta <= 0");
00177 }
00178
00179 local void print_elements(sdyn3* b)
00180 {
00181
00182
00183
00184 sdyn3* b1 = b->get_oldest_daughter();
00185 sdyn3* b2 = b1->get_younger_sister();
00186 sdyn3* b3 = b2->get_younger_sister();
00187
00188
00189
00190 sdyn3 cm;
00191 cm.set_mass(b1->get_mass()+b2->get_mass());
00192 cm.set_pos((b1->get_mass()*b1->get_pos()+b2->get_mass()*b2->get_pos())
00193 / cm.get_mass());
00194 cm.set_vel((b1->get_mass()*b1->get_vel()+b2->get_mass()*b2->get_vel())
00195 / cm.get_mass());
00196
00197
00198
00199 kepler k1, k3;
00200 initialize_kepler_from_dyn_pair(k1, b1, b2, true);
00201 initialize_kepler_from_dyn_pair(k3, b3, &cm, true);
00202
00203
00204
00205 cerr << b->get_system_time() << " "
00206 << k1.get_semi_major_axis() << " "
00207 << k3.get_semi_major_axis() << " "
00208 << k1.get_eccentricity() << " "
00209 << k3.get_eccentricity() << " "
00210 << 0.1 * k3.get_periastron() << " "
00211 << 0.1 * k3.get_periastron() / k1.get_apastron() << " "
00212 << endl;
00213 }
00214
00215 #define PERT_TOL 0.5
00216
00217 local real period_ratio(sdyn3* a, sdyn3* b, sdyn3* c, bool debug = false)
00218 {
00219
00220
00221
00222 if (debug) {
00223 cerr << "period_ratio: a = " << a->format_label();
00224 cerr << " b = " << b->format_label();
00225 cerr << " c = " << c->format_label() << endl;
00226 }
00227
00228
00229
00230 real ma = a->get_mass();
00231 real mb = b->get_mass();
00232 real mc = c->get_mass();
00233
00234 real mab = ma + mb;
00235 vector rab = b->get_pos() - a->get_pos();
00236 vector vab = b->get_vel() - a->get_vel();
00237
00238 real dab = abs(rab);
00239 real eab = 0.5*square(vab) - mab/dab;
00240 if (debug) {
00241 PRI(4); PRC(dab); PRC(eab);
00242 }
00243
00244 if (eab >= 0) {
00245 if (debug) cerr << endl;
00246 return 0;
00247 }
00248
00249
00250
00251
00252
00253 vector cmpos = (ma*a->get_pos() + mb*b->get_pos()) / mab;
00254 vector cmvel = (ma*a->get_vel() + mb*b->get_vel()) / mab;
00255
00256 real mabc = mab + mc;
00257 vector rc = c->get_pos() - cmpos;
00258 vector vc = c->get_vel() - cmvel;
00259
00260
00261
00262 real dc = abs(rc);
00263
00264
00265
00266 if (mc*dab*dab*dab > PERT_TOL*mab*dc*dc*dc) return 0;
00267
00268 real ec = 0.5*square(vc) - mabc/dc;
00269 if (debug) {
00270 PRC(abs(rc)), PRL(ec);
00271 }
00272
00273 if (ec >= 0) return 0;
00274
00275
00276
00277
00278 real ee = eab/ec;
00279
00280 return (mabc/mab) * ee * ee;
00281 }
00282
00283 local int outer_component(sdyn3* b, bool debug = false)
00284 {
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296 sdyn3* b1 = b->get_oldest_daughter();
00297 sdyn3* b2 = b1->get_younger_sister();
00298 sdyn3* b3 = b2->get_younger_sister();
00299
00300
00301
00302 real ratio1 = period_ratio(b2, b3, b1, debug);
00303 real ratio2 = period_ratio(b3, b1, b2, debug);
00304 real ratio3 = period_ratio(b1, b2, b3, debug);
00305
00306 if (debug) {
00307 cerr << "outer_component: ";
00308 PRC(ratio1), PRC(ratio2), PRL(ratio3);
00309 }
00310
00311 real ratio_max = max(max(ratio1, ratio2), ratio3);
00312
00313 if (ratio_max <= 1)
00314 return 0;
00315 else if (ratio_max == ratio1)
00316 return 1;
00317 else if (ratio_max == ratio2)
00318 return 2;
00319 else
00320 return 3;
00321 }
00322
00323
00324
00325
00326 local void hier3(initial_state3 & init,
00327 real cpu_time_check,
00328 real dt_out,
00329 real dt_snap,
00330 real snap_cube_size,
00331 real dt_print,
00332 real t_end,
00333 bool quiet = false)
00334 {
00335 check_init(init);
00336 sdyn3 * b = init_to_sdyn3(init);
00337
00338 if (!b) err_exit("Unable to initialize system...");
00339
00340
00341
00342 sdyn3_to_system(b, init.system);
00343
00344 real e_init = energy(b);
00345 real cpu_init = cpu_time();
00346 real cpu = cpu_init;
00347
00348
00349
00350 int n_kepler = 0;
00351
00352 do {
00353
00354 int n_stars = 0;
00355 for_all_daughters(sdyn3, b, bb) n_stars++;
00356
00357 tree3_evolve(b, CHECK_INTERVAL, dt_out, dt_snap, snap_cube_size,
00358 init.eta, cpu_time_check,
00359 dt_print, print_elements);
00360
00361
00362
00363 if (outer_component(b) != 3) break;
00364
00365
00366
00367
00368 if (cpu_time() - cpu > cpu_time_check) {
00369
00370 if (!quiet) {
00371
00372 if (cpu == cpu_init)
00373 cerr << endl;
00374
00375 int p = cerr.precision(STD_PRECISION);
00376 cerr << "hier3: CPU time = " << cpu_time() - cpu_init
00377 << " time = " << b->get_system_time()
00378 << " n_steps = " << b->get_n_steps()
00379 << endl;
00380 cerr << " n_osc = " << b->get_n_ssd_osc()
00381 << " n_kepler = " << n_kepler
00382 << endl << flush;
00383 cerr.precision(p);
00384 }
00385 cpu = cpu_time();
00386 }
00387
00388 merge_collisions(b);
00389
00390
00391
00392 for_all_daughters(sdyn3, b, bbb) n_stars--;
00393 if (n_stars > 0) {
00394 if (dt_snap < VERY_LARGE_NUMBER
00395 && system_in_cube(b, snap_cube_size)) {
00396 put_node(cout, *b);
00397 cout << flush;
00398 }
00399 }
00400
00401 } while (b->get_system_time() < t_end &&
00402 !extend_or_end_scatter(b, init));
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412 if (dt_snap < VERY_LARGE_NUMBER && system_in_cube(b, snap_cube_size)) {
00413 put_node(cout, *b);
00414 cout << flush;
00415 }
00416
00417 int p = cerr.precision(STD_PRECISION);
00418 cerr << "t = " << b->get_system_time()
00419 << " t/t_end = " << b->get_system_time()/t_end
00420 << " outer = " << outer_component(b)
00421 << endl;
00422 cerr.precision(p);
00423
00424 if (!quiet) outer_component(b, true);
00425
00426
00427
00428 sdyn3 * bi = b->get_oldest_daughter();
00429 while (bi) {
00430 sdyn3 * tmp = bi->get_younger_sister();
00431 delete bi;
00432 bi = tmp;
00433 }
00434 delete b;
00435 }
00436
00437 main(int argc, char **argv)
00438 {
00439 initial_state3 init;
00440 make_hier_init(init);
00441
00442 int seed = 0;
00443 int n_rand = 0;
00444
00445 int n_experiments = 1;
00446 real dt_out =
00447 VERY_LARGE_NUMBER;
00448 real dt_snap =
00449 VERY_LARGE_NUMBER;
00450 real dt_print =
00451 VERY_LARGE_NUMBER;
00452
00453 real cpu_time_check = 3600;
00454 real snap_cube_size = 10;
00455
00456 int planar_flag = 0;
00457 int psi_flag = 0;
00458 real psi = 0;
00459
00460 real outer_peri = 0;
00461 bool peri_flag = false;
00462
00463 bool quiet = false;
00464
00465 bool X_flag = false, Y_flag = false;
00466
00467
00468 real X_KE = 10, Y_KE = 4;
00469
00470
00471 real T_stab = 100;
00472
00473 check_help();
00474
00475 extern char *poptarg;
00476 int c;
00477 char* param_string
00478 = "a:A:c:C:d:D:e:E:g:m:M:n:N:o:pPq:QR:s:S:t:T:x:X:y:Y:z:";
00479
00480 while ((c = pgetopt(argc, argv, param_string)) != -1)
00481 switch(c) {
00482
00483 case 'a': init.a_out = atof(poptarg);
00484 X_flag = false;
00485 break;
00486 case 'A': init.eta = atof(poptarg);
00487 break;
00488 case 'c': cpu_time_check = 3600*atof(poptarg);
00489 break;
00490 case 'C': snap_cube_size = atof(poptarg);
00491 break;
00492 case 'd': dt_out = atof(poptarg);
00493 if (dt_out < 0) dt_out = pow(2.0, dt_out);
00494 break;
00495 case 'D': dt_snap = atof(poptarg);
00496 if (dt_snap < 0) dt_snap = pow(2.0, dt_snap);
00497 break;
00498 case 'e': init.ecc = atof(poptarg);
00499 peri_flag = false;
00500 break;
00501 case 'E': init.e_out = atof(poptarg);
00502 peri_flag = false;
00503 Y_flag = false;
00504 break;
00505 case 'g': init.tidal_tol_factor = atof(poptarg);
00506 break;
00507 case 'm': init.m2 = atof(poptarg);
00508 break;
00509 case 'M': init.m3 = atof(poptarg);
00510 break;
00511 case 'n': n_experiments = atoi(poptarg);
00512 break;
00513 case 'N': n_rand = atoi(poptarg);
00514 break;
00515 case 'o': psi = atof(poptarg);
00516 psi_flag = 1;
00517 break;
00518 case 'p': planar_flag = 1;
00519 break;
00520 case 'P': planar_flag = -1;
00521 break;
00522 case 'q': outer_peri = atof(poptarg);
00523 peri_flag = true;
00524 Y_flag = false;
00525 break;
00526 case 'Q': quiet = !quiet;
00527 break;
00528 case 'R': init.r_stop = atof(poptarg);
00529 break;
00530 case 's': seed = atoi(poptarg);
00531 break;
00532 case 'S': init.r_stop = atof(poptarg);
00533 break;
00534 case 't': dt_print = atof(poptarg);
00535 if (dt_print < 0) dt_print = pow(2.0, dt_print);
00536 break;
00537 case 'T': T_stab = pow(10.0, atof(poptarg));
00538 break;
00539 case 'x': init.r1 = atof(poptarg);
00540 break;
00541 case 'X': X_KE =atof(poptarg);
00542 X_flag = true;
00543 break;
00544 case 'y': init.r2 = atof(poptarg);
00545 break;
00546 case 'Y': Y_KE =atof(poptarg);
00547 peri_flag = false;
00548 Y_flag = true;
00549 break;
00550 case 'z': init.r3 = atof(poptarg);
00551 break;
00552 case '?': params_to_usage(cerr, argv[0], param_string);
00553 get_help();
00554 }
00555
00556 if (init.m2 > 1) {
00557 cerr << "hier3: init.m2 = " << init.m2 << " > 1" << endl;
00558 exit(1);
00559 }
00560
00561 if (X_flag) {
00562
00563
00564
00565
00566 if (X_KE <= 1) err_exit("X_KE <= 1");
00567
00568 init.a_out = pow((1+init.m3)*X_KE*X_KE, 1.0/3.0);
00569 }
00570
00571 if (Y_flag) {
00572
00573
00574
00575
00576 if (Y_KE <= 1) err_exit("Y_KE <= 1");
00577
00578 init.e_out = 1 - (init.sma*(1+init.ecc) * Y_KE) / init.a_out;
00579 }
00580
00581 if (peri_flag) {
00582
00583
00584
00585 if (outer_peri <= 0) err_exit("outer_peri <= 0");
00586
00587 init.e_out = 1 - outer_peri / init.a_out;;
00588 }
00589
00590 cpu_init();
00591 int random_seed = srandinter(seed, n_rand);
00592
00593 for (int i = 0; i < n_experiments; i++) {
00594
00595 if (!quiet) {
00596 if (n_experiments > 1) cerr << i+1 << ": ";
00597
00598 cerr << "Random seed = " << get_initial_seed()
00599 << " n_rand = " << get_n_rand() << endl << flush;
00600 }
00601
00602 init.id = get_initial_seed() + get_n_rand();
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615 randomize_angles(init.phase);
00616
00617 if (planar_flag == 1) {
00618 init.phase.cos_theta = 1;
00619 if (psi_flag) init.phase.psi = psi * M_PI / 180.0;
00620 } else if (planar_flag == -1) {
00621 init.phase.cos_theta = -1;
00622 if (psi_flag) init.phase.psi = psi * M_PI / 180.0;
00623 }
00624
00625 hier3(init, cpu_time_check,
00626 dt_out, dt_snap, snap_cube_size, dt_print,
00627 2*M_PI*T_stab*sqrt(pow(init.a_out, 3)/(1+init.m3)),
00628 quiet);
00629 }
00630 }
00631
00632 #endif