Main Page   Class Hierarchy   Data Structures   File List   Data Fields   Globals  

hdyn_merge.C

Go to the documentation of this file.
00001 
00002        //=======================================================//    _\|/_
00003       //  __  _____           ___                    ___       //      /|\ ~
00004      //  /      |      ^     |   \  |         ^     |   \     //          _\|/_
00005     //   \__    |     / \    |___/  |        / \    |___/    //            /|\ ~
00006    //       \   |    /___\   |  \   |       /___\   |   \   // _\|/_
00007   //     ___/   |   /     \  |   \  |____  /     \  |___/  //   /|\ ~
00008  //                                                       //            _\|/_
00009 //=======================================================//              /|\ ~
00010 
00011 //
00012 //  hdyn_merge.C: functions related to physical mergers in kira
00013 //                (formerly part of hdyn_tree.C).
00014 //.............................................................................
00015 //    version 1:  Jun 2000      Steve McMillan
00016 //.............................................................................
00017 //
00018 //  Externally visible functions:
00019 //
00020 //      void   hdyn::merge_logs_after_collision
00021 //      hdyn*  hdyn::merge_nodes
00022 //      bool   hdyn::check_merge_node
00023 //
00024 //.............................................................................
00025 
00026 #include "hdyn.h"
00027 #include <star/dstar_to_kira.h>
00028 #include <star/single_star.h>
00029 
00030 //#define CALCULATE_POST_COLLISION_ON_GRAPE
00031 
00032 // Local function (incomplete).
00033 
00034 local hdyn* apply_tidal_dissipation(hdyn* bi, hdyn* bj, kepler k)
00035 {
00036     // Change the relative orbit of bi and bj to take tidal dissipation
00037     // into account.  Kepler structure k describes the relative motion
00038     // of bi and bj on entry.  The system has just passed periastron where
00039     // tidal dissipation is to be applied.
00040 
00041     print_encounter_elements(bi, bj, "Tidal encounter");
00042 
00043 
00044     //-----------------------------------------------------------------
00045 
00046 
00047     cerr << endl << "**** tidal dissipation suppressed ****"
00048          << endl << endl;
00049     return NULL;
00050 
00051 
00052     //-----------------------------------------------------------------
00053 
00054 
00055     real t_peri = k.return_to_periastron();
00056     if (t_peri > bi->get_time())
00057         warning("apply_tidal_dissipation: stars not past periastron");
00058 
00059     real m_tot = bi->get_mass() + bj->get_mass();
00060     vector r_rel = k.get_rel_pos();
00061     vector v_rel = k.get_rel_vel();
00062 
00063     real de_diss = 0;
00064     for_all_daughters(hdyn, bi->get_parent(), bb) {
00065         if (bb->get_radius() > 0) {
00066             real dde_diss = 0;
00067             real rr = bb->get_radius()/k.get_separation();
00068             real eta_pt = sqrt(bb->get_mass() / m_tot) * pow(rr, -1.5);
00069             stellar_type type = bb->get_starbase()->get_element_type();
00070             dde_diss = tf2_energy_diss(eta_pt, type)
00071                          + pow(rr, 2) * tf3_energy_diss(eta_pt, type);
00072 
00073             cerr << endl;
00074             PRC(type); PRC(bb->get_radius()), PRL(k.get_separation());
00075             PRC(rr); PRC(eta_pt); PRL(dde_diss);
00076 
00077             de_diss += pow(bb->get_binary_sister()->get_mass(), 2)
00078                         * pow(rr, 6) * dde_diss / bb->get_radius();
00079         }
00080     }
00081 
00082     real m_red = bi->get_mass()*bj->get_mass() / m_tot;
00083     real kinetic = 0.5*m_red*square(v_rel);
00084     real potential = -m_red*m_tot/abs(r_rel);
00085 
00086     cerr << endl << "at periastron:  U = " << potential
00087          << "  K = " << kinetic
00088          << "  total = " << potential + kinetic << endl;
00089     cerr << "de_diss = " << de_diss << endl;
00090 
00091     // Reduce energy by de_diss, keep angular momentum constant,
00092     // and compute the new orbit.
00093 
00094     real new_E = k.get_energy() - de_diss;
00095     real J = k.get_angular_momentum();
00096 
00097     real new_sma = -0.5*m_tot/new_E;    // Note: sma may have either sign
00098                                         //       -- not kepler convention
00099 
00100     real new_ecc_2 = 1 - J*J/(m_tot*new_sma);
00101 
00102     if (new_ecc_2 < 0) {
00103         cerr << "immediate merger with J^2 > Ma" << endl;
00104         return bj;
00105     }
00106 
00107     cerr << "old orbit parameters:  sma = " << k.get_semi_major_axis()
00108          << "  ecc = " << k.get_eccentricity()
00109          << "  periastron = " << k.get_periastron() << endl;
00110 
00111     real new_ecc = sqrt(new_ecc_2);
00112     k.set_semi_major_axis(abs(new_sma));
00113     k.set_eccentricity(new_ecc);
00114     k.initialize_from_shape_and_phase();
00115 
00116     cerr << "expected orbit parameters:  sma = " << abs(new_sma)
00117          << "  ecc = " << new_ecc << endl;
00118     cerr << "new orbit parameters:  sma = " << k.get_semi_major_axis()
00119          << "  ecc = " << k.get_eccentricity()
00120          << "  periastron = " << k.get_periastron() << endl;
00121 
00122     real old_phi = bi->get_mass()*bi->get_pot()
00123                         + bj->get_mass()*bj->get_pot()
00124                             - 2*potential;
00125 
00126     k.transform_to_time(bi->get_time());
00127 
00128     r_rel = k.get_rel_pos();
00129     v_rel = k.get_rel_vel();
00130 
00131     vector r_com = (bi->get_mass()*bi->get_pos()
00132                      + bj->get_mass()*bj->get_pos()) / m_tot;
00133     vector v_com = (bi->get_mass()*bi->get_vel()
00134                      + bj->get_mass()*bj->get_vel()) / m_tot;
00135 
00136     // Adjust positions and velocities of the interacting stars.
00137 
00138     bi->set_pos(r_com - bj->get_mass()*r_rel/m_tot);
00139     bj->set_pos(r_com + bi->get_mass()*r_rel/m_tot);
00140     bi->set_vel(v_com - bj->get_mass()*v_rel/m_tot);
00141     bj->set_vel(v_com + bi->get_mass()*v_rel/m_tot);
00142 
00143     // Recompute accs and jerks and update energy bookkeeping.
00144 
00145     hdynptr list[2] = {bi, bj};
00146     bool _false = false;
00147     calculate_acc_and_jerk_for_list(bi->get_root(), list, 2,
00148                                     bi->get_time(),
00149                                     _false, _false, _false, _false);
00150 
00151     bi->get_kira_counters()->de_total -= de_diss;
00152     bi->get_kira_counters()->de_tidal_diss -= de_diss;
00153 
00154     potential = -m_red*m_tot/abs(k.get_separation());
00155     real new_phi = bi->get_mass()*bi->get_pot()
00156                         + bj->get_mass()*bj->get_pot()
00157                             - 2*potential;
00158 
00159     PRC(old_phi); PRC(new_phi); PRL(potential);
00160     PRL(new_phi-old_phi);
00161 
00162     return NULL;
00163 }
00164 
00165 // Flag close encounter distances between stars.  Output occurs on any
00166 // unbound encounter, and on the first encounter in a bound system.
00167 
00168 local void print_perioapo_clustron(hdyn* bi) {
00169 
00170   hdyn *bj = bi->get_root();
00171 
00172   real d2cd_2 = -1;
00173   real d2cd_1 = -1;
00174   real d2cd   = -1;
00175 
00176     // Variables:       bi is star, bj is cluster com
00177     //                  pa_time is time of previous coll
00178     //                  d2cd is squared distance to cluster com
00179     //                  d2cd_1 is previous d2cd
00180     //                  d2cd_2 is previous d2cd_1
00181     //                  pcp_time is time of last periclustron
00182     //                  pca_time is time of last apoclustron
00183     //                  pcp_cntr counts bound periclustron
00184     //                  pca_cntr counts bound apoclustron
00185     //
00186     // All but bi and bj are stored in the bi log story.
00187 
00188 #if 0
00189     cerr << "\nIn print_close_encounter with bi =  " << bi->format_label()
00190          << "  at time " << bi->get_system_time() << endl;
00191     cerr << "     "; print_coll(bi,2);
00192     cerr << "     "; print_nn(bi,2);
00193     cerr << "     (bj = " << bj->format_label();
00194     cerr << ":  coll = "; print_coll(bj);
00195     cerr << ",  nn = "; print_nn(bj); cerr << ")" << endl;
00196 
00197 #endif
00198 
00199     // Retrieve coll information from the log story.
00200 
00201     d2cd_2 = getrq(bi->get_log_story(), "d2cd_1");
00202     d2cd_1 = getrq(bi->get_log_story(), "d2cd");
00203     d2cd   = square(bi->get_pos() - bj->get_pos());
00204 
00205 //    PRC(bi->format_label());PRC(d2cd_2);PRC(d2cd_1);PRL(d2cd);
00206 
00207     if (d2cd_2 > 0) {
00208 
00209       if (d2cd_2 > d2cd_1 && d2cd >= d2cd_1) {    // just passed periclustron
00210 
00211         int pcp_cntr = 0;
00212         real E = get_total_energy(bi, bj);
00213 
00214         if (E > 0) {
00215 
00216           // Always print unbound encounter elements.
00217 
00218           print_encounter_elements(bi, bj, "Perioclustron", false);
00219 
00220         }
00221         else {
00222           if (find_qmatch(bi->get_log_story(), "pcp_cntr"))
00223             pcp_cntr = getiq(bi->get_log_story(), "pcp_cntr");
00224 
00225           pcp_cntr++;
00226         
00227           if (pcp_cntr == 1)
00228             print_encounter_elements(bi, bj, "First periclustron", false);
00229           else
00230             print_encounter_elements(bi, bj, "Periclustron", false);
00231         }
00232 
00233         // Save data on last pericenter (bound or unbound).
00234         // Note that an unbound pericenter resets pcc_cntr to zero.
00235 
00236         putiq(bi->get_log_story(), "pcp_cntr", pcp_cntr);
00237         putrq(bi->get_log_story(), "pcp_time", bi->get_time());
00238         
00239       }
00240       else if (d2cd_2 < d2cd_1 && d2cd <= d2cd_1) { //just passed apoclustron
00241 
00242         int pca_cntr = 0;
00243         real E = get_total_energy(bi, bj);
00244 
00245         if (E > 0) {
00246 
00247           // Always print unbound encounter elements.
00248         
00249           print_encounter_elements(bi, bj, "Apoclustron", false);
00250 
00251         }
00252         else {
00253           if (find_qmatch(bi->get_log_story(), "pca_cntr"))
00254             pca_cntr = getiq(bi->get_log_story(), "pca_cntr");
00255 
00256           pca_cntr++;
00257 
00258           if (pca_cntr == 1)
00259             print_encounter_elements(bi, bj, "First apoclustron", false);
00260           else
00261             print_encounter_elements(bi, bj, "Apoclustron", false);
00262         }
00263 
00264         // Save data on last pericenter (bound or unbound).
00265         // Note that an unbound pericenter resets pca_cntr to zero.
00266 
00267         putiq(bi->get_log_story(), "pca_cntr", pca_cntr);
00268         putrq(bi->get_log_story(), "pca_time", bi->get_time());
00269       }
00270       else {
00271         
00272         // Unlikely multiple encounter(?).  Has been known to occur
00273         // when one incoming star overtakes another.
00274 
00275         //        cerr << endl << "print_close_encounter:  "
00276         //             << "bi = " << bi->format_label()
00277         //             << " at time " << bi->get_system_time() << endl;
00278         //        cerr << "     current coll = " << bj->format_label();
00279         //        cerr << endl;
00280         //        cerr << "  (periclustron counter = "
00281         //             << getiq(bi->get_log_story(), "pcp_cntr") << ")\n";
00282       }
00283 
00284     }
00285 
00286     putrq(bi->get_log_story(), "d2cd_1", d2cd_1);
00287     putrq(bi->get_log_story(), "d2cd", d2cd);
00288     //    putrq(bi->get_log_story(), "pcd_time", bi->get_time());
00289 
00290 #if 0
00291     cerr << "\nAt end of print_close_encounter at time "
00292          << bi->get_system_time() << endl;
00293     cerr << "bi = " << bi->format_label();
00294 #endif
00295 
00296 }
00297 
00298 hdyn* hdyn::check_periapo_node() {
00299 
00300   // For now only for single stars.
00301   //  if (is_leaf() && (is_top_level_node() || parent->is_top_level_node())
00302 
00303     print_perioapo_clustron(this);
00304 }
00305 
00306 
00307 hdyn* hdyn::check_merge_node()
00308 {
00309     // Note: merger criterion is based on coll pointer.
00310 
00311     // In the case of a collision we simply return a pointer to the
00312     // colliding star and take no other action.  Otherwise, we do
00313     // bookkeeping, apply tidal effects, etc. in place.
00314 
00315     // In constant-density case, collision criterion also covers
00316     // tidal destruction by a massive black hole so long as the
00317     // "radius" of the hole (based on constant density) is much
00318     // greater than the radius of a particle.
00319 
00320     if (use_dstar) {
00321         if (is_low_level_node()) {
00322             if (binary_is_merged(this)) {
00323                 cerr << "check_merge_node: merging a binary with logs:"
00324                      << endl;
00325                 print_log_story(cerr);
00326                 cerr << "and\n";
00327                 get_binary_sister()->print_log_story(cerr);
00328                 return get_binary_sister();
00329             }
00330         }
00331     }
00332 
00333     // Note multiple functionality: check for and implement stellar
00334     // mergers; implement tidal dissipation at periastron.
00335 
00336     // Check for encounters moved to kira.C by Steve, 3/24/00.
00337 
00338     if (stellar_capture_criterion_sq <= 0) return NULL;
00339 
00340     hdyn *coll = get_coll();
00341 
00342     if (is_leaf() && coll != NULL && coll->is_leaf() && (kep == NULL)) {
00343 
00344         // Check for tidal capture and physical stellar collision.
00345 
00346         if (!coll->is_valid())
00347             warning("check_merge_node: invalid coll pointer");
00348 
00349         real sum_of_radii_sq = pow(get_sum_of_radii(this, coll), 2);
00350 
00351 
00352         // (NB: d_coll_sq = distance_squared - sum_of_radii_sq)
00353 
00354         if (get_d_coll_sq() <= (stellar_capture_criterion_sq-1)
00355                                                 * sum_of_radii_sq) {
00356 
00357             // Note that the pair must approach within
00358             // stellar_capture_criterion in order for
00359             // stellar_merger_criterion to be checked.
00360 
00361             // cerr << endl << "Capture between " << format_label();
00362             // cerr << " and " << coll->format_label()
00363             //      << " at time = " << get_time() << endl;
00364 
00365             // pp3_minimal(get_top_level_node(), cerr);
00366             // if (get_top_level_node()->get_nn())
00367             //     pp3_minimal(get_top_level_node()->get_nn(), cerr);
00368         
00369             // For a 2-body orbit, use kepler pericenter rather than
00370             // sampled orbit points to determine whether or not a
00371             // collision will occur.  Probably desirable to have
00372             // stellar_capture_criterion a few times greater than
00373             // stellar_merger_criterion to ensure that we get close
00374             // enough to the collision for a more precise determination
00375             // of its elements.
00376 
00377             // Don't use the kepler orbit if the two stars aren't sisters!
00378             // Don't apply tidal dissipation if the two stars aren't sisters!
00379 
00380             // Original:
00381             //
00382             // if (d_coll_sq > (stellar_merger_criterion_sq-1)
00383             //                                  * sum_of_radii_sq) {
00384 
00385             // BUG corrected by Steve 12/98:
00386             //
00387             // if (k.get_periastron() > (stellar_merger_criterion_sq-1)
00388             //                                  * sum_of_radii_sq) {
00389 
00390             real sep_sq = get_d_coll_sq();
00391             kepler k;
00392 
00393             if (get_parent() == coll->get_parent()) {
00394                 coll->synchronize_node();
00395                 initialize_kepler_from_dyn_pair(k, this, coll, false);
00396                 sep_sq = min(sep_sq, k.get_periastron() * k.get_periastron()
00397                                                 - sum_of_radii_sq);
00398             }
00399 
00400             // Check for collision.
00401 
00402             if (sep_sq <= (stellar_merger_criterion_sq-1)
00403                                                 * sum_of_radii_sq)
00404                 return coll;
00405 
00406             // Check for tidal dissipation.
00407 
00408             if (get_parent() != coll->get_parent()) return NULL;
00409 
00410             if (find_qmatch(get_log_story(), "tidal_dissipation")) {
00411                 rmq(get_log_story(), "tidal_dissipation");
00412                 return apply_tidal_dissipation(this, coll, k);
00413             }
00414 
00415             real t_peri = k.get_time_of_periastron_passage();
00416             if (time < t_peri && time + timestep >= t_peri)
00417                 putiq(get_log_story(), "tidal_dissipation", 1);
00418 
00419         }
00420     }
00421 
00422     return NULL;
00423 }
00424 
00425 
00426 // correct_nn_pointers:  Check nn and coll pointers of all nodes in the
00427 //                       system, replacing them by cm if they lie on
00428 //                       the specified list.
00429 //
00430 // These checks should probably be applied every time correct_perturber_lists
00431 // is invoked...
00432 
00433 local void correct_nn_pointers(hdyn * b, hdyn ** list, int n, hdyn * cm)
00434 {
00435     for_all_nodes(hdyn, b, bb) {
00436         for (int i = 0; i < n; i++) {
00437             if (bb->get_nn() == list[i]) bb->set_nn(cm);
00438             if (bb->get_coll() == list[i]) bb->set_coll(cm);
00439         }
00440     }
00441 }
00442 
00443 void hdyn::merge_logs_after_collision(hdyn *bi, hdyn* bj) {
00444 
00445   // log only the moment of the last merger
00446   putrq(get_log_story(), "last_merger_time", bi->get_time());
00447 
00448   if(find_qmatch(bi->get_log_story(), "black_hole"))
00449     putiq(get_log_story(), "black_hole",
00450           getiq(bi->get_log_story(), "black_hole"));
00451   else if(find_qmatch(bj->get_log_story(), "black_hole"))
00452     putiq(get_log_story(), "black_hole",
00453           getiq(bj->get_log_story(), "black_hole"));
00454 }
00455 
00456 
00457 #define CONSTANT_DENSITY        1       // Should be a parameter...
00458 #define MASS_LOSS               0.0
00459 #define KICK_VELOCITY           0.0
00460 
00461 hdyn* hdyn::merge_nodes(hdyn * bcoll,
00462                         int full_dump)  // default = 0
00463 {
00464 
00465     // This function actually does the work of merging nodes.
00466     // It returns a pointer to the newly merged CM.
00467 
00468     // Currently, only calls come from kira.C and dstar_to_kira.C.
00469 
00470     if (diag->tree) {
00471         if (diag->tree_level > 0) {
00472             cerr << endl << "merge_nodes: merging leaves ";
00473             pretty_print_node(cerr);
00474             cerr << " and ";
00475             bcoll->pretty_print_node(cerr);
00476 
00477             int p = cerr.precision(HIGH_PRECISION);
00478             cerr << " at time " << system_time << endl;
00479             cerr.precision(p);
00480 
00481             if (diag->tree_level > 1) {
00482                 cerr << endl;
00483                 pp3(this, cerr);
00484                 pp3(bcoll, cerr);
00485                 if (diag->tree_level > 2) {
00486                     cerr << endl;
00487                     put_node(cerr, *this,  options->print_xreal);
00488                     put_node(cerr, *bcoll, options->print_xreal);
00489                 }
00490                 cerr << endl;
00491             }
00492         }
00493     }
00494 
00495     bool is_pert = (get_kepler() == NULL);
00496     real sum_of_radii_sq = pow(get_sum_of_radii(this, bcoll), 2);
00497     // real sum_of_radii_sq = pow(radius+bcoll->radius, 2);
00498 
00499     // Potentially very expensive if merger doesn't occur during binary
00500     // evolution, as this may entail synchronizing the entire system and
00501     // synchronize_tree currently doesn't use GRAPE.  Fix is to define
00502     // kira_synchronize_tree() in kira_grape_include.C to switch between
00503     // GRAPE (if available) and non-GRAPE code.
00504 
00505     cerr << "merge_nodes: calling synchronize_tree..." << flush;
00506     PRL(cpu_time());
00507     kira_synchronize_tree(get_root());
00508     cerr << "back" << endl << flush;
00509     PRL(cpu_time());
00510 
00511     // Yes, it really is possible that 'this' or bcoll is unperturbed
00512     // (probably in periastron passage)!  Better delete any kepler
00513     // structures here to avoid problems later.  Probably OK simply
00514     // to get rid of the keplers, since we are about to merge the
00515     // nodes...
00516 
00517     if (get_kepler()) {
00518         rmkepler();
00519         cerr << "deleted kepler for " << format_label() << endl;
00520     } else if (get_binary_sister() != bcoll) {
00521         if (bcoll->get_kepler()) bcoll->rmkepler();
00522         cerr << "deleted kepler for " << bcoll->format_label() << endl;
00523     }
00524 
00525     if (is_top_level_node() || get_binary_sister() != bcoll) {
00526 
00527         // Nodes to be merged ('this' and bcoll) are not binary
00528         // sisters.  Force them to become sisters prior to actually
00529         // merging them, temporarily placing them in the same
00530         // subtree if necessary.
00531 
00532         cerr << "creating CM node" << endl;
00533 
00534         hdyn* ancestor = common_ancestor(this, bcoll);
00535         
00536         if (ancestor->is_root()) {
00537 
00538             // Nodes are not in the same subtree.  Combine their
00539             // subtrees into a single clump to allow use of function
00540             // move_node below.  Undo the combination before
00541             // continuing, if necessary.
00542         
00543             bool decombine = !is_top_level_node()
00544                                 && !bcoll->is_top_level_node();
00545 
00546             cerr << "merge_nodes: call combine_top_level_nodes" << endl;
00547 
00548             // PRL(this);
00549             // PRL(get_top_level_node());
00550             // PRL(bcoll);
00551             // PRL(bcoll->get_top_level_node());
00552 
00553             combine_top_level_nodes(get_top_level_node(),
00554                                     bcoll->get_top_level_node(),
00555                                     full_dump);
00556 
00557             // pp2(get_top_level_node(), cerr);
00558 
00559             if (get_binary_sister() != bcoll) {
00560 
00561                 if (full_dump)
00562                     put_node(cout, *(get_top_level_node()), false, 3);
00563         
00564                 move_node(bcoll, this);         // move bcoll to become
00565                                                 // sister of this
00566                 if (full_dump)
00567                     put_node(cout, *(get_top_level_node()), false, 2);
00568             }
00569         
00570             if (decombine) {
00571 
00572                 // cerr << "call split_top_level_node 3" << endl;
00573 
00574                 split_top_level_node(get_top_level_node(), full_dump);
00575 
00576             }
00577         
00578         } else {
00579 
00580             // Already in the same subtree.
00581 
00582             // pp2(get_top_level_node(), cerr);
00583 
00584             if (full_dump)
00585                 put_node(cout, *(get_top_level_node()), false, 3);
00586 
00587             move_node(bcoll, this);             // Move bcoll to become
00588                                                 // sister of this.
00589             if (full_dump)
00590                 put_node(cout, *(get_top_level_node()), false, 2);
00591         }               
00592     }
00593 
00594     // Nodes 'this' and bcoll are binary sisters (in all cases).
00595     // Merge them into their center-of-mass node and remove them.
00596 
00597     // pp2(get_top_level_node(), cerr);
00598 
00599     if (full_dump)
00600         put_node(cout, *(get_top_level_node()), false, 3);
00601 
00602     // Compute energies prior to merger, for bookkeeping purposes:
00603 
00604     cerr << "calculating energies..." << endl << flush;
00605     real epot0, ekin0, etot0;
00606 
00607     // calculate_energies(get_root(), eps2, epot0, ekin0, etot0); //dyn function
00608     // replaced by GRAPE-friendly function (SPZ, March 2001)
00609     // kira_calculate_internal_energies(get_root(), epot0, ekin0, etot0);
00610     // Replaced with ..._with_external by Steve, Jan 02, to maintain
00611     // continuity in pot and avoid GRAPE warning messages.
00612 
00613     calculate_energies_with_external(get_root(), epot0, ekin0, etot0);
00614     PRC(epot0); PRC(ekin0); PRL(etot0);
00615 
00616     hdyn* cm = get_parent();
00617 
00618     real epot_int = -mass * bcoll->mass / abs(pos - bcoll->pos);
00619     real ekin_int = 0.5 * (mass * square(vel)
00620                            + bcoll->mass * square(bcoll->vel));
00621     real etot_int = epot_int + ekin_int;
00622 
00623     PRC(epot_int); PRC(ekin_int); PRL(etot_int);
00624     PRL(cpu_time());
00625     //pp3(cm, cerr);
00626     //pp3(cm->get_root(), cerr);
00627 
00628     label_merger_node(cm);
00629 
00630     // Default mass-radius relation:
00631 
00632     cm->set_radius(radius + bcoll->radius);
00633     PRL(cm->format_label());
00634 
00635     // pp3(cm->get_root(), cerr);
00636 
00637     real dm;
00638     vector dv;
00639 
00640     if (!use_sstar) {
00641 
00642         // Test code for systems without stellar evolution.
00643         // Set mass loss and velocity kick.
00644         
00645         dm = -MASS_LOSS*cm->mass;
00646         
00647         real costh = randinter(-1, 1);
00648         real sinth = sqrt(1 - costh*costh);
00649         if (randinter(0, 1) < 0.5) sinth = -sinth;
00650         real phi = TWO_PI*randinter(0, 1);
00651         dv = KICK_VELOCITY * sqrt(cm->mass/cm->radius)
00652                            * vector(sinth*cos(phi),
00653                                     sinth*sin(phi),
00654                                     costh);
00655 
00656         print_encounter_elements(this, bcoll, "Collision");
00657 
00658         if (CONSTANT_DENSITY) {
00659 
00660             // Override default M-R relation by requiring that the
00661             // (average) density remain constant:
00662             //
00663             //      M_cm / R_cm^3 = 0.5 * (M1 / R1^3 + M2 / R2^3)
00664 
00665             real rho1 = 0, rho2 = 0;
00666             if (radius > 0) rho1 = mass/pow(radius, 3);
00667             if (bcoll->radius > 0) rho2 = bcoll->mass/pow(bcoll->radius, 3);
00668 
00669             if (rho1+rho2 > 0)
00670                 cm->set_radius(pow(2*(1-MASS_LOSS)*cm->mass
00671                                     / (rho1 + rho2), 1.0/3));
00672             else
00673                 cm->set_radius(0);
00674 
00675         } else
00676             cm->set_radius((1-MASS_LOSS)*cm->get_radius());
00677 
00678         cerr << "non-stellar merger: new radius = "
00679              << cm->get_radius() << endl;
00680 
00681     } else {
00682 
00683         // Real code uses stellar evolution code for data to
00684         // initialize collision product.
00685         
00686         hdyn * primary = this;
00687         hdyn * secondary = bcoll;
00688         
00689         cerr << "merge_nodes: merging two STARS"<<endl;
00690         // pp2(cm->get_root(), cerr);
00691 
00692         ((star*)(primary->sbase))->dump(cerr, false);
00693         ((star*)(secondary->sbase))->dump(cerr, false);
00694         
00695 //      real tmp1, tmp2, tmp3;
00696 //      cerr << endl << "computing energies #1:"
00697 //           << endl << flush;
00698 //      calculate_energies_with_external(get_root(), tmp1, tmp2, tmp3);
00699 //      cerr << "OK" << endl << endl << flush;
00700 
00701         if (!merge_with_primary(dynamic_cast(star*, primary->sbase),
00702                                 dynamic_cast(star*, secondary->sbase))) {
00703             primary = bcoll;
00704             secondary = this;
00705         }
00706 
00707         print_encounter_elements(primary, secondary, "Collision");
00708         
00709         ((star*)(primary->sbase))
00710                         ->merge_elements(((star*)(secondary->sbase)));
00711         
00712         cerr << "Merger product: "<< endl;
00713         cerr << format_label() << " (";
00714         //              put_state(make_star_state(sbase), cerr);
00715                 put_state(make_star_state(primary), cerr);
00716         cerr << "; M=" << get_total_mass(primary) << " [Msun], "
00717              << " R=" << get_effective_radius(primary) << " [Rsun]). " << endl;
00718         ((star*)(primary->sbase))->dump(cerr, false);
00719 
00720         real old_mass = cm->mass;
00721 
00722         // For now, keep the disintegrated star and make a log of it.
00723         // Special case if the merger product ceases to exist.
00724         //
00725         // if (((star*)(primary->sbase))->get_element_type()==Disintegrated) {
00726         //   cerr << "Disintegrated star, set CM mass to zero" << endl;
00727         //   cm->mass = 0;
00728         // }
00729         
00730         // Must (1) merge the logs of primary and secondary, and      <---
00731         //      (2) add a line to the log describing the merger.      <---
00732         
00733         // Attach the new merger star to cm.
00734         // Old information of star in CM (if any) is lost here......
00735         
00736         cm->sbase = primary->sbase;
00737         cm->sbase->set_node(cm);
00738         primary->sbase = NULL;
00739         
00740         real new_mass = get_total_mass(cm);
00741         dm = new_mass - old_mass;
00742         dv = anomalous_velocity(cm);
00743     }
00744 
00745     cerr << "new node name = " << cm->format_label() << endl;
00746     PRL(cpu_time());
00747 
00748 //     pp3(cm->get_top_level_node());
00749 //     PRL(get_use_sstar());
00750 //     PRL(get_ignore_internal());
00751 //     PRL(get_external_field());
00752 //     PRL(tidal_type);
00753 //     PRL(get_omega());
00754 //     PRL(get_alpha1());
00755 //     PRL(get_alpha3());
00756 //     PRL(get_use_dstar());
00757 //     PRL(get_stellar_encounter_criterion_sq());
00758 //     PRL(get_stellar_capture_criterion_sq());
00759 //     PRL(get_stellar_merger_criterion_sq());
00760 //     PRL(get_perturbed_list());
00761 //     PRL(get_n_perturbed());
00762 
00763 //     real tmp1, tmp2, tmp3;
00764 //     cerr << endl << "computing energies #2:"
00765 //       << endl << flush;
00766 //     calculate_energies_with_external(get_root(), tmp1, tmp2, tmp3);
00767 //     cerr << "OK" << endl << endl << flush;
00768 
00769     correct_leaf_for_change_of_mass(cm, dm);
00770     if (cm->mass < 0) {
00771         cerr << "check and merge, negative mass ";
00772         PRL(cm->mass);
00773     }
00774 
00775     cm->set_coll(NULL);                 // Set its coll to NULL.
00776 
00777     // Add kick velocity, if any...
00778 
00779     if (square(dv) > 0)
00780         correct_leaf_for_change_of_vector(cm, dv, &hdyn::get_vel,
00781                                           &hdyn::inc_vel);
00782 
00783     cm->set_oldest_daughter(NULL);
00784     cm->remove_perturber_list();
00785 
00786 //     PRL(cm->get_sp());
00787 //     PRL(get_kepler());
00788 //     PRL(get_slow());
00789 //     PRL(get_sp());
00790 //     PRL(bcoll->get_slow());
00791 //     PRL(bcoll->get_sp());
00792 
00793     // Do not try to free memory by simply
00794     //          delete bcoll;
00795     //          delete this;
00796     // -- causes a (not so very) strange error.
00797 
00798 //     cerr << endl << "computing energies #3:"
00799 //       << endl << flush;
00800 //     calculate_energies_with_external(get_root(), tmp1, tmp2, tmp3);
00801 //     cerr << "OK" << endl << endl << flush;
00802 //     PRC(tmp1); PRC(tmp2); PRL(tmp3);
00803 
00804 //     pp3(cm->get_top_level_node());
00805 //     PRL(get_use_sstar());
00806 //     PRL(get_ignore_internal());
00807 //     PRL(get_external_field());
00808 //     PRL(tidal_type);
00809 //     PRL(get_omega());
00810 //     PRL(get_alpha1());
00811 //     PRL(get_alpha3());
00812 //     PRL(get_use_dstar());
00813 //     PRL(get_stellar_encounter_criterion_sq());
00814 //     PRL(get_stellar_capture_criterion_sq());
00815 //     PRL(get_stellar_merger_criterion_sq());
00816 //     PRL(get_perturbed_list());
00817 //     PRL(get_n_perturbed());
00818 
00819     real epot, ekin, etot;
00820 
00821 // #ifdef CALCULATE_POST_COLLISION_ON_GRAPE
00822 //     cerr << "calculate post collision on GRAPE"<<endl;
00823 //     // replaced by GRAPE friendly function (SPZ, March 2001)
00824 //     kira_calculate_internal_energies(get_root(), epot, ekin, etot);
00825 // #else
00826 //     calculate_energies(get_root(), eps2, epot, ekin, etot);  //dyn function
00827 // #endif
00828 
00829     calculate_energies_with_external(get_root(), epot, ekin, etot);
00830     PRC(epot); PRC(ekin); PRL(etot);
00831 
00832     real de_total = etot - etot0;
00833     vector vcm = hdyn_something_relative_to_root(cm, &hdyn::get_vel);
00834     real de_kick = 0.5 * cm->mass * (vcm*vcm - square(vcm-dv));
00835     real de_int = -etot_int;
00836 
00837     PRC(de_total); PRC(de_int); PRL(de_kick);
00838     PRL(cpu_time());
00839 
00840     // Update statistics on mass and energy change components:
00841 
00842     kc->dm_massloss -= dm;      // dm < 0, note
00843 
00844     kc->de_total += de_total;
00845     kc->de_merge += de_int;
00846     kc->de_massloss += de_total - de_int - de_kick;
00847     kc->de_kick += de_kick;
00848 
00849     hdyn* root = cm->get_root();
00850     xreal time = cm->time;
00851 
00852 //     cerr << endl << "computing energies #4:"
00853 //       << endl << flush;
00854 //     calculate_energies_with_external(get_root(), tmp1, tmp2, tmp3);
00855 //     cerr << "OK" << endl << endl << flush;
00856 
00857     // Special treatment of case cm->mass = 0.
00858 
00859     if (cm->mass <= 0) {
00860         
00861         // NOTE: Must copy cm's log entry before deleting the node.     <---
00862         //       Place it in the root log.                              <---
00863         
00864         remove_node_and_correct_upto_ancestor(cm->get_parent(), cm);
00865     }
00866 
00867     predict_loworder_all(root, time);
00868 
00869     // Clean up various lists...
00870 
00871     // Check and correct for the presence of either merged node
00872     // on any perturber list.  Also check and correct neighbor
00873     // and coll pointers.
00874     //
00875     // Probably should perform these checks within merge_nodes.
00876 
00877 //     cerr << endl << "computing energies #5:"
00878 //       << endl << flush;
00879 //     calculate_energies_with_external(get_root(), tmp1, tmp2, tmp3);
00880 //     cerr << "OK" << endl << endl << flush;
00881 
00882     hdynptr del[2];
00883     del[0] = this;
00884     del[1] = bcoll;
00885 
00886     if (RESOLVE_UNPERTURBED_PERTURBERS || is_pert)
00887         correct_perturber_lists(get_root(), del, 2, cm);
00888 
00889     correct_nn_pointers(get_root(), del, 2, cm);
00890 
00891     // Also, if cm is on the perturbed binary list, better remove it.
00892 
00893     if (cm->on_perturbed_list()) {
00894         cerr << "Removing " << cm->format_label()
00895              << " from perturbed binary list " << endl;
00896         cm->remove_from_perturbed_list();
00897     } else
00898         cerr << cm->format_label() << " not on perturbed binary list (OK)"
00899              << endl;
00900 
00901     cerr << endl;
00902 
00903 //     cerr << endl << "computing energies #6:"
00904 //       << endl << flush;
00905 //     calculate_energies_with_external(get_root(), tmp1, tmp2, tmp3);
00906 //     cerr << "OK" << endl << endl << flush;
00907 
00908     if (full_dump) {
00909         hdyn *top = cm->get_top_level_node();
00910         predict_loworder_all(top, cm->get_system_time());
00911         put_node(cout, *top, false, 2);
00912     }
00913 
00914     return cm;
00915 }

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