Main Page   Class Hierarchy   Data Structures   File List   Data Fields   Globals  

extend_or_end.C

Go to the documentation of this file.
00001 
00002        //=======================================================//    _\|/_
00003       //  __  _____           ___                    ___       //      /|\
00004      //  /      |      ^     |   \  |         ^     |   \     //          _\|/_
00005     //   \__    |     / \    |___/  |        / \    |___/    //            /|\
00006    //       \   |    /___\   |  \   |       /___\   |   \   // _\|/_
00007   //     ___/   |   /     \  |   \  |____  /     \  |___/  //   /|\     
00008  //                                                       //            _\|/_
00009 //=======================================================//              /|\
00010 
00011 // Code shared by scatter3 and hier3 relating to possible termination
00012 // or analytic extension of motion, or merging two or all stars.
00013 //
00014 // Globally visible functions:
00015 //
00016 //      merge_collisions
00017 //      extend_or_end_scatter
00018 
00019 #include "scatter.h"
00020 #include "kepler.h"
00021 
00022 #define UNPERTURBED_DIAG false
00023 
00024 void kepler_pair_to_triple(kepler & k1, // Inner binary (b1 + b2)
00025                            kepler & k2, // Outer binary
00026                            sdyn * b1,
00027                            sdyn * b2,
00028                            sdyn * b3)
00029 {
00030     // Construct positions and velocities from the specified kepler structures.
00031 
00032     // Assume that labels, masses, times, and the center of mass are handled
00033     // elsewhere.
00034 
00035     // Set up the outer orbit first.  Note that the center of mass of
00036     // the three-body system is taken to be at rest at the origin.
00037 
00038     // Make no assumptions about masses!
00039 
00040     real m1 = b1->get_mass();
00041     real m2 = b2->get_mass();
00042     real m3 = b3->get_mass();
00043 
00044     real m12 = m1 + m2;
00045     real m123 = m12 + m3;
00046 
00047     // Relative position and velocity from (1,2) to 3
00048 
00049     b3->set_pos(m12 * k2.get_rel_pos() / m123);
00050     b3->set_vel(m12 * k2.get_rel_vel() / m123);
00051     
00052     b1->set_pos(-m3 * k2.get_rel_pos() / m123);
00053     b1->set_vel(-m3 * k2.get_rel_vel() / m123);
00054 
00055     b2->set_pos(b1->get_pos());
00056     b2->set_vel(b1->get_vel());
00057 
00058     // Then set up the inner binary.
00059 
00060     b1->inc_pos(-m2 * k1.get_rel_pos() / m12);      // rel_pos is from 1 to 2
00061     b1->inc_vel(-m2 * k1.get_rel_vel() / m12);
00062 
00063     b2->inc_pos( m1 * k1.get_rel_pos() / m12);
00064     b2->inc_vel( m1 * k1.get_rel_vel() / m12);
00065 
00066 }
00067 
00068 // tree_is_unbound: return TRUE iff all the top-level nodes of the specified
00069 //                  tree are unbound, widely separated, and receding.
00070 //
00071 // Specifically, require that all top-level pairs be unbound and receding,
00072 // and that no node be a significant perturber of any other pair.
00073 //
00074 // Since deeper levels of structure are already taken into account in the
00075 // tree structure, we only need to check that all nodes at the top level
00076 // are unbound and separating.
00077 //
00078 // Note: If we want to apply analytic extension of nearly unbound top-level
00079 //       nodes, it should be done here.
00080 
00081 bool tree_is_unbound(sdyn* root, real ttf, int debug) {
00082 
00083     if (debug) {
00084         cerr << "Top level nodes: ";
00085         for_all_daughters(sdyn, root, bb) cerr << " " << id(bb);
00086         cerr << endl;
00087     }
00088 
00089     //    root->flatten_node();  // make the node flat.
00090     root->to_com();      // Move to the center-of-mass frame.
00091 
00092     real kin = 0;
00093     real pot = 0;
00094 
00095     for_all_daughters(sdyn, root, bi) {
00096         for (sdyn* bj = bi->get_younger_sister();
00097              bj != NULL; bj = bj->get_younger_sister()) {
00098 
00099             if (debug) cerr << "checking i = " << id(bi)
00100                             << "  j = " << id(bj) << endl;
00101             
00102             // Test radial velocity, separation, and relative energy of (i,j):
00103 
00104             if ((bi->get_pos() - bj->get_pos())
00105                  * (bi->get_vel() - bj->get_vel()) < 0) return FALSE;
00106 
00107             real rij = abs(bi->get_pos() - bj->get_pos());
00108 
00109             if (debug) cerr << "    rij = " << rij << endl;
00110 
00111             real mij = bi->get_mass() + bj->get_mass();
00112             real mu_scale = ttf * bi->get_mass() / mij;
00113 
00114             // (mij here for the same reason as in scatter3/triple_escape.)
00115 
00116             real rlimit = max(LARGE_SEPARATION,
00117                  bi->get_radius() * pow(mu_scale, -1/3.0));
00118 
00119             if (debug) cerr << "    rlimit = " << rlimit << endl;
00120 
00121             if (rij < rlimit) return FALSE;
00122 
00123             real scaled_safety_factor = ENERGY_SAFETY_FACTOR * rlimit / rij;
00124 
00125             real kij = 0.5 * square(bi->get_vel() - bj->get_vel());
00126             real pij = mij / rij;
00127             real eij = kij - pij;
00128 
00129             if (debug) cerr << "    kij = " << kij
00130                  << "  pij = " << pij
00131                  << "  eij = " << kij - pij
00132                  << endl;
00133 
00134             if (eij < 0) return FALSE;
00135             if (abs(kij/pij - 1) < scaled_safety_factor) return FALSE;
00136 
00137             real aij = 0.5 * mij / eij;
00138             vector cmij = (bi->get_mass() * bi->get_pos()
00139                              + bj->get_mass() * bj->get_pos()) / mij;
00140 
00141             // Check the perturbations of all other particles on (i,j).
00142 
00143             for_all_daughters(sdyn, root, bk)
00144                 if (bk != bi && bk != bj) {
00145 
00146                     real rk = abs(bk->get_pos() - cmij);
00147 
00148                     if (debug) cerr << "    checking perturber " << id(bk)
00149                          << " at distance " << rk << "...";
00150 
00151                     //PRC(bi->format_label());
00152                     //PRC(bj->format_label());
00153                     //PRC(bk->format_label());
00154                     //PRL(rk/aij);
00155 
00156                     if (rk < aij * pow(ttf * mij
00157                                        / (bk->get_mass() + mij), -1/3.0)) {
00158                         if (debug) cerr << "too close" << endl;
00159                         return FALSE;
00160                     }
00161                     if (debug) cerr << endl;
00162                 }
00163 
00164             if (debug) cerr << "    done" << endl;
00165 
00166             pot -= bi->get_mass() * bj->get_mass() / rij;
00167         }
00168         kin += 0.5 * bi->get_mass() * square(bi->get_vel());
00169     }
00170 
00171     // Finally, check total energy.
00172 
00173     // cerr << "total system energy = " << kin + pot << endl;
00174 
00175     if (kin + pot <= 0) return FALSE;
00176     return TRUE;
00177 }
00178 
00179 #if 0
00180 
00181 bool tree_is_unbound(sdyn* root, int debug) {
00182 
00183     if (debug) {
00184         cerr << "Top level nodes: ";
00185         for_all_daughters(sdyn, root, bb) cerr << " " << id(bb);
00186         cerr << endl;
00187     }
00188 
00189     root->to_com();      // Move to the center-of-mass frame.
00190 
00191     real kin = 0;
00192     real pot = 0;
00193 
00194     for_all_daughters(sdyn, root, bi) {
00195         for (sdyn* bj = bi->get_younger_sister();
00196              bj != NULL; bj = bj->get_younger_sister()) {
00197 
00198             if (debug) cerr << "checking i = " << id(bi)
00199                             << "  j = " << id(bj) << endl;
00200             
00201             // Test radial velocity, separation, and relative energy of (i,j):
00202 
00203             if ((bi->get_pos() - bj->get_pos())
00204                  * (bi->get_vel() - bj->get_vel()) < 0) return FALSE;
00205 
00206             real rij = abs(bi->get_pos() - bj->get_pos());
00207 
00208             if (debug) cerr << "    rij = " << rij << endl;
00209 
00210             real mij = bi->get_mass() + bj->get_mass();
00211             real mu_scale = TIDAL_TOL_FACTOR * bi->get_mass() / mij;
00212 
00213             // (mij here for the same reason as in scatter3/triple_escape.)
00214 
00215             real rlimit = max(LARGE_SEPARATION,
00216                  bi->get_radius() * pow(mu_scale, -1/3.0));
00217 
00218             if (debug) cerr << "    rlimit = " << rlimit << endl;
00219 
00220             if (rij < rlimit) return FALSE;
00221 
00222             real scaled_safety_factor = ENERGY_SAFETY_FACTOR * rlimit / rij;
00223 
00224             real kij = 0.5 * square(bi->get_vel() - bj->get_vel());
00225             real pij = mij / rij;
00226             real eij = kij - pij;
00227 
00228             if (debug) cerr << "    kij = " << kij
00229                  << "  pij = " << pij
00230                  << "  eij = " << kij - pij
00231                  << endl;
00232 
00233             if (eij < 0) return FALSE;
00234             if (abs(kij/pij - 1) < scaled_safety_factor) return FALSE;
00235 
00236             real aij = 0.5 * mij / eij;
00237             vector cmij = (bi->get_mass() * bi->get_pos()
00238                              + bj->get_mass() * bj->get_pos()) / mij;
00239 
00240             // Check the perturbations of all other particles on (i,j).
00241 
00242             for_all_daughters(sdyn, root, bk)
00243                 if (bk != bi && bk != bj) {
00244 
00245                     real rk = abs(bk->get_pos() - cmij);
00246 
00247                     if (debug) cerr << "    checking perturber " << id(bk)
00248                          << " at distance " << rk << "...";
00249 
00250                     if (rk < aij * pow(TIDAL_TOL_FACTOR * mij
00251                                        / (bk->get_mass() + mij), -1/3.0)) {
00252                         if (debug) cerr << "too close" << endl;
00253                         return FALSE;
00254                     }
00255                     if (debug) cerr << endl;
00256                 }
00257 
00258             if (debug) cerr << "    done" << endl;
00259 
00260             pot -= bi->get_mass() * bj->get_mass() / rij;
00261         }
00262         kin += 0.5 * bi->get_mass() * square(bi->get_vel());
00263     }
00264 
00265     // Finally, check total energy.
00266 
00267     // cerr << "total system energy = " << kin + pot << endl;
00268 
00269     if (kin + pot <= 0) return FALSE;
00270     return TRUE;
00271 }
00272 #endif
00273 
00274 local real potential_energy(sdyn * b) {
00275 
00276     real u = 0;
00277 
00278     for_all_daughters(sdyn, b, bi) {
00279         for (sdyn * bj = bi->get_younger_sister(); bj != NULL;
00280              bj = bj->get_younger_sister())
00281           u -= bi->get_mass() * bj->get_mass()
00282                / abs(bi->get_pos() - bj->get_pos());
00283     }
00284 
00285     return u;
00286 }
00287 
00288 local real energy(sdyn * b)
00289 {
00290     real k = 0, u = 0, dissipation = 0;
00291 
00292     for_all_daughters(sdyn, b, bi) {
00293 
00294         // PRC(bi), PRL(bi->get_pos());
00295 
00296         k += bi->get_mass() * bi->get_vel() * bi->get_vel();
00297         dissipation += bi->get_energy_dissipation();
00298 
00299         for (sdyn * bj = bi->get_younger_sister(); bj != NULL;
00300              bj = bj->get_younger_sister()) {
00301 
00302             // PRC(bj), PRL(bj->get_pos());
00303 
00304             u -= bi->get_mass() * bj->get_mass()
00305                   / abs(bi->get_pos() - bj->get_pos());
00306         }
00307     }
00308 
00309     return 0.5*k + u + dissipation;
00310 }
00311 
00312 void set_kepler_from_sdyn(kepler& k, sdyn* b1, sdyn* b2)
00313 {
00314     if (b1->get_time() != b2->get_time()) 
00315         err_exit("set_kepler_from_sdyn: inconsistent times");
00316 
00317     k.set_time(b1->get_time());
00318     k.set_total_mass( b1->get_mass() + b2->get_mass() );
00319     k.set_rel_pos( b2->get_pos() - b1->get_pos() );
00320     k.set_rel_vel( b2->get_vel() - b1->get_vel() );
00321 
00322     k.initialize_from_pos_and_vel();
00323 }
00324 
00325 
00326 local void stop_integration(sdyn * bi, sdyn * bj, sdyn * bk,
00327                             real ejk, real mjk,
00328                             real sep, real virial_ratio) {
00329 
00330     real ajk = 0.5 * mjk / abs(ejk);
00331 
00332     //    final->descriptor = stopped;
00333     //    final->sma = ajk;
00334 
00335     real ang_mom = abs((bk->get_pos() - bj->get_pos())
00336                        ^ (bk->get_vel() - bj->get_vel()));
00337 
00338     real ecc2 = 1 - ang_mom * ang_mom / (mjk * ajk);
00339     
00340     if (ecc2 < 1.e-10) {
00341 
00342         // Take care with small eccentricities! 
00343 
00344         kepler k;
00345         set_kepler_from_sdyn(k, bj, bk);
00346         //      final->ecc = k.get_eccentricity();
00347 
00348     } else
00349       //        final->ecc = sqrt(ecc2);
00350       ;
00351 
00352     //    final->escaper = bi->get_index();
00353     //    final->virial_ratio = virial_ratio;
00354     //    final->outer_separation = sep;
00355 
00356 }
00357 
00358 
00359 local void extend_orbits(sdyn * b1, sdyn * b2, sdyn * b3, real& apo)
00360 
00361 // Analytically extend the orbits of the [[1,2],3] hierarchical system.
00362 
00363 {
00364     if ( (b1->get_time() != b2->get_time())
00365          || (b1->get_time() != b3->get_time()) )
00366         err_exit("extend_orbits: inconsistent times");
00367     
00368     real time = b3->get_time();
00369     
00370     kepler inner, outer;
00371 
00372     set_kepler_from_sdyn(inner, b1, b2);
00373     
00374     real m1 = b1->get_mass();
00375     real m2 = b2->get_mass();
00376     real m3 = b3->get_mass();
00377     real m12 = m1 + m2;
00378     real m123 = m12 + m3;
00379     
00380     outer.set_time(time);
00381     outer.set_total_mass(m123);
00382     
00383     // Center of mass position and velocity of the inner binary:
00384     
00385     vector cmr = (m1 * b1->get_pos() + m2 * b2->get_pos()) / m12;
00386     vector cmv = (m1 * b1->get_vel() + m2 * b2->get_vel()) / m12;
00387     
00388     outer.set_rel_pos(b3->get_pos() - cmr);
00389     outer.set_rel_vel(b3->get_vel() - cmv);
00390 
00391     outer.initialize_from_pos_and_vel();
00392 
00393     // Determine the outer apocenter, to check the stopping criterion
00394     // in the calling routine.
00395 
00396     apo = outer.get_semi_major_axis() * (1 + outer.get_eccentricity());
00397     
00398     if (UNPERTURBED_DIAG) {
00399 
00400         cerr << "  inner binary:  r = " << inner.get_separation()
00401              << "  a = " << inner.get_semi_major_axis()
00402              << "  e = " << inner.get_eccentricity()
00403              << endl
00404              << "  mass = " << inner.get_total_mass() << endl
00405              << "  pos = " << inner.get_rel_pos() << endl
00406              << "  vel = " << inner.get_rel_vel() << endl;
00407         cerr << "  outer binary:  R = " << outer.get_separation()
00408              << "  a = " << outer.get_semi_major_axis() << endl
00409              << "  e = " << outer.get_eccentricity()
00410              << endl
00411              << "  mass = " << outer.get_total_mass() << endl
00412              << "  pos = " << outer.get_rel_pos() << endl
00413              << "  vel = " << outer.get_rel_vel() << endl;
00414 
00415     }
00416 
00417     // Map forward in time by an integral number of inner binary periods
00418     // to an incoming configuration as close as possible to the outgoing one.
00419 
00420     real orbits = 2 * (outer.pred_advance_to_apastron() - time)
00421                                 / inner.get_period();
00422 
00423     // Note: orbits may be too big to fit in an int...
00424 
00425     real big = 1.e9;
00426     while (orbits > big) {
00427         time += big*inner.get_period();
00428         orbits -= big;
00429     }
00430 
00431     int inner_orbits = (int) (orbits + 0.5);
00432     time += inner_orbits * inner.get_period();
00433 
00434     outer.transform_to_time(time);
00435     
00436     // Note that no modification is needed to the inner orbit
00437     // except to increase its time.
00438     
00439     inner.set_time(time);
00440     
00441     if (UNPERTURBED_DIAG) {
00442 
00443         cerr << "  outer binary:  R = " << outer.get_separation()
00444              << "  a = " << outer.get_semi_major_axis() << endl
00445              << "  e = " << outer.get_eccentricity()
00446              << endl
00447              << "  mass = " << outer.get_total_mass() << endl
00448              << "  pos = " << outer.get_rel_pos() << endl
00449              << "  vel = " << outer.get_rel_vel() << endl;
00450 
00451     }
00452 
00453     // Reconstruct the new sdyns:
00454     
00455     b1->get_parent()->set_time(time);
00456     b1->set_time(time);
00457     b2->set_time(time);
00458     b3->set_time(time);
00459 
00460     kepler_pair_to_triple(inner, outer, b1, b2, b3);
00461     
00462 //    cerr << "extend_orbits:  " << inner_orbits << " inner orbits" << endl;
00463 //    cerr << "outer orbit: " << endl;
00464 //    outer.print_elements(cerr);
00465 //    cerr << "inner orbit: " << endl;
00466 //    inner.print_elements(cerr);
00467     
00468 }
00469 
00470 local int escape(sdyn * bi, sdyn * bj, sdyn * bk, real ejk,
00471                  real ttf) {
00472 
00473 // Return true iff bi is escaping from the center of mass of bj and bk.
00474 // Perform analytic continuation if appropriate.
00475 // On entry, we already know that i is "widely" separated from j and k.
00476 
00477     if (ejk >= 0) return 0;             // Inner pair not bound.
00478 
00479     real mi = bi->get_mass();
00480     real mj = bj->get_mass();
00481     real mk = bk->get_mass();
00482     real mjk = mj + mk;
00483 
00484     // Center of mass position and velocity of j-k "binary":
00485 
00486     vector cmr = (mj * bj->get_pos() + mk * bk->get_pos()) / mjk;
00487     vector cmv = (mj * bj->get_vel() + mk * bk->get_vel()) / mjk;
00488 
00489     // Return immediately if the third particle is approaching the binary,
00490     // unless r_stop < 0 (meaning that the integration is to be terminated
00491     // if we pass apastron).  Note that NO analytic extension is performed
00492     // on the initial incoming orbit -- it is assumed that the initial
00493     // conditions take care of this.
00494 
00495     vector dv = bi->get_vel() - cmv;
00496     vector dr = bi->get_pos() - cmr;
00497 
00498     // PRL(abs(dr));
00499     // PRL(abs(dv));
00500     // PRL(dr*dv);
00501     // PRL(init.r_stop);
00502 
00503     if (dr*dv <= 0) return 0;
00504 
00505     real sep = abs(dr);
00506     real virial_ratio = .5 * dv * dv * sep / (mi + mj + mk);
00507 
00508     // Test stopping criterion.
00509 
00510     // PRL(sep);
00511 
00512     if (dr*dv <= 0) {
00513 
00514         cerr << "stopping... \n";
00515         cerr << "  sep = " << sep << "  dr*dv = " << dr*dv;
00516       cerr << endl;
00517 
00518         stop_integration(bi, bj, bk, ejk, mjk, sep, virial_ratio);
00519         return 1;
00520     }
00521 
00522     // Test for sufficiently unperturbed inner binary.
00523     
00524     real ajk = 0.5 * mjk / abs(ejk);
00525 
00526     // PRL(ajk);
00527 
00528     // Determine limiting radius for "negligible" tidal perturbation
00529     // Note that the term in the denominator is mjk + mi, not just
00530     // mi, in order to prevent problems with low-mass third stars.
00531 
00532     // The use of r_stop is a kludge to allow "flyby" experiments where
00533     // we catch the outcoming particle at some specific radius.  For the
00534     // strictest flyby experiments (see flyby3.C), r_stop < 0, meaning
00535     // we stop at |r_stop| or apocenter.  In this case ONLY, let r_stop
00536     // override the tidal limit.  If r_stop > 0, assume that the built-in
00537     // tidal parameters are OK.
00538 
00539     real rlimit = (ajk + bi->get_radius())
00540                       * pow(ttf * mjk / (mi + mjk), -1/3.0);
00541     //    if (init.r_stop < 0) rlimit = max(rlimit, abs(init.r_stop));
00542 
00543     // PRL(rlimit);
00544 
00545     if (sep < rlimit) return 0;
00546 
00547     // Test for sufficiently non-perturbed outer binary. The safety
00548     // factor is reduced at large radii.
00549 
00550     real scaled_safety_factor = ENERGY_SAFETY_FACTOR * rlimit / sep;
00551 
00552 //    cerr.precision(6);
00553 //    cerr << "inner unperturbed, sep, rlim, factor, |v - 1| = " << endl;
00554 //    cerr << "   " << sep <<" "<< rlimit <<" "<< scaled_safety_factor
00555 //       <<" "<< abs(virial_ratio - 1) << endl;
00556 
00557     // PRL(virial_ratio);
00558 
00559     if (abs(virial_ratio - 1) < scaled_safety_factor) return 0;
00560 
00561     // Now outer binary is either clearly bound or clearly unbound.
00562 
00563     if (virial_ratio > 1) {
00564 
00565         // Body bi is escaping.
00566 
00567 
00568         if (false) {
00569 #if 0
00570 
00571             if (bi->get_index() == 1)   // Initial binary was (1,2).
00572                 final->descriptor = exchange_1;
00573             else if (bi->get_index() == 2)
00574                 final->descriptor = exchange_2;
00575             else if (bi->get_index() == 3)
00576                 final->descriptor = preservation;
00577             else
00578                 final->descriptor = unknown_final;
00579 #endif
00580 
00581             //      final->sma = ajk;
00582             real ang_mom = abs((bk->get_pos() - bj->get_pos())
00583                                ^ (bk->get_vel() - bj->get_vel()));
00584 
00585             real ecc2 = 1 - ang_mom * ang_mom / (mjk * ajk);
00586             if (ecc2 < 1.e-10) {
00587 
00588                 // Take care with small eccentricities! 
00589 
00590                 kepler k;
00591                 set_kepler_from_sdyn(k, bj, bk);
00592                 //              final->ecc = k.get_eccentricity();
00593 
00594             } else
00595               //                final->ecc = sqrt(ecc2);
00596               ;
00597 
00598             //      final->escaper = bi->get_index();
00599             //      final->virial_ratio = virial_ratio;
00600             //      final->outer_separation = sep;
00601         }
00602 
00603         return 1;
00604 
00605     } else {
00606 
00607         // Analytically extend the orbits by an integral number
00608         // of binary periods.
00609 
00610         real e = energy(bi->get_parent());
00611 
00612         if (UNPERTURBED_DIAG) 
00613             cerr << "Beginning analytic extension at time "
00614                  << bi->get_parent()->get_time()
00615                            + bi->get_parent()->get_time_offset()
00616                  << endl;
00617 
00618         real apo;
00619         extend_orbits(bj, bk, bi, apo);
00620 
00621         //      if (inter) inter->n_kepler++;
00622 
00623         if (UNPERTURBED_DIAG)
00624             cerr << "Done.  Energy error = "
00625                  << energy(bi->get_parent()) - e
00626                  << endl;
00627 
00628         // See if we exceeded the stopping condition during the extension.
00629 
00630         //      if (apo >= init.r_stop) {
00631         //          stop_integration(bi, bj, bk, ejk, mjk,
00632         //                           min(apo, abs(init.r_stop)), virial_ratio);
00633         //          return 1;
00634         //      }
00635     }
00636     
00637     return 0;
00638 }
00639 
00640 #define UNPERTURBED_DIAG false
00641 
00642 local void determine_triple_parameters(sdyn * b, real& apo) {
00643 
00644   cerr << "determine_triple_parameters" << endl;
00645 
00646     sdyn *b1, *b2, *b3;
00647     int i=0;
00648     for_all_leaves(sdyn, b, bi) { 
00649       if(i==0) b1 = bi;
00650       else if(i==1) b2 = bi;
00651       else if(i==2) b3 = bi;
00652       i++;
00653     }
00654 
00655     if ( (b1->get_time() != b2->get_time())
00656          || (b1->get_time() != b3->get_time()) )
00657         err_exit("extend_orbits: inconsistent times");
00658     
00659     real time = b3->get_time();
00660     
00661     kepler inner, outer;
00662 
00663     set_kepler_from_sdyn(inner, b1, b2);
00664     
00665     real m1 = b1->get_mass();
00666     real m2 = b2->get_mass();
00667     real m3 = b3->get_mass();
00668     real m12 = m1 + m2;
00669     real m123 = m12 + m3;
00670     
00671     outer.set_time(time);
00672     outer.set_total_mass(m123);
00673     
00674     // Center of mass position and velocity of the inner binary:
00675     
00676     vector cmr = (m1 * b1->get_pos() + m2 * b2->get_pos()) / m12;
00677     vector cmv = (m1 * b1->get_vel() + m2 * b2->get_vel()) / m12;
00678     
00679     outer.set_rel_pos(b3->get_pos() - cmr);
00680     outer.set_rel_vel(b3->get_vel() - cmv);
00681 
00682     outer.initialize_from_pos_and_vel();
00683 
00684     // Determine the outer apocenter, to check the stopping criterion
00685     // in the calling routine.
00686 
00687     apo = outer.get_semi_major_axis() * (1 + outer.get_eccentricity());
00688     
00689         cerr << "  inner binary:  r = " << inner.get_separation()
00690              << "  a = " << inner.get_semi_major_axis()
00691              << "  e = " << inner.get_eccentricity()
00692              << endl
00693              << "  mass = " << inner.get_total_mass() << endl
00694              << "  pos = " << inner.get_rel_pos() << endl
00695              << "  vel = " << inner.get_rel_vel() << endl;
00696         cerr << "  outer binary:  R = " << outer.get_separation()
00697              << "  a = " << outer.get_semi_major_axis() << endl
00698              << "  e = " << outer.get_eccentricity()
00699              << endl
00700              << "  mass = " << outer.get_total_mass() << endl
00701              << "  pos = " << outer.get_rel_pos() << endl
00702              << "  vel = " << outer.get_rel_vel() << endl;
00703 
00704 
00705     // Map forward in time by an integral number of inner binary periods
00706     // to an incoming configuration as close as possible to the outgoing one.
00707 
00708 //    real orbits = 2 * (outer.pred_advance_to_apastron() - time)
00709 //                              / inner.get_period();
00710 
00711     }
00712 
00713 
00714 
00715 // triple_escape: return 1 if star 3 is unbound with respect to the center
00716 //                of mass of stars 1 and 2 (distance r3) and is a negligible
00717 //                perturber of the (1,2) hyperbolic orbit.
00718 
00719 local int triple_escape(real e12, real r3, real m12, real m3,
00720                         real tidal_tol_factor)
00721 {
00722 
00723     if (e12 < 0) return 0; // e12 = energy per unit reduced mass of pair (1,2)
00724 
00725     real a12 = 0.5 * m12 / e12;
00726 
00727     //----------------------------------------------------------------------
00728     // Hmmm... Still a problem with pow on RH 5.2?
00729 
00730     // if (r3 > a12 * pow(tidal_tol_factor * m12 / (m3 + m12), -1/3.0))
00731 
00732     // The m12 in the denominator here includes the tidal effect of (1,2) on 3.
00733 
00734     real tid_fac = tidal_tol_factor * m12 / (m3 + m12);
00735     real ratio = a12/r3;
00736 
00737     if (ratio*ratio*ratio > tid_fac)
00738     //----------------------------------------------------------------------
00739         return 1;
00740     else
00741         return 0;
00742 }
00743 
00744 local int extend_or_end_scatter4(sdyn * b) {
00745 
00746     b->flatten_node();
00747     b->to_com();          // map the whole system to center-of-mass frame
00748     real mt= b->get_mass();
00749 
00750     real rij[5], phi[5], mu[5], kij[5], vrij[5];
00751     real mij[5], mkl[5];
00752     sdyn* bj = NULL;
00753 
00754     int i=0;
00755     real phit=0;
00756     vector dv;
00757     for_all_leaves(sdyn, b, bi) {
00758       for (bj = (sdyn*)bi->next_node(b); bj != NULL;
00759            bj = (sdyn*)bj->next_node(b)) {
00760 
00761         mij[i] = bi->get_mass() + bj->get_mass();
00762         mkl[i] = mt - mij[i];
00763         rij[i] = abs(bi->get_pos() - bj->get_pos());
00764         PRC(rij[i]);PRC(bi->format_label());PRL(bj->format_label());
00765         phi[i] = bi->get_mass() * bj->get_mass() / rij[i];
00766         phit += phi[i];
00767         mu[i]  = bi->get_mass() * bj->get_mass() / (mij[i]);
00768 
00769         dv = bj->get_vel() - bi->get_vel();
00770         kij[i] = 0.5 * mu[i] * dv * dv;
00771         vrij[i] = dv * (bj->get_pos() - bi->get_pos());
00772 
00773         i++;
00774       }
00775     }
00776 
00777     i=0;
00778     real m[4], k[4];
00779     real kt=0;
00780     {
00781     for_all_leaves(sdyn, b, bj) {
00782       m[i]  = bj->get_mass();
00783       k[i]  = 0.5 * m[i] * bj->get_vel() * bj->get_vel();
00784       kt += k[i]; 
00785       i++;
00786     }}
00787 
00788     bool unbound = false;
00789     if (kt >= phit)
00790       unbound = true;
00791 
00792     bool large_distance = false;
00793     bool receding = false;
00794     if(!unbound)
00795       for(i=0; i<5; i++) {
00796         if(kij[i]>phi[i]) {
00797           unbound = true;
00798           break;
00799         }
00800         if(rij[i]>LARGE_SEPARATION) {
00801           large_distance = true;
00802           break;
00803         }
00804         if(vrij[i]>0) {
00805           receding = true;
00806           break;
00807         }
00808       }
00809 
00810     real rmin;
00811     bool tescape = false;
00812     real ttf = TIDAL_TOL_FACTOR; //  1e-6;
00813     for(i=0; i<5; i++) {
00814       rmin = VERY_LARGE_NUMBER;
00815       for(int j=0; j<5; j++) 
00816         if(j!=i) rmin = min(rmin, rij[j]);
00817       tescape = triple_escape(kij[i] - phi[i], rmin, mij[i], mkl[i], ttf);
00818       if(tescape) break;
00819     }
00820 
00821     PRC(unbound);PRC(large_distance);PRC(receding);PRL(tescape);
00822     // terminate if any of these is true.
00823     if(unbound || large_distance || receding || tescape)
00824       return 0;
00825 
00826 
00827     // Now test the closest pair and the third star for escape.
00828     // Function "escape" also does analytic extension, if appropriate.
00829     // Note that the emergency stopping criterion R > |r_stop| returns
00830     // looking like an escape has occurred. This should be decoupled from
00831     // the escape test (someday).
00832 
00833 #if 0 
00834     bool bescape = false;
00835     real rtot;
00836     for(i=0; i<5; i++) {
00837       rtot = 0;
00838       for(j=0; j<5; j++) 
00839         if(j!=i) rtot += rij[j];
00840       if (rij[i] * LARGE_SEPARATION_FACTOR < rtot)
00841      bescape = escape(b3, b1, b2, (k12 - phi12)/mu12, ttf);
00842     if(bescape) return 0;
00843 }
00844 #endif
00845 
00846     cerr << "Make tree" << flush << endl;
00847     make_tree(b, DYNAMICS, STABILITY, K_MAX, true);
00848     cerr << "tree made" << endl;
00849     
00850     return 1;
00851 
00852 }
00853 
00854 local int extend_or_end_scatter3(sdyn * b) {
00855 
00856     b->to_com();          // map the whole system to center-of-mass frame
00857     sdyn *b1, *b2, *b3;
00858     int i=0;
00859     for_all_leaves(sdyn, b, bi) { 
00860       if(i==0) b1 = bi;
00861       else if(i==1) b2 = bi;
00862       else if(i==2) b3 = bi;
00863       i++;
00864     }
00865 
00866     real r12 = abs(b1->get_pos() - b2->get_pos());
00867     real r23 = abs(b2->get_pos() - b3->get_pos());
00868     real r31 = abs(b3->get_pos() - b1->get_pos());
00869 
00870     real m1 = b1->get_mass();
00871     real m2 = b2->get_mass();
00872     real m3 = b3->get_mass();
00873 
00874     real k1 = 0.5 * m1 * b1->get_vel() * b1->get_vel();
00875     real k2 = 0.5 * m2 * b2->get_vel() * b2->get_vel();
00876     real k3 = 0.5 * m3 * b3->get_vel() * b3->get_vel();
00877 
00878     real phi12 = m1 * m2 / r12;
00879     real phi23 = m2 * m3 / r23;
00880     real phi31 = m3 * m1 / r31;
00881 
00882     real mu12 = m1 * m2 / (m1 + m2);
00883     real mu23 = m2 * m3 / (m2 + m3);
00884     real mu31 = m3 * m1 / (m3 + m1);
00885 
00886     vector dv = b2->get_vel() - b1->get_vel();
00887     real k12 = 0.5 * mu12 * dv * dv;
00888     real vr12 = dv * (b2->get_pos() - b1->get_pos());
00889 
00890     dv = b3->get_vel() - b2->get_vel();
00891     real k23 = 0.5 * mu23 * dv * dv;
00892     real vr23 = dv * (b3->get_pos() - b2->get_pos());
00893 
00894     dv = b1->get_vel() - b3->get_vel();
00895     real k31 = 0.5 * mu31 * dv * dv;
00896     real vr31 = dv * (b1->get_pos() - b3->get_pos());
00897 
00898     // First test for ionization.
00899 
00900     real ttf = TIDAL_TOL_FACTOR; //  1e-6;
00901     if (k1 + k2 + k3 >= phi12 + phi23 + phi31
00902         && r12 > LARGE_SEPARATION 
00903         && r23 > LARGE_SEPARATION
00904         && r31 > LARGE_SEPARATION
00905         && k12 > phi12 && k23 > phi23 && k31 > phi31
00906         && vr12 > 0 && vr23 > 0 && vr31 > 0
00907         && triple_escape(k12 - phi12, min(r23, r31), m1 + m2, m3, ttf)
00908         && triple_escape(k23 - phi23, min(r31, r12), m2 + m3, m1, ttf)
00909         && triple_escape(k31 - phi31, min(r12, r23), m3 + m1, m2, ttf)) {
00910 
00911         return 1;
00912     }
00913 
00914     // Now test the closest pair and the third star for escape.
00915     // Function "escape" also does analytic extension, if appropriate.
00916     // Note that the emergency stopping criterion R > |r_stop| returns
00917     // looking like an escape has occurred. This should be decoupled from
00918     // the escape test (someday).
00919 
00920     if (r12 * LARGE_SEPARATION_FACTOR < (r23 + r31))
00921       return escape(b3, b1, b2, (k12 - phi12)/mu12, ttf);
00922 
00923     if (r23 * LARGE_SEPARATION_FACTOR < (r31 + r12))
00924       return escape(b1, b2, b3, (k23 - phi23)/mu23, ttf);
00925 
00926     if (r31 * LARGE_SEPARATION_FACTOR < (r12 + r23))
00927       return escape(b2, b3, b1, (k31 - phi31)/mu31, ttf);
00928 
00929     return 0;
00930 }
00931 
00932 local int extend_or_end_scatter2(sdyn * b) {
00933 
00934     sdyn * d1 = b->get_oldest_daughter();
00935     sdyn * d2 = d1->get_younger_sister();
00936 
00937     // Consistency (just in case):
00938 
00939     d2->set_younger_sister(NULL);
00940 
00941     kepler k;
00942 
00943     sdyn * merger = NULL;
00944     sdyn * single = NULL;
00945 
00946     // One of the two stars must be a merger product.
00947 
00948     if (d1->get_index() > 3) {
00949         merger = d1;
00950         single = d2;
00951     } else {
00952         merger = d2;
00953         single = d1;
00954     }
00955 
00956     set_kepler_from_sdyn(k, d1, d2);
00957     //    k.print_all(cerr);
00958 
00959     real closest_approach = k.get_periastron();
00960     if (k.get_energy() >= 0
00961         && (d1->get_pos() - d2->get_pos())
00962             * (d1->get_vel() - d2->get_vel()) > 0)
00963         closest_approach = k.get_separation();
00964     else {
00965       return 2;   // indicate that two-body system is still bound
00966     }
00967 
00968     if (closest_approach < d1->get_radius() + d2->get_radius()) {
00969       PRL(closest_approach);
00970       cerr <<"Merge nodes"<<endl;
00971       merge(d1, d2);
00972       d1 = b->get_oldest_daughter();
00973       d1->set_younger_sister(NULL);     // Again, just in case.
00974 
00975 #if 0
00976         if (final) {
00977             final->descriptor = triple_merger;
00978             final->escaper = 0;                // 0 means no escaper
00979             final->outer_separation = 0;
00980             final->virial_ratio = -1;
00981         }
00982 #endif
00983 
00984     } else {
00985 
00986         real closest_approach_squared = closest_approach * closest_approach;
00987 
00988 
00989         merger->set_min_nn_dr2(closest_approach_squared);
00990         merger->set_min_nn_label(single->get_index());
00991 
00992         if (closest_approach_squared < single->get_min_nn_dr2()) {
00993           // cerr <<" Merge NODES?"<<endl;
00994           // PRC(closest_approach_squared);PRL(single->get_min_nn_dr2());
00995           // PRC(single->format_label());PRL(merger->format_label());
00996             single->set_min_nn_dr2(closest_approach_squared);
00997             single->set_min_nn_label(merger->get_index());
00998         }
00999     }
01000 
01001     return 1;
01002 }
01003 
01004 int extend_or_end_scatter(sdyn * b, real ttf, bool debug) {
01005 
01006   if (b->get_n_steps() > MAX_N_STEPS) {
01007     return 1;
01008   }
01009 
01010   int unbound = 0;
01011   if(b->n_leaves()==4) {
01012     unbound = tree_is_unbound(b, ttf, debug);
01013   }
01014   else if(b->n_leaves()==3) {
01015     unbound = extend_or_end_scatter3(b);
01016     //    determine_triple_parameters(b, apo);
01017   } else if(b->n_leaves()==2) {
01018     unbound = extend_or_end_scatter2(b);
01019   } else if(b->n_leaves()==1) {
01020     //          return extend_or_end_scatter1(b);
01021     unbound = 1;
01022   }
01023 
01024     return unbound; 
01025 }
01026 

Generated at Sun Feb 24 09:57:00 2002 for STARLAB by doxygen1.2.6 written by Dimitri van Heesch, © 1997-2001