00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "scatter3.h"
00020
00021 #define UNPERTURBED_DIAG false
00022
00023 local void extend_orbits(sdyn3 * b1, sdyn3 * b2, sdyn3 * b3, real& apo)
00024
00025
00026
00027 {
00028 if ( (b1->get_time() != b2->get_time())
00029 || (b1->get_time() != b3->get_time()) )
00030 err_exit("extend_orbits: inconsistent times");
00031
00032 real time = b3->get_time();
00033
00034 kepler inner, outer;
00035
00036 set_kepler_from_sdyn3(inner, b1, b2);
00037
00038 real m1 = b1->get_mass();
00039 real m2 = b2->get_mass();
00040 real m3 = b3->get_mass();
00041 real m12 = m1 + m2;
00042 real m123 = m12 + m3;
00043
00044 outer.set_time(time);
00045 outer.set_total_mass(m123);
00046
00047
00048
00049 vector cmr = (m1 * b1->get_pos() + m2 * b2->get_pos()) / m12;
00050 vector cmv = (m1 * b1->get_vel() + m2 * b2->get_vel()) / m12;
00051
00052 outer.set_rel_pos(b3->get_pos() - cmr);
00053 outer.set_rel_vel(b3->get_vel() - cmv);
00054
00055 outer.initialize_from_pos_and_vel();
00056
00057
00058
00059
00060 apo = outer.get_semi_major_axis() * (1 + outer.get_eccentricity());
00061
00062 if (UNPERTURBED_DIAG) {
00063
00064 cerr << " inner binary: r = " << inner.get_separation()
00065 << " a = " << inner.get_semi_major_axis()
00066 << " e = " << inner.get_eccentricity()
00067 << endl
00068 << " mass = " << inner.get_total_mass() << endl
00069 << " pos = " << inner.get_rel_pos() << endl
00070 << " vel = " << inner.get_rel_vel() << endl;
00071 cerr << " outer binary: R = " << outer.get_separation()
00072 << " a = " << outer.get_semi_major_axis() << endl
00073 << " e = " << outer.get_eccentricity()
00074 << endl
00075 << " mass = " << outer.get_total_mass() << endl
00076 << " pos = " << outer.get_rel_pos() << endl
00077 << " vel = " << outer.get_rel_vel() << endl;
00078
00079 }
00080
00081
00082
00083
00084 real orbits = 2 * (outer.pred_advance_to_apastron() - time)
00085 / inner.get_period();
00086
00087
00088
00089 real time_0 = time;
00090
00091 real big = 1.e9;
00092 while (orbits > big) {
00093 time += big*inner.get_period();
00094 orbits -= big;
00095 }
00096
00097 int inner_orbits = (int) (orbits + 0.5);
00098 time += inner_orbits * inner.get_period();
00099
00100 outer.transform_to_time(time);
00101
00102
00103
00104
00105 inner.set_time(time);
00106
00107 if (UNPERTURBED_DIAG) {
00108
00109 cerr << " outer binary: R = " << outer.get_separation()
00110 << " a = " << outer.get_semi_major_axis() << endl
00111 << " e = " << outer.get_eccentricity()
00112 << endl
00113 << " mass = " << outer.get_total_mass() << endl
00114 << " pos = " << outer.get_rel_pos() << endl
00115 << " vel = " << outer.get_rel_vel() << endl;
00116
00117 }
00118
00119
00120
00121 b1->get_parent()->set_time(time);
00122 b1->set_time(time);
00123 b2->set_time(time);
00124 b3->set_time(time);
00125
00126 kepler_pair_to_triple(inner, outer, b1, b2, b3);
00127
00128
00129
00130
00131
00132
00133
00134 }
00135
00136 local void stop_integration(sdyn3 * bi, sdyn3 * bj, sdyn3 * bk,
00137 real ejk, real mjk,
00138 real sep, real virial_ratio,
00139 final_state3 * final = NULL)
00140 {
00141 if (!final) return;
00142
00143 real ajk = 0.5 * mjk / abs(ejk);
00144
00145 final->descriptor = stopped;
00146 final->sma = ajk;
00147
00148 real ang_mom = abs((bk->get_pos() - bj->get_pos())
00149 ^ (bk->get_vel() - bj->get_vel()));
00150
00151 real ecc2 = 1 - ang_mom * ang_mom / (mjk * ajk);
00152
00153 if (ecc2 < 1.e-10) {
00154
00155
00156
00157 kepler k;
00158 set_kepler_from_sdyn3(k, bj, bk);
00159 final->ecc = k.get_eccentricity();
00160
00161 } else
00162 final->ecc = sqrt(ecc2);
00163
00164 final->escaper = bi->get_index();
00165 final->virial_ratio = virial_ratio;
00166 final->outer_separation = sep;
00167 }
00168
00169 local int escape(sdyn3 * bi, sdyn3 * bj, sdyn3 * bk,
00170 real ejk,
00171 initial_state3& init,
00172 intermediate_state3 * inter = NULL,
00173 final_state3 * final = NULL)
00174
00175
00176
00177
00178
00179 {
00180 if (final) final->descriptor = unknown_final;
00181
00182 if (ejk >= 0) return 0;
00183
00184 real mi = bi->get_mass();
00185 real mj = bj->get_mass();
00186 real mk = bk->get_mass();
00187 real mjk = mj + mk;
00188
00189
00190
00191 vector cmr = (mj * bj->get_pos() + mk * bk->get_pos()) / mjk;
00192 vector cmv = (mj * bj->get_vel() + mk * bk->get_vel()) / mjk;
00193
00194
00195
00196
00197
00198
00199
00200 vector dv = bi->get_vel() - cmv;
00201 vector dr = bi->get_pos() - cmr;
00202
00203
00204
00205
00206
00207
00208 if (dr*dv <= 0 && init.r_stop > 0) return 0;
00209
00210 real sep = abs(dr);
00211 real virial_ratio = .5 * dv * dv * sep / (mi + mj + mk);
00212
00213
00214
00215
00216
00217 if (sep > abs(init.r_stop)
00218 || (inter && init.r_stop < 0 && dr*dv <= 0 && inter->n_osc > 0)) {
00219
00220
00221
00222
00223
00224
00225
00226 stop_integration(bi, bj, bk, ejk, mjk,
00227 sep, virial_ratio, final);
00228 return 1;
00229 }
00230
00231
00232
00233 real ajk = 0.5 * mjk / abs(ejk);
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248 real rlimit = (ajk + bi->get_radius())
00249 * pow(init.tidal_tol_factor * mjk / (mi + mjk), -1/3.0);
00250 if (init.r_stop < 0) rlimit = max(rlimit, abs(init.r_stop));
00251
00252
00253
00254 if (sep < rlimit) return 0;
00255
00256
00257
00258
00259 real scaled_safety_factor = ENERGY_SAFETY_FACTOR * rlimit / sep;
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269 if (abs(virial_ratio - 1) < scaled_safety_factor) return 0;
00270
00271
00272
00273 if (virial_ratio > 1) {
00274
00275
00276
00277 if (final) {
00278
00279 if (bi->get_index() == 1)
00280 final->descriptor = exchange_1;
00281 else if (bi->get_index() == 2)
00282 final->descriptor = exchange_2;
00283 else if (bi->get_index() == 3)
00284 final->descriptor = preservation;
00285 else
00286 final->descriptor = unknown_final;
00287
00288 final->sma = ajk;
00289 real ang_mom = abs((bk->get_pos() - bj->get_pos())
00290 ^ (bk->get_vel() - bj->get_vel()));
00291
00292 real ecc2 = 1 - ang_mom * ang_mom / (mjk * ajk);
00293 if (ecc2 < 1.e-10) {
00294
00295
00296
00297 kepler k;
00298 set_kepler_from_sdyn3(k, bj, bk);
00299 final->ecc = k.get_eccentricity();
00300
00301 } else
00302 final->ecc = sqrt(ecc2);
00303
00304 final->escaper = bi->get_index();
00305 final->virial_ratio = virial_ratio;
00306 final->outer_separation = sep;
00307 }
00308
00309 return 1;
00310
00311 } else {
00312
00313
00314
00315
00316 real e = energy(bi->get_parent());
00317
00318 if (UNPERTURBED_DIAG)
00319 cerr << "Beginning analytic extension at time "
00320 << bi->get_parent()->get_time()
00321 + bi->get_parent()->get_time_offset()
00322 << endl;
00323
00324 real apo;
00325 extend_orbits(bj, bk, bi, apo);
00326
00327 if (inter) inter->n_kepler++;
00328
00329 if (UNPERTURBED_DIAG)
00330 cerr << "Done. Energy error = "
00331 << energy(bi->get_parent()) - e
00332 << endl;
00333
00334
00335
00336 if (apo >= init.r_stop) {
00337 stop_integration(bi, bj, bk, ejk, mjk,
00338 min(apo, abs(init.r_stop)), virial_ratio, final);
00339 return 1;
00340 }
00341 }
00342
00343 return 0;
00344 }
00345
00346
00347
00348 local void set_merger_mass_and_radius(sdyn3 * bn, sdyn3 * bi, sdyn3 * bj)
00349 {
00350 bn->set_mass(bi->get_mass() + bj->get_mass());
00351 bn->set_radius(bi->get_radius() + bj->get_radius());
00352 }
00353
00354
00355
00356
00357 local void set_merger_dyn(sdyn3 * bn, sdyn3 * bi, sdyn3 * bj)
00358 {
00359 real mi = bi->get_mass();
00360 real mj = bj->get_mass();
00361 real m_inv = 1/(mi + mj);
00362
00363 bn->set_pos((mi*bi->get_pos() + mj*bj->get_pos())*m_inv);
00364 bn->set_vel((mi*bi->get_vel() + mj*bj->get_vel())*m_inv);
00365 bn->set_acc((mi*bi->get_acc() + mj*bj->get_acc())*m_inv);
00366 bn->set_jerk((mi*bi->get_jerk() + mj*bj->get_jerk())*m_inv);
00367
00368 vector d_pos = bi->get_pos() - bj->get_pos();
00369 real rij = sqrt(d_pos*d_pos);
00370
00371 vector d_vel = bi->get_vel() - bj->get_vel();
00372 real vij2 = d_vel*d_vel;
00373
00374 real eij_pot = -mi * mj / rij;
00375 real eij_kin = 0.5 * mi * mj * m_inv * vij2;
00376
00377
00378
00379 sdyn3 * b = bi->get_parent();
00380 sdyn3 * bk = NULL;
00381
00382 for_all_daughters(sdyn3, b, bb)
00383 if (bb != bi && bb != bj) bk = bb;
00384
00385 real tidal_pot = 0;
00386 if (bk) {
00387 real mn = mi + mj;
00388 real mk = bk->get_mass();
00389 tidal_pot = -mn * mk / abs(bn->get_pos() - bk->get_pos())
00390 + mi * mk / abs(bi->get_pos() - bk->get_pos())
00391 + mj * mk / abs(bj->get_pos() - bk->get_pos());
00392 }
00393
00394 bn->set_energy_dissipation(bi->get_energy_dissipation()
00395 + bj->get_energy_dissipation()
00396 + eij_pot + eij_kin
00397 - tidal_pot);
00398
00399 }
00400
00401
00402
00403 local void merge(sdyn3 * bi, sdyn3 * bj)
00404 {
00405 sdyn3 * b = bi->get_parent();
00406 if (b != bj->get_parent()) err_exit("merge: parent conflict...");
00407
00408
00409
00410 sdyn3 * bn = new sdyn3();
00411
00412
00413
00414
00415
00416
00417
00418
00419 set_merger_mass_and_radius(bn, bi, bj);
00420 set_merger_dyn(bn, bi, bj);
00421 bn->set_time(bi->get_time());
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436 int new_index = bi->get_index() + bj->get_index();
00437 if (bi->get_index() < 4 && bj->get_index() < 4) new_index++;
00438 bn->set_label(new_index);
00439
00440 detach_node_from_general_tree(*bi);
00441 detach_node_from_general_tree(*bj);
00442
00443 add_node(*bn, *b);
00444 }
00445
00446
00447
00448 void merge_collisions(sdyn3 * b)
00449 {
00450 int coll = 1;
00451 while (coll) {
00452
00453 coll = 0;
00454 for_all_daughters(sdyn3, b, bi)
00455 {
00456 if (coll) break;
00457 for (sdyn3 * bj = bi->get_younger_sister(); bj != NULL;
00458 bj = bj->get_younger_sister()) {
00459
00460 if ( abs(bi->get_pos() - bj->get_pos())
00461 < (bi->get_radius() + bj->get_radius()) ) {
00462
00463 merge(bi, bj);
00464 coll = 1;
00465 break;
00466 }
00467 }
00468 }
00469 }
00470 }
00471
00472
00473
00474
00475
00476 local int triple_escape(real e12, real r3, real m12, real m3,
00477 real tidal_tol_factor)
00478 {
00479 if (e12 < 0) return 0;
00480
00481 real a12 = 0.5 * m12 / e12;
00482
00483
00484
00485
00486
00487
00488
00489
00490 real tid_fac = tidal_tol_factor * m12 / (m3 + m12);
00491 real ratio = a12/r3;
00492
00493 if (ratio*ratio*ratio > tid_fac)
00494
00495 return 1;
00496 else
00497 return 0;
00498 }
00499
00500 local int extend_or_end_scatter3(sdyn3 * b,
00501 initial_state3& init,
00502 intermediate_state3 * inter = NULL,
00503 final_state3 * final = NULL)
00504 {
00505 b->to_com();
00506
00507 sdyn3 * b1 = b->get_oldest_daughter();
00508 sdyn3 * b2 = b1->get_younger_sister();
00509 sdyn3 * b3 = b2->get_younger_sister();
00510
00511 real r12 = abs(b1->get_pos() - b2->get_pos());
00512 real r23 = abs(b2->get_pos() - b3->get_pos());
00513 real r31 = abs(b3->get_pos() - b1->get_pos());
00514
00515 real m1 = b1->get_mass();
00516 real m2 = b2->get_mass();
00517 real m3 = b3->get_mass();
00518
00519 real k1 = 0.5 * m1 * b1->get_vel() * b1->get_vel();
00520 real k2 = 0.5 * m2 * b2->get_vel() * b2->get_vel();
00521 real k3 = 0.5 * m3 * b3->get_vel() * b3->get_vel();
00522
00523 real phi12 = m1 * m2 / r12;
00524 real phi23 = m2 * m3 / r23;
00525 real phi31 = m3 * m1 / r31;
00526
00527 real mu12 = m1 * m2 / (m1 + m2);
00528 real mu23 = m2 * m3 / (m2 + m3);
00529 real mu31 = m3 * m1 / (m3 + m1);
00530
00531 vector dv = b2->get_vel() - b1->get_vel();
00532 real k12 = 0.5 * mu12 * dv * dv;
00533 real vr12 = dv * (b2->get_pos() - b1->get_pos());
00534
00535 dv = b3->get_vel() - b2->get_vel();
00536 real k23 = 0.5 * mu23 * dv * dv;
00537 real vr23 = dv * (b3->get_pos() - b2->get_pos());
00538
00539 dv = b1->get_vel() - b3->get_vel();
00540 real k31 = 0.5 * mu31 * dv * dv;
00541 real vr31 = dv * (b1->get_pos() - b3->get_pos());
00542
00543
00544
00545 if (k1 + k2 + k3 >= phi12 + phi23 + phi31
00546 && r12 > LARGE_SEPARATION
00547 && r23 > LARGE_SEPARATION
00548 && r31 > LARGE_SEPARATION
00549 && k12 > phi12 && k23 > phi23 && k31 > phi31
00550 && vr12 > 0 && vr23 > 0 && vr31 > 0
00551 && triple_escape(k12 - phi12, min(r23, r31), m1 + m2, m3,
00552 init.tidal_tol_factor)
00553 && triple_escape(k23 - phi23, min(r31, r12), m2 + m3, m1,
00554 init.tidal_tol_factor)
00555 && triple_escape(k31 - phi31, min(r12, r23), m3 + m1, m2,
00556 init.tidal_tol_factor)) {
00557
00558 if (final) {
00559 final->descriptor = ionization;
00560 final->virial_ratio = min(min(k12/phi12, k23/phi23), k31/phi31);
00561 final->outer_separation = -1;
00562 final->escaper = -1;
00563 }
00564
00565 return 1;
00566 }
00567
00568
00569
00570
00571
00572
00573
00574 if (r12 * LARGE_SEPARATION_FACTOR < (r23 + r31))
00575 return escape(b3, b1, b2, (k12 - phi12)/mu12, init, inter, final);
00576
00577 if (r23 * LARGE_SEPARATION_FACTOR < (r31 + r12))
00578 return escape(b1, b2, b3, (k23 - phi23)/mu23, init, inter, final);
00579
00580 if (r31 * LARGE_SEPARATION_FACTOR < (r12 + r23))
00581 return escape(b2, b3, b1, (k31 - phi31)/mu31, init, inter, final);
00582
00583 return 0;
00584 }
00585
00586 local int extend_or_end_scatter2(sdyn3 * b, final_state3 * final = NULL)
00587 {
00588 sdyn3 * d1 = b->get_oldest_daughter();
00589 sdyn3 * d2 = d1->get_younger_sister();
00590
00591
00592
00593 d2->set_younger_sister(NULL);
00594
00595 kepler k;
00596
00597 sdyn3 * merger = NULL;
00598 sdyn3 * single = NULL;
00599
00600
00601
00602 if (d1->get_index() > 3) {
00603 merger = d1;
00604 single = d2;
00605 } else {
00606 merger = d2;
00607 single = d1;
00608 }
00609
00610 set_kepler_from_sdyn3(k, d1, d2);
00611
00612 real closest_approach = k.get_periastron();
00613 if (k.get_energy() >= 0
00614 && (d1->get_pos() - d2->get_pos())
00615 * (d1->get_vel() - d2->get_vel()) > 0)
00616 closest_approach = k.get_separation();
00617
00618 if (closest_approach < d1->get_radius() + d2->get_radius()) {
00619
00620 merge(d1, d2);
00621 d1 = b->get_oldest_daughter();
00622 d1->set_younger_sister(NULL);
00623
00624 if (final) {
00625 final->descriptor = triple_merger;
00626 final->escaper = 0;
00627 final->outer_separation = 0;
00628 final->virial_ratio = -1;
00629 }
00630
00631 } else {
00632
00633 real closest_approach_squared = closest_approach * closest_approach;
00634
00635 merger->set_min_nn_dr2(closest_approach_squared);
00636 merger->set_min_nn_label(single->get_index());
00637
00638 if (closest_approach_squared < single->get_min_nn_dr2()) {
00639 single->set_min_nn_dr2(closest_approach_squared);
00640 single->set_min_nn_label(merger->get_index());
00641 }
00642
00643
00644 if (final) {
00645
00646 if (k.get_energy() < 0) {
00647
00648 if (single->get_index() == 1)
00649 final->descriptor = merger_binary_1;
00650 else if (single->get_index() == 2)
00651 final->descriptor = merger_binary_2;
00652 else if (single->get_index() == 3)
00653 final->descriptor = merger_binary_3;
00654 else
00655 final->descriptor = unknown_final;
00656
00657 final->sma = k.get_semi_major_axis();
00658 final->ecc = k.get_eccentricity();
00659 final->outer_separation = -1;
00660 final->escaper = 0;
00661 final->virial_ratio = -1;
00662
00663 } else {
00664
00665 if (single->get_index() == 1)
00666 final->descriptor = merger_escape_1;
00667 else if (single->get_index() == 2)
00668 final->descriptor = merger_escape_2;
00669 else if (single->get_index() == 3)
00670 final->descriptor = merger_escape_3;
00671 else
00672 final->descriptor = unknown_final;
00673
00674 final->outer_separation = k.get_separation();
00675 final->escaper = single->get_index();
00676 final->virial_ratio = k.get_energy() * k.get_separation()
00677 / k.get_total_mass() - 1;
00678 }
00679 }
00680 }
00681
00682 return 1;
00683 }
00684
00685 local int extend_or_end_scatter1(final_state3 * final = NULL)
00686 {
00687 if (final) {
00688 final->descriptor = triple_merger;
00689 final->escaper = 0;
00690 final->outer_separation = 0;
00691 final->virial_ratio = -1;
00692 }
00693
00694 return 1;
00695 }
00696
00697
00698
00699
00700
00701 int extend_or_end_scatter(sdyn3 * b,
00702 initial_state3& init,
00703 intermediate_state3 * inter,
00704 final_state3 * final)
00705 {
00706
00707
00708 if (init.r_stop == VERY_LARGE_NUMBER && b->get_n_steps() > MAX_N_STEPS) {
00709 if (final) final->descriptor = stopped;
00710 return 1;
00711 }
00712
00713 int n = 0;
00714 for_all_daughters(sdyn3, b, bb) n++;
00715
00716
00717
00718 if (final) {
00719 final->sma = -1;
00720 final->ecc = -1;
00721 }
00722
00723 if (n == 3)
00724 return extend_or_end_scatter3(b, init, inter, final);
00725 else if (n == 2)
00726 return extend_or_end_scatter2(b, final);
00727 else if (n == 1)
00728 return extend_or_end_scatter1(final);
00729 else {
00730 cerr << "extend_or_end_scatter: n = " << n << endl;
00731 exit(1);
00732 }
00733 return 0;
00734 }