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 }