Main Page   Class Hierarchy   Data Structures   File List   Data Fields   Globals  

kira.C

Go to the documentation of this file.
00001 
00002 #define T_DEBUG 169.5           // track progress through the main integration
00003 #undef  T_DEBUG                 // loop after time T_DEBUG if defined
00004 
00005 //#define DUMP_DATA 1           // uncomment to allow detailed TMP_DUMP output
00006 
00007        //=======================================================//    _\|/_
00008       //  __  _____           ___                    ___       //      /|\ ~
00009      //  /      |      ^     |   \  |         ^     |   \     //          _\|/_
00010     //   \__    |     / \    |___/  |        / \    |___/    //            /|\ ~
00011    //       \   |    /___\   |  \   |       /___\   |   \   // _\|/_
00012   //     ___/   |   /     \  |   \  |____  /     \  |___/  //   /|\ ~
00013  //                                                       //            _\|/_
00014 //=======================================================//              /|\ ~
00015 
00090 
00091 // Level-2 help:
00092 
00093 //++
00094 //++ Some run-time parameters:
00095 //++
00096 //++ The initial virial radius is read from the input snapshot.  If no
00097 //++ initial virial radius is found there, the value specified by the
00098 //++ "-V" command-line option is used.  If no "-V' option is set, a
00099 //++ default value of 1 is assumed.
00100 //++
00101 //++ The initial mass is read from the input snapshot.  If no initial
00102 //++ mass is found there, the mass is computed if t = 0; otherwise, a
00103 //++ default value of 1 is assumed.  The initial mass is saved in the
00104 //++ output snapshot for future use.
00105 //++
00106 //++ If a tidal field is specified ("-Q"), the initial Jacobi radius
00107 //++ is set from the "initial_rtidal_over_rvirial" entry in the input
00108 //++ file, if such an entry exists.  This value may be overridden by
00109 //++ setting the Jacobi radius on the command line ("-J").  If specified,
00110 //++ the command-line value scales the initial tidal radius (if found),
00111 //++ or the virial radius (otherwise).  The initial Jacobi radius is
00112 //++ written to the output snapshot for future use.  If a
00113 //++ "kira-written" initial Jacobi radius is found in the input file,
00114 //++ it is used regardless of the other settings.  Thus, in a typical
00115 //++ situation, the Jacobi radius computed at t = 0 will be used in
00116 //++ all subsequent restarts.
00117 //++
00118 //++ A stripping radius may be specified with the "-G" option.  If a
00119 //++ command-line value specified, it scales the Jacobi radius if one
00120 //++ is known, or the virial radius otherwise.  The scaled stripping
00121 //++ radius (normalized to unit mass) is written to the output
00122 //++ snapshot for future use.  If a scaled stripping radius is found
00123 //++ in the input file, it is used regardless of the other settings.
00124 //++ As with the initial Jacobi radius, in a typical situation, the
00125 //++ scaled stripping radius computed at t = 0 will be used in all
00126 //++ subsequent restarts.
00127 //++
00128 //++ If the input snapshot does not contain physical scales (and if
00129 //++ stellar evolution/interactions are enabled), they may be set on
00130 //++ the command line.  The "-M" option specifies the total system
00131 //++ mass, in solar units.  The "-R" option specifies the value of
00132 //++ the virial radius, in parsecs.  The "-T" option specifies the
00133 //++ (Heggie & Mathieu) system time unit, in Myr.
00134 //++
00135 //++ NOTE from Steve (7/01): the following options have been retired:
00136 //++
00137 //++      -F    specify tidal field type (0 = none, 1 = point-mass,
00138 //++                                      2 = isothermal, 3 = disk,
00139 //++                                      4 = custom)
00140 //++                          [0 if -Q not set; 1 otherwise][*]
00141 //++
00142 //++      -J    specify Jacobi radius [none][*]
00143 //++
00144 //++      -Q    use tidal field [none][*]
00145 //++
00146 //++      -M    specify initial total mass, in solar masses
00147 //++                          [none; take from input snap if present]
00148 //++      -R    specify initial virial radius, in pc
00149 //++                          [none; take from input snap if present]
00150 //++      -T    specify initial virial time scale, in Myr
00151 //++                          [none; take from input snap if present]
00152 //++
00153 //++      -r    specify initial virial radius in code units
00154 //++                          [1; take from input snap if present]
00155 
00156 //      J. Makino, S. McMillan          12/92
00157 //      S. McMillan, P. Hut              9/94
00158 //      J. Makino, S. McMillan          12/95
00159 //      J. Makino, S. McMillan           7/96
00160 //      J. Makino, S. McMillan           1/97
00161 //      S. McMillan                      6/97
00162 //      S. McMillan, S. Portegies Zwart  3/98
00163 //      S. McMillan, S. Portegies Zwart  7/98
00164 //      S. McMillan                      8/98
00165 //      S. Portegies Zwart              12/00
00166 //      S. McMillan                      7/01
00167 //
00168 // NOTE:  ALL direct references to USE_GRAPE are confined to
00169 //        this file (referenced externally via the functions below).
00170 //        Most significant GRAPE-related functions are contained
00171 //        in the file kira_grape_include.C.
00172 //
00173 // Known problems:  First timestep is a bit shaky, in particular 
00174 //                  if the system is cold.
00175 //
00176 // July 1997 (Steve)
00177 //
00178 //   Need the ability to ensure rigorous reproducability on restart.
00179 //   Should restructure evolve_system to allow log output, snap output,
00180 //   escaper removal, stellar evolution, debugging to be performed
00181 //   independently.
00182 
00183 
00184 
00185 #ifdef TOOLBOX
00186 
00187 #include "hdyn.h"
00188 #include "star/dstar_to_kira.h"
00189 
00190 #define INITIAL_STEP_LIMIT  0.0625      // Arbitrary limit on the first step
00191 
00192 //#define CHECK_PERI_APO_CLUSTER          // Follow individual stellar orbits.
00193 
00194 static kira_counters kc_prev; 
00195 static bool dbg = false;
00196 
00197 
00198 
00199 // *** All GRAPE-related calls are now defined in kira_grape_include.C ***
00200 
00201 #ifdef USE_TREE
00202   #include "/work6/starlab/Tree++/kira_tree_include.C"
00203 #else
00204   #include "kira_grape_include.C"
00205 #endif
00206 
00207 //========================================================================
00208 
00209 
00210 // Handy local functions...
00211 
00212 // match_label: return true iff b's id (name, index, or #index)
00213 //              matches the specified string.
00214 
00215 local bool match_label(hdyn* b, char* label)
00216 {
00217     if (b->name_is(label))
00218         return true;
00219 #if 0
00220     // Function format_label() prepends a # to numbers.
00221     // Check for the number without the #.
00222 
00223     if (b->get_index() >= 0) {
00224         char id[64];
00225         sprintf(id, "%d", b->get_index());
00226         if (streq(id, label))
00227             return true;
00228     }
00229 #endif
00230     return false;
00231 }
00232 
00233 // match_label_tree: return true iff the label of any
00234 //                   node below b (or b) matches the
00235 //                   specified string.
00236 
00237 local bool match_label_tree(hdyn* b, char* label)
00238 {
00239     for_all_nodes(hdyn, b, bi)
00240         if (match_label(bi, label)) return true;
00241     return false;
00242 }
00243 
00244 // cond_print_nn: for each b in the list, print out the IDs of the entire
00245 //                subtree containing b if any of those IDs match the
00246 //                specified string.
00247 
00248 local void cond_print_nn(hdyn** list, int n, char* label, char* header = NULL)
00249 {
00250     for (int i = 0; i < n; i++) {
00251         hdyn* b = list[i];
00252         if (b) {
00253             if (match_label_tree(b->get_top_level_node(), label)) {
00254                 if (header) cerr << header << endl;
00255                 cerr << "print_nn triggered by node "
00256                      << b->format_label() << endl;
00257                 for_all_leaves(hdyn, b, bi)
00258                     print_nn(bi, 2);
00259             }
00260         }
00261     }
00262 }
00263 
00264 local void test_kepler(hdyn *b)
00265 {
00266     for_all_nodes(hdyn,b,bi) {
00267         if (bi->get_kepler()) {
00268             if (bi->is_top_level_node()) {
00269                 cerr << " test_kepler: top level ";
00270                 bi->pretty_print_node(cerr); cerr << "has kepler \n";
00271                 pp3(bi, cerr);
00272             }
00273         }
00274     }
00275 }
00276 
00277 
00278 
00279 // Triple debugging...
00280 
00281 local void print_triple_stats(hdyn* root, hdyn* b)
00282 {
00283     if (!b->is_top_level_node()) return;
00284     if (b->n_leaves() != 3) return;
00285 
00286     hdyn* ss = b->get_oldest_daughter();
00287     hdyn* bs = ss->get_younger_sister();
00288     if (ss->is_parent()) {
00289         hdyn* tmp = ss;
00290         ss = bs;
00291         bs = tmp;
00292     }
00293 
00294     // Triple is (ss, bs), with ss single, bs double.
00295 
00296     real mss = ss->get_mass();
00297     vector pos_ss = b->get_pos() + ss->get_pos();
00298     vector vel_ss = b->get_vel() + ss->get_vel();
00299     hdyn* bs1 = bs->get_oldest_daughter();
00300     hdyn* bs2 = bs1->get_younger_sister();
00301     real mb1 = bs1->get_mass();
00302     real mb2 = bs2->get_mass();
00303     vector pos_bs1 = b->get_pos() + bs->get_pos() + bs1->get_pos();
00304     vector vel_bs1 = b->get_vel() + bs->get_vel() + bs1->get_vel();
00305     vector pos_bs2 = b->get_pos() + bs->get_pos() + bs2->get_pos();
00306     vector vel_bs2 = b->get_vel() + bs->get_vel() + bs2->get_vel();
00307 
00308     real pot_1 = -mss * (mb1+mb2) / abs(ss->get_pos() - bs->get_pos());
00309     real pot_2 = -mss * mb1 / abs(pos_ss - pos_bs1)
00310                  -mss * mb2 / abs(pos_ss - pos_bs2);
00311     real pot_b = -mb1 * mb2 / abs(pos_bs1 - pos_bs2);
00312 
00313     real pot_ext = 0;
00314     for_all_daughters(hdyn, root, x) {
00315         if (x != b)
00316             pot_ext -= x->get_mass() * (mss/abs(x->get_pos() - pos_ss)
00317                                         + mb1/abs(x->get_pos() - pos_bs1)
00318                                         + mb2/abs(x->get_pos() - pos_bs2));
00319     }
00320 
00321     real ke = 0.5 * (mss*square(vel_ss) + mb1*square(vel_bs1) 
00322                                         + mb2*square(vel_bs2));
00323     // PRC(ke), PRL(pot_ext);
00324     // PRC(pot_2 + pot_b + ke), PRL(pot_ext + pot_2 + pot_b + ke);
00325 
00326     // print_binary_from_dyn_pair(ss, bs, 0, 0, true);
00327     // print_binary_from_dyn_pair(bs1, bs2, 0, 0, true);
00328 
00329     cerr << endl << "Triple " << b->format_label() << " at time "
00330          << b->get_system_time() << ":" << endl
00331          << "    Eint = " << pot_2 + pot_b + ke
00332          << "  Eint + phi_ext = " << pot_2 + pot_b + ke + pot_ext << endl;
00333 }
00334 
00335 
00336 
00337 local void print_binary_diagnostics(hdyn* bi)
00338 {
00339     bool diag = true;
00340 
00341     kepler *kep;
00342     hdyn *s = bi->get_binary_sister();
00343     real M = bi->get_parent()->get_mass();
00344 
00345     if (bi->get_kepler() == NULL) {
00346         kep = new kepler;
00347         kep->set_time(bi->get_time());
00348         kep->set_total_mass(M);
00349         kep->set_rel_pos(bi->get_pos() - s->get_pos());
00350         kep->set_rel_vel(bi->get_vel() - s->get_vel());
00351         kep->initialize_from_pos_and_vel();
00352     } else
00353         kep = bi->get_kepler();
00354 
00355     // if (kep->get_separation() < kep->get_semi_major_axis())
00356     //    diag = false;
00357 
00358     if (diag) {
00359 
00360 #if 0               
00361         cerr << "\nLow-level node bi = ", bi->print_label(cerr);
00362         cerr << endl;
00363         PRI(4); PRL(bi->get_time());
00364 
00365         int p = cerr.precision(INT_PRECISION);
00366         PRI(4); cerr << "top-level: ",
00367         PRL(bi->get_top_level_node()->get_time());
00368         cerr.precision(p);
00369 
00370         pp2(bi->get_top_level_node(), cerr, 2);
00371         PRI(4);
00372         PRL(bi->get_top_level_node()->get_valid_perturbers());
00373         PRI(4); PRL(bi->get_top_level_node()->get_n_perturbers());
00374 #endif
00375 
00376         if (bi->get_kepler())
00377             cerr << "    bi unperturbed";
00378         else
00379             cerr << "    bi perturbed";
00380 
00381         real r = kep->get_separation();
00382         real E = kep->get_energy();
00383         real a = r;
00384         if (E < 0) a = min(r, kep->get_semi_major_axis());
00385 
00386         cerr << ", -E/mu = " << -E
00387              << "  P = " << 2*M_PI * sqrt(a*a*a/M)
00388              << "  e = " << kep->get_eccentricity()
00389              << endl
00390              << "    sma = " << kep->get_semi_major_axis()
00391              << "  r = " << r
00392              << endl;
00393 
00394         PRI(4);
00395         if (bi->get_kepler()) PRC(bi->get_unperturbed_timestep());
00396         PRL(bi->get_timestep());
00397     }
00398 
00399     if (bi->get_kepler() == NULL) delete kep;
00400 }
00401 
00402 
00403 
00404 local void check_unperturbed(hdyn* bi, bool& tree_changed)
00405 {
00406     // Check for unperturbed motion.
00407 
00408     // This is the ONLY place in kira where unperturbed motion
00409     // (of any sort) is initiated.
00410 
00411     // The unperturbed criterion is defined in function
00412     // is_unperturbed_and_approaching()) (see hdyn_unpert.C).
00413 
00414     if (bi->get_kepler() == NULL && bi->get_eps2() == 0
00415         && (bi->is_unperturbed_and_approaching())) {
00416 
00417         // Must bring triple components up to date before
00418         // continuing (about to freeze the entire triple system).
00419 
00420         // *** In general, should bring ANY substructure
00421         // *** components up to date before proceeding
00422         // *** with unperturbed startup.
00423 
00424         // cerr << endl << "Unperturbed motion for "
00425         //      << bi->format_label()
00426         //      << " at time " << bi->get_time() << endl;
00427 
00428         if (bi->is_parent() || bi->get_binary_sister()->is_parent()) {
00429 
00430             bool synch = false;
00431 
00432             if (bi->is_parent()) {
00433                 bool sync = false;
00434                 for_all_nodes(hdyn, bi, bb) {
00435                     if (bb->get_time() < bi->get_time())
00436                         sync = true;
00437                 }
00438                 if (sync)
00439                     synchronize_tree(bi);       // OK because bi is not root
00440                 synch |= sync;
00441             }
00442 
00443             if (bi->get_binary_sister()->is_parent()) {
00444                 bool sync = false;
00445                 for_all_nodes(hdyn, bi->get_binary_sister(), bb) {
00446                     if (bb->get_time()
00447                         < bi->get_binary_sister()->get_time())
00448                         sync = true;
00449 
00450                 }
00451                 if (sync)
00452                     synchronize_tree(bi->get_binary_sister());
00453                 synch |= sync;
00454             }
00455 
00456             // If a newly-synchronized node is not on the
00457             // integration list (which must be the case, as we
00458             // only synchronize if a node is not up to date), then
00459             // there is a good chance that the scheduling list will
00460             // be corrupted, so force the list to be recomputed.
00461 
00462             if (synch)
00463                 tree_changed = true;
00464         }
00465 
00466         // Actual initialization of unperturbed motion:
00467 
00468         bi->startup_unperturbed_motion();
00469 
00470     }
00471 }
00472 
00473 
00474 
00475 // Slow binary functions.
00476 
00477 local inline void check_set_slow(hdyn *bi)
00478 {
00479     // Check for initiation of slow binary motion in a (normal-speed)
00480     // perturbed binary.
00481 
00482     // Calling function has already checked that kepler, slow,
00483     // and elder_sister are all NULL.
00484 
00485     // Criteria:        (0) bound!
00486     //                  (1) perturber list is valid
00487     //                  (2) perturbation less than cutoff
00488     //                  (3) just passed apastron
00489     //                  (4) components are single or unperturbed
00490     //
00491     // Apply these (inline) tests before passing control to the real
00492     // startup function.
00493 
00494     // if (streq(bi->get_parent()->format_label(), "(652a,652b)")) return;
00495 
00496     if (bi->get_max_slow_factor() > 1
00497         && (bi->is_leaf() || bi->get_oldest_daughter()->get_kepler())
00498         && (bi->get_younger_sister()->is_leaf()
00499             || bi->get_younger_sister()->get_kepler())
00500         && bi->get_valid_perturbers()
00501         && bi->get_perturbation_squared()
00502                 < bi->get_max_slow_perturbation_sq()/2
00503         && bi->passed_apo()
00504         && get_total_energy(bi, bi->get_younger_sister()) < 0) {
00505 
00506         // (Energy check shouldn't be necessary, as passed_apo should
00507         // never return true in an unbound system...)
00508 
00509 #if 0
00510         // Don't start slow motion if there are any binaries on the
00511         // perturber list.
00512 
00513         if (has_binary_perturbers(bi)) {
00514             cerr << "suppressing slow motion for "
00515                  << bi->get_parent()->format_label()
00516                  << " because of binary perturbers" << endl;
00517             return;
00518         }
00519 #endif
00520 
00521         bi->startup_slow_motion();
00522     }
00523 }
00524 
00525 local inline void check_extend_slow(hdyn *bi)
00526 {
00527     // Check for extension or termination of slow binary motion.
00528 
00529     // Calling function has already checked that kepler and elder_sister
00530     // are all NULL, and slow is currently set.
00531 
00532     // Apply this (inline) test in an inline function before passing
00533     // control to the real startup function.
00534 
00535     if (bi->passed_apo()) {
00536 
00537         // Use of function passed_apo should be OK most of the time, but
00538         // it may fail if an orbit is nearly circular.  Best to make sure
00539         // that we are at the right phase of the orbit before modifying
00540         // the slow motion.
00541 
00542         // For weakly perturbed binaries, energy should be nearly conserved,
00543         // so the period should be a reasonably good indicator of the time
00544         // since the last apocenter.
00545 
00546         real P = get_period(bi, bi->get_younger_sister());
00547 
00548         if (bi->get_time() - bi->get_slow()->get_t_apo() > 0.9 * P)
00549 
00550             bi->extend_or_end_slow_motion(P);
00551     }
00552 }
00553 
00554 
00555 
00556 local void merge_and_correct(hdyn* b, hdyn* bi, hdyn* bcoll, int full_dump)
00557 {
00558     // This intermediate function added mainly to allow
00559     // deletion of bi and bcoll after leaving merge_nodes.
00560 
00561     cerr << endl << "----------" << endl
00562          << "merge_and_correct: merging node "
00563          << bi->format_label();
00564     cerr << " with node " << bcoll->format_label() 
00565          << " at time " << bi->get_system_time() << endl;
00566 
00567     PRC(bi), PRC(bcoll), PRC(bi->get_parent()); PRL(cpu_time());
00568 
00569     // Note from Steve (9/01): Modified merge_nodes() to accept the
00570     // full_dump flag.  For a simple merger, could place the put_node()
00571     // calls here, but merge_nodes() may modify the tree (if bi and bcoll
00572     // aren't binary sisters), and this must be properly documented.
00573 
00574     hdyn* cm = bi->merge_nodes(bcoll, full_dump);
00575 
00576     delete bi;
00577     delete bcoll;
00578 
00579     b->get_kira_counters()->leaf_merge++;
00580 
00581     cerr << "after merge_nodes ";
00582     PRC(cm); PRL(cpu_time());
00583 
00584     cerr << "----------" << endl;
00585 }
00586 
00587 local inline void check_periapo(hdyn * bi) {
00588 
00589   // Just bookkeeping for stellar orbits.
00590 
00591 #ifdef CHECK_PERI_APO_CLUSTER
00592     bi->check_periapo_node();
00593 #endif
00594 }
00595 
00596 local hdyn* check_and_merge(hdyn* bi, int full_dump)
00597 {
00598     hdyn * bcoll;
00599     if ((bcoll = bi->check_merge_node()) != NULL) {
00600 
00601         // cerr << "check_and_merge: "; PRL(bcoll);
00602 
00603         hdyn* b = bi->get_root();
00604 
00605         merge_and_correct(b, bi, bcoll, full_dump);
00606 
00607         // Check for multiple mergers.  Note that we check *all*
00608         // stars for merging, whether or not they are in the
00609         // current block.
00610         //
00611         // This is perhaps more than we really want (Steve, 12/98).
00612 
00613         bool merge_flag = true;
00614         while (merge_flag) {
00615 
00616             merge_flag = false;
00617 
00618             for (hdyn* bb = b;
00619                  (bb != NULL) && !merge_flag;   
00620                  bb = (hdyn*) bb->next_node(b)) {
00621 
00622                 if (bb->is_leaf()) {
00623                     hdyn* bcoll2 = bb->check_merge_node();
00624                     if (bcoll2 != NULL) {
00625                         // cerr << "check_and_merge (2): "; PRL(bcoll2);
00626                         merge_and_correct(b, bb, bcoll2, full_dump);
00627                         merge_flag = true;
00628                     }
00629                 }
00630             }
00631         }
00632     }
00633     // cerr << "return from check_and_merge: "; PRL(bcoll);
00634 
00635     return bcoll;
00636 }
00637 
00638 
00639 
00640 // Define TIME_LIST in order to time various parts of integrate_list.
00641 
00642 //#define TIME_LIST
00643 
00644 local int integrate_list(hdyn * b,
00645                          hdyn ** next_nodes, int n_next,
00646                          bool exact, bool & tree_changed,
00647                          int full_dump,
00648                          real r_reflect)
00649 {
00650     static bool restart_grape = true;
00651     static bool reset_force_correction = true;  // no longer used
00652 
00653     int return_fac = 1;
00654 
00655     int i, steps = 0;
00656     xreal sys_t = next_nodes[0]->get_system_time();
00657 
00658     //    cerr << "At stars of Integrate_list: sys_t = " << sys_t << endl;
00659 
00660     // Code to time specific force-calculation operations:
00661 
00662     real cpu0, cpu1;
00663 
00664 #ifdef TIME_LIST
00665 
00666     int kmax = 1;
00667 
00668     for (int k = 0; k < n_next; k++) {
00669         hdyn* bi = next_nodes[k];
00670 
00671         if (bi->name_is("(13a,13b)")
00672             && bi->get_kepler() == NULL
00673             && bi->find_perturber_node()
00674             && bi->find_perturber_node()->get_n_perturbers() > 0
00675             ) {
00676 
00677             // Found the particle.  Clean up the rest of the list.
00678 
00679             for (int kk = 0; kk < n_next; kk++)
00680                 if (kk != k)
00681                     next_nodes[kk]->set_timestep(VERY_LARGE_NUMBER);
00682             n_next = 1;
00683             next_nodes[0] = bi;
00684 
00685             int p = cerr.precision(HIGH_PRECISION);
00686             cerr << endl << "timing " << bi->format_label()
00687                  << " at time " << bi->get_system_time() << endl;
00688             if (bi->is_low_level_node()) {
00689                 PRL(bi->get_top_level_node()->format_label());
00690                 if (bi->find_perturber_node()) {
00691                     PRL(bi->find_perturber_node()->format_label());
00692                     PRL(bi->find_perturber_node()->get_n_perturbers());
00693                 }
00694             }
00695             cerr.precision(p);
00696 
00697             kmax = 25000;
00698             cpu0 = cpu_time();
00699         }
00700     }
00701 #endif
00702 
00703     // Separate the force calculation from the rest for GRAPE implementation.
00704 
00705     xreal t_next = next_nodes[0]->get_next_time();
00706 
00707 #ifdef TIME_LIST
00708     for (int k = 0; k < kmax; k++) {
00709 #endif
00710 
00711 #ifdef T_DEBUG
00712 //if (sys_t > T_DEBUG) cerr << 41 << endl << flush;
00713 #endif
00714 
00715     calculate_acc_and_jerk_for_list(b, next_nodes, n_next, t_next,
00716                                     exact, tree_changed,
00717                                     reset_force_correction,  // no longer used
00718                                     restart_grape);
00719 
00720 #ifdef T_DEBUG
00721 //if (sys_t > T_DEBUG) cerr << 42 << endl << flush;
00722 #endif
00723 
00724 #ifdef TIME_LIST
00725     }
00726     if (kmax > 1) cpu1 = cpu_time();
00727 #endif
00728 
00729     // Apply corrector and redetermine timesteps.
00730 
00731     bool reinitialize = false;
00732 
00733 #ifdef TIME_LIST
00734     for (int k = 0; k < kmax; k++) {
00735 #endif
00736 
00737     bool diag = false;
00738 
00739     for (i = 0; i < n_next; i++) {
00740 
00741         hdyn *bi = next_nodes[i];
00742 
00743         if (bi && bi->is_valid()) {
00744 
00745             if (!bi->get_kepler()) {
00746 
00747                 if (diag) cerr << " perturbed correction for "
00748                                << bi->format_label() << endl;
00749 
00750 #ifdef T_DEBUG
00751 //if (sys_t > T_DEBUG) cerr << 43 << endl << flush;
00752 #endif
00753 
00754                 if (!bi->correct_and_update()) {
00755 
00756 #ifdef T_DEBUG
00757 //if (sys_t > T_DEBUG) cerr << 44 << endl << flush;
00758 #endif
00759 
00760                     // A problem has occurred during the step, presumably
00761                     // because of a hardware error on the GRAPE.
00762 
00763                     // Recompute acc and jerk on the front end (no bookkeeping
00764                     // yet) and retry once.  (Steve 9/98)
00765 
00766                     if (bi->get_kira_diag()->grape
00767                         && bi->get_kira_diag()->grape_level > 0)
00768                         cerr << "retrying force calculation for "
00769                              << bi->format_label() << endl;
00770 
00771                     // Better do an exact calculation, as we can't (yet) call
00772                     // correct_acc_and_jerk() to correct a single particle...
00773                     // This may run into problems with slow binaries, however.
00774 
00775                     bi->clear_interaction();
00776                     bi->calculate_acc_and_jerk(true);
00777                     bi->set_valid_perturbers(false);
00778 
00779                     if (bi->is_top_level_node()
00780                         && b->get_external_field() > 0) {
00781                         vector acc, jerk;
00782                         real pot;
00783                         get_external_acc(bi,
00784                                          bi->get_pred_pos(),
00785                                          bi->get_pred_vel(),
00786                                          pot, acc, jerk);
00787                         bi->inc_pot(pot);
00788                         bi->inc_acc(acc);
00789                         bi->inc_jerk(jerk);
00790                     }
00791 
00792                     if (!bi->correct_and_update()) {
00793 
00794                         cerr << endl
00795                              << "Failed to correct hardware error for "
00796                              << bi->format_label() << " at time "
00797                              << bi->get_system_time() << endl << endl;
00798                         err_exit("Run terminated in integrate_list");
00799 
00800                     } else {
00801 
00802                         // Should we always print a message here, or only
00803                         // if GRAPE diagnostics are enabled...?
00804 
00805                         cerr << endl
00806                              << "Corrected apparent GRAPE"
00807                              << " error for "
00808                              << bi->format_label() << " at time "
00809                              << bi->get_system_time();
00810 #if defined(STARLAB_HAS_GRAPE4)
00811                         cerr << " (chip " << get_grape_chip(bi) << ")";
00812 #endif
00813                         cerr << endl;
00814 
00815                         if (bi->get_kira_diag()->grape) {
00816                             if (bi->get_kira_diag()->grape_level > 0) {
00817                                 cerr << "recomputed  "; PRL(bi->get_acc());
00818                                 PRI(12); PRL(bi->get_jerk());
00819                                 // PRI(12); PRL(bi->get_pos());
00820                                 // PRI(12); PRL(bi->get_vel());
00821                                 cerr << endl;
00822                             }
00823                             return_fac = -1;
00824                         }
00825                     }
00826                 }
00827 
00828                 bi->init_pred();
00829                 bi->store_old_force();
00830 
00831                 // Note that old_acc = acc at the end of a step.
00832 
00833 
00834 #if 0000
00835                 if (bi->is_parent()
00836                     && (bi->name_is("(5394,21337)")
00837                         || bi->name_is("(21337,5394)"))) {
00838                     cerr << endl;
00839                     pp3(bi);
00840                     cerr << endl;
00841                     print_nn(bi, 1);
00842                     PRC(bi->get_nn()); PRL(bi->get_d_nn_sq());
00843                     cerr << endl;
00844                     bi->print_pert();
00845                     cerr << endl;
00846                 }
00847 #endif
00848 
00849 
00850             } else {
00851 
00852                 if (bi->get_eps2() != 0)        // Excessively cautious?
00853                     err_exit("integrate_list invoked with non-zero softening");
00854 
00855                 if (diag) {
00856                     cerr << "unperturbed motion for "
00857                          << bi->format_label() << endl;
00858                     if (bi->get_nn())
00859                         cerr << "nn = " << bi->get_nn()->format_label()
00860                              << endl;
00861                 }
00862 
00863                 // As of 3/99, integrate_unperturbed_motion returns true
00864                 // iff bi is still an unperturbed binary after the step.
00865 
00866                 hdyn* parent = bi->get_parent();
00867                 bool top_level = parent->is_top_level_node();
00868 
00869                 bool pert = bi->is_perturbed_cpt();   // false iff bi is
00870                                                       // fully unperturbed
00871 
00872                 if (!bi->integrate_unperturbed_motion(reinitialize)) {
00873 
00874                     // Unperturbed motion is over.  Either the binary
00875                     // containing bi has become perturbed or it has merged.
00876 
00877                     if (bi->is_valid()) {
00878 
00879                         // Parent of bi is a newly perturbed binary.
00880                         // Add it to the list if the binary was top-level
00881                         // and fully perturbed previously (i.e. don't
00882                         // bother with partial unperturbed orbits).
00883 
00884                         if (top_level && !pert)
00885                             parent->add_to_perturbed_list(1);
00886 
00887                     } else {
00888 
00889                         // Seem to have had a merger.  Remove binary from
00890                         // the list, if necessary.
00891 
00892                         if (top_level && pert)
00893                             parent->remove_from_perturbed_list(1);
00894 
00895                     }
00896                 }
00897 
00898                 // Note that it is possible for integrate_unperturbed_motion
00899                 // to delete bi.  Must take this possibility into account
00900                 // below.
00901 
00902                 if (!bi->is_valid())
00903                     next_nodes[i] = NULL;
00904 
00905             }
00906         }
00907     }
00908 
00909 #ifdef TIME_LIST
00910     }
00911 
00912 
00913     if (kmax > 1) {
00914         cerr << "CPU times: "
00915              << (cpu1-cpu0)/kmax << "  "
00916              << (cpu_time()-cpu1)/kmax << endl;
00917         exit(0);
00918     }
00919 #endif
00920 
00921 #ifdef T_DEBUG
00922 //if (sys_t > T_DEBUG) cerr << 45 << endl << flush;
00923 #endif
00924 
00925 #if 111111
00926     if (r_reflect > 0) {
00927         for (i = 0; i < n_next; i++) {
00928             hdyn *bi = next_nodes[i];
00929             if (bi && bi->is_valid()) {
00930                 real ri2 = square(bi->get_pos());
00931 
00932                 // Apply reflection if necessary.  Don't worry about error
00933                 // introduced in the jerk -- particle is at the edge of the
00934                 // system, so jerk change should be small (and no effect on
00935                 // other particles, as this option should only be used when
00936                 // ignore_internal is true.
00937 
00938                 if (ri2 > 1) {
00939                     real vr = bi->get_pos() * bi->get_vel();
00940                     bi->set_vel(bi->get_vel() - 2*vr*bi->get_pos()/ri2);
00941                 }
00942 
00943                 // cerr << endl << "reflected " << bi->format_label()
00944                 //      << " at time " << bi->get_time() << endl << flush;
00945             }
00946         }
00947     }
00948 #endif
00949 
00950 #ifdef T_DEBUG
00951 //if (sys_t > T_DEBUG) cerr << 46 << endl << flush;
00952 #endif
00953 
00954     // Complete all steps before modifying binary structure...
00955 
00956     diag = false;
00957     for (i = 0; i < n_next; i++) {
00958 
00959         hdyn *bi = next_nodes[i];
00960 
00961         if (bi && bi->is_valid()) {
00962 
00963             if (!bi->is_low_level_node()) {
00964 
00965                // Not much to do for a top-level node -- just update counters.
00966 
00967                 if (bi->is_leaf())
00968                     b->get_kira_counters()->step_top_single++;
00969                 else
00970                     b->get_kira_counters()->step_top_cm++;
00971 
00972                 // Diagnostics:
00973 
00974                 if (diag) {
00975                     cerr << "\nTop-level node bi = " << bi->format_label()
00976                          << " at time " << bi->get_time() << endl;
00977                     cerr << "timestep = " << bi->get_timestep() << endl;
00978                     PRL(bi->get_acc());
00979                     PRL(bi->get_jerk());
00980                 }
00981 
00982             } else {
00983 
00984                 update_binary_sister(bi);
00985 
00986                 b->get_kira_counters()->step_low_level++;
00987 
00988                 if (bi->get_slow())
00989                     b->get_kira_counters()->inc_slow(bi->get_kappa());
00990 
00991                 // print_binary_diagnostics(bi);
00992 
00993                 // Check for new unperturbed motion.
00994 
00995                 if (!bi->get_kepler()) {
00996 
00997                     if (bi->get_eps2() == 0) {
00998 
00999                         // Check for unperturbed motion:
01000 
01001                         check_unperturbed(bi, tree_changed);
01002 
01003                         // Check to see if the binary containing bi has just
01004                         // become unperturbed.
01005 
01006                         if (bi->get_parent()->is_top_level_node()
01007                             && !bi->is_perturbed_cpt())
01008                             bi->get_parent()->remove_from_perturbed_list(2);
01009                     }
01010                 }
01011 
01012                 // Check for new or modified slow motion.  Note that we
01013                 // recheck the kepler pointer, just in case...
01014 
01015                 // There is some redundancy here, since the checks may
01016                 // repeat those in is_unperturbed_and_approaching, and
01017                 // also only want to check immediately after apocenter,
01018                 // but worry about these issues later.
01019                 //                                      (Steve, 7/99)
01020 
01021                 if (!bi->get_kepler()) {
01022 
01023                     // Only check on elder sister (should never see younger
01024                     // sister in any case).
01025 
01026                     if (!bi->get_elder_sister()) {
01027 
01028                         if (bi->get_slow())
01029                             check_extend_slow(bi);
01030                         else
01031                             check_set_slow(bi);
01032 
01033                         // Need to update counters for slow motion here.
01034                     }
01035                 }
01036             }
01037 
01038             steps++;
01039         }
01040     }
01041 
01042 #ifdef T_DEBUG
01043 //if (sys_t > T_DEBUG) cerr << 47 << endl << flush;
01044 #endif
01045 
01046     // Probably makes more sense to check for encounters for all stars
01047     // before testing for mergers, tree changes, etc. (Steve, 3/24/00).
01048 
01049     if (b->get_stellar_encounter_criterion_sq() > 0)
01050         for (i = 0; i < n_next; i++) 
01051             check_print_close_encounter(next_nodes[i]);
01052 
01053     // ONLY ONE tree reconstruction (following a collision or
01054     // otherwise) is currently permitted per block step.
01055 
01056     //++ Note from Steve to Steve, 7/98.  Could we relax the
01057     //++ requirement of only one tree reconstruction per step?
01058 
01059     for (i = 0; i < n_next; i++) {
01060 
01061         // Note somewhat convoluted calling sequence to merge nodes:
01062         //
01063         //      check_and_merge
01064         //          - calls check_merge_node  to locate bcoll (if any)
01065         //          - calls merge_and_correct to merge bi and bcoll
01066         //                + calls merge_nodes to do the merging and clean up
01067         //                + *deletes* both nodes bi and bcoll
01068         //          - attempts to handle multiple mergers.
01069         //
01070         // Routine merge_and_correct takes care of all corrections
01071         // associated with mergers.
01072         //
01073         // ** This is now mostly handled by merge_nodes (Steve, 3/9/00). **
01074 
01075         hdyn *bi = next_nodes[i];
01076 
01077         if (bi && bi->is_valid()) {
01078 
01079             // First check for peri- or apoclustron passage.
01080 
01081             check_periapo(bi);
01082 
01083             hdyn* bcoll = check_and_merge(bi, full_dump);
01084 
01085             // cerr << "integrate_list: "; PRL(bcoll);
01086 
01087             if (bcoll) {
01088 
01089                 // Merger occurred and tree has to be rebuilt.  No further
01090                 // tree reorganization is permitted during this block step.
01091                 // Perturber and other lists should already be up to date,
01092                 // and the merging nodes have already been replaced by
01093                 // their center of mass.
01094 
01095                 // If bcoll is non-NULL, then both bi and bcoll have
01096                 // *already* been deleted...
01097 
01098                 // PRC(bi), PRL(bcoll);
01099 
01100                 // *** Must have check_and_merge take care of full_dump
01101                 // *** output in this case...
01102 
01103                 tree_changed = true;
01104                 restart_grape = true;
01105                 reset_force_correction = true;  // no longer used
01106 
01107                 kira_synchronize_tree(b);
01108                 steps += b->n_leaves();
01109 
01110                 cerr << "call initialize_system_phase2() "
01111                      << "from integrate_list [1]"
01112                      << " at time " << b->get_system_time() << endl;
01113 
01114                 initialize_system_phase2(b, 1, true);
01115                 b->reconstruct_perturbed_list();
01116 
01117                 PRL(tree_changed);
01118 
01119                 // Remove merged star and its merger companion from the
01120                 // integration list.  Note that the list may be still
01121                 // be incomplete on return, as multiple merger companions
01122                 // may remain on it.
01123 
01124                 next_nodes[i] = NULL;
01125                 for (int j = 0; j < n_next; j++) {
01126                     if (next_nodes[j] == bcoll)
01127                         next_nodes[j] = NULL;
01128                 }
01129 
01130                 return return_fac* steps;
01131             }
01132         }
01133     }
01134 
01135 #ifdef T_DEBUG
01136 //if (sys_t > T_DEBUG) cerr << 48 << endl << flush;
01137 #endif
01138 
01139     if (reinitialize) {
01140 
01141         kira_synchronize_tree(b);
01142         steps += b->n_leaves();
01143 
01144         cerr << "call initialize_system_phase2() from integrate_list [2]"
01145              << " at time " << b->get_system_time() << endl;
01146 
01147         initialize_system_phase2(b, 2, true);
01148         b->reconstruct_perturbed_list();
01149 
01150         tree_changed = true;
01151         restart_grape = true;
01152         reset_force_correction = true;  // no longer used
01153 
01154     } else {
01155 
01156         for (i = 0; i < n_next; i++) {
01157 
01158             hdyn *bi = next_nodes[i];
01159 
01160             if (bi && bi->is_valid()) {
01161 
01162                 hdynptr* cm_list = NULL;
01163                 int n_list = 0;
01164 
01165                 if (bi->is_low_level_node() || bi->is_parent()) {
01166 
01167                     // Make a list of CM nodes in the current clump.
01168 
01169                     for_all_nodes(hdyn, bi, bb)
01170                         if (bb->is_parent()) n_list++;
01171 
01172                     if (n_list > 0) {
01173                         cm_list = new hdynptr[n_list];
01174                         n_list = 0;
01175                         for_all_nodes(hdyn, bi, bb)
01176                             if (bb->is_parent()) cm_list[n_list++] = bb;
01177                     }
01178                 }
01179 
01180                 // Check (and modify, if necessary) the tree structure.
01181                 // Save some data on bi, in case the tree is restructured.
01182 
01183                 hdyn *top_level = bi->get_top_level_node();
01184                 hdyn *od = NULL, *yd = NULL;
01185                 bool pert = false;
01186 
01187                 if (top_level->is_parent()) {
01188                     od = top_level->get_oldest_daughter();
01189                     yd = od->get_younger_sister();
01190                     pert = od->is_perturbed_cpt();
01191                 }
01192 
01193                 int adjust_tree = bi->adjust_tree_structure(full_dump);
01194 
01195                 if (adjust_tree) {
01196 
01197                     b->get_kira_counters()->tree_change++;
01198 
01199                     reset_force_correction = true;      // no longer used
01200                     restart_grape = true;
01201                     tree_changed = true;
01202 
01203                     // Check to see if the unperturbed binary list needs
01204                     // to be updated.
01205 
01206                     // As of 3/99, if adjust_tree_structure returns true (> 0),
01207                     // its value indicates the type of adjustment:
01208                     //
01209                     //  0       no adjustment
01210                     //  1       low-level combine
01211                     //  2       top-level combine (direct)
01212                     //  3       top-level split (direct)
01213                     //  4       top-level combine (indirect)
01214                     //  5       top-level split (indirect)
01215                     //  6       low-level synchronization
01216                     //
01217                     // Top-level changes may be driven directly by top-level
01218                     // nodes (2 and 3), or they may be forced by changes at
01219                     // lower levels (4 and 5).  The unpleasant logic below
01220                     // seems unavoidable given the construction of
01221                     // adjust_tree_structure() and the requirements of
01222                     // perturbed_list.
01223 
01224                     // PRC(adjust_tree); PRL(pert);
01225 
01226                     if (adjust_tree == 1) {
01227 
01228                         // Low-level combine, but still possible that the
01229                         // identity of the top-level node has changed.
01230 
01231                         if (bi->get_top_level_node() != top_level
01232                             && pert) {
01233                             top_level->remove_from_perturbed_list(3);
01234                             bi->get_top_level_node()->add_to_perturbed_list(2);
01235                         }
01236 
01237                     } else if (adjust_tree == 2) {
01238 
01239                         // Top-level combine.  Node bi is now one component
01240                         // of a new top-level binary.  (In this case, bi is
01241                         // the same as top_level.)
01242 
01243                         if (pert) bi->remove_from_perturbed_list(4);
01244 
01245                         if (bi->is_perturbed_cpt())
01246                             bi->get_parent()->add_to_perturbed_list(3);
01247 
01248                         yd = bi->get_binary_sister();
01249 
01250                         if (yd->is_perturbed_cm())
01251                             yd->remove_from_perturbed_list(5);
01252 
01253                     } else if (adjust_tree == 3) {
01254 
01255                         // Top-level split.  Binary CM node bi = top_level
01256                         // no longer exists, but its components od and yd
01257                         // are now at the top level.
01258 
01259                         // Update perturbed_list as necessary.
01260 
01261                         if (pert) top_level->remove_from_perturbed_list(6);
01262 
01263                         if (od->is_perturbed_cm())
01264                             od->add_to_perturbed_list(4);
01265 
01266                         if (yd->is_perturbed_cm())
01267                             yd->add_to_perturbed_list(5);
01268 
01269                     } else if (adjust_tree == 4) {
01270 
01271                         // Top-level combine was induced by internal
01272                         // reorganization.  Node bi is now part of a new
01273                         // top-level binary, but we don't necessarily
01274                         // know which component...
01275 
01276                         top_level = bi->get_top_level_node();
01277                         od = top_level->get_oldest_daughter();
01278                         yd = od->get_younger_sister();
01279 
01280                         if (od->is_perturbed_cm())
01281                             od->remove_from_perturbed_list(7);
01282 
01283                         if (yd->is_perturbed_cm())
01284                             yd->remove_from_perturbed_list(8);
01285 
01286                         if (od->is_perturbed_cpt())
01287                             top_level->add_to_perturbed_list(6);
01288 
01289                     } else if (adjust_tree == 5) {
01290 
01291                         // Top-level split was induced by internal
01292                         // reorganization.  Node top_level no longer
01293                         // exists, but its components od and yd are now
01294                         // at the top level.
01295 
01296                         if (pert) top_level->remove_from_perturbed_list(9);
01297 
01298                         if (od->is_perturbed_cm())
01299                             od->add_to_perturbed_list(7);
01300 
01301                         if (yd->is_perturbed_cm())
01302                             yd->add_to_perturbed_list(8);
01303 
01304                     }
01305 
01306 #ifndef USE_GRAPE
01307 
01308                     if (b->get_kira_diag()->kira_main) {
01309                         cerr << "\nAfter adjusting tree structure... \n";
01310                         cerr << "Time = " << next_nodes[0]->get_system_time()
01311                              << " single_steps = "
01312                              << b->get_kira_counters()->step_top_single
01313                              << endl;
01314                         print_recalculated_energies(b);
01315                         // pp3(bi->get_top_level_node(), cerr);
01316                         flush(cerr);
01317                     }
01318 
01319 #endif
01320 
01321                     // Set next_nodes[i] = NULL for any center of mass in
01322                     // the clump that has been adjusted, so we can use the
01323                     // rest of the array in evolve_system on return from
01324                     // integrate_list.
01325 
01326                     if (cm_list && n_list > 0) {
01327                         for (int j = 0; j < n_next; j++) {
01328                             if (!next_nodes[j]->is_valid()) {
01329 
01330 //                              cerr << "next_nodes[" <<j<< "] = "
01331 //                                   << next_nodes[j]
01332 //                                   << " is no longer valid" << endl;
01333 
01334                                 next_nodes[j] = NULL;
01335                             } else
01336                                 for (int k = 0; k < n_list; k++)
01337                                     if (next_nodes[j] == cm_list[k]) {
01338                                         next_nodes[j] = NULL;
01339                                         break;
01340                                     }
01341                         }
01342                     }
01343                     if (cm_list) delete [] cm_list;
01344 
01345                     return return_fac*steps;
01346                                         // NOTE: we currently return after
01347                                         //       the FIRST tree rearrangement,
01348                                         //       so we can only have one
01349                                         //       restructuring per block time
01350                                         //       step.
01351                 }
01352                 if (cm_list) delete [] cm_list;
01353             }
01354         }
01355     }
01356 
01357     return return_fac*steps;
01358 }
01359 
01360 
01361 
01362 local void full_reinitialize(hdyn* b, xreal t, bool verbose)
01363 {
01364     cerr << "\nReinitializing system at time " << t << endl;
01365 
01366     real cpu_0 = cpu_time();
01367 
01368     b->set_system_time(t);
01369     // b->to_com();
01370     initialize_system_phase1(b, t);
01371     initialize_system_phase2(b, 3,
01372                              false);                    // "false" here means
01373                                                         // timesteps are only
01374                                                         // set if zero
01375     // Reset and save d_min_sq().
01376 
01377     int n = 0;
01378     real mass = 0;
01379     real pot = 0;
01380     for_all_daughters(hdyn, b, bb) {
01381         n++;
01382         mass += bb->get_mass();
01383         pot += bb->get_mass()*bb->get_pot();            // total potential
01384     }
01385 
01386     // Only want the internal potential, which is counted twice in pot.
01387 
01388     pot -= get_external_pot(b);
01389     pot /= 2;
01390     PRC(mass); PRC(pot);
01391 
01392     real rvirial = -0.5*mass*mass/pot;
01393     PRC(rvirial); PRL(n);
01394 
01395     cerr << "old "; PRC(b->get_d_min_sq());
01396     real d_min_sq = square(b->get_d_min_fac()*rvirial/n);
01397     b->set_d_min_sq(d_min_sq);
01398     cerr << "new "; PRL(b->get_d_min_sq());
01399 
01400     putrq(b->get_log_story(), "kira_d_min_sq", d_min_sq);
01401 
01402     b->reconstruct_perturbed_list();
01403 
01404     // Quietly reinitialize all kepler structures.
01405     // (Repeats actions taken by get_hdyn() on startup.)
01406 
01407     b->initialize_unperturbed();
01408 
01409     if (verbose) {
01410         cerr << "CPU time for reinitialization = "
01411              << cpu_time() - cpu_0 << endl;
01412     }
01413 }
01414 
01415 local bool check_sync(hdyn* b)
01416 {
01417     bool need_new_list = false;
01418 
01419     for_all_nodes(hdyn, b, bb)
01420         if (bb->get_time() != b->get_system_time()
01421              && bb->get_kepler() == NULL) {
01422           cerr << "check_sync warning:  node "
01423                << bb->format_label() << " not synchronized at time "
01424                << b->get_system_time() << "; node time = " << bb->get_time()
01425                << endl;
01426           need_new_list = true;
01427         }
01428 
01429     return need_new_list;
01430 }
01431 
01432 local void backward_step_exit(hdyn* b, real ttmp, real t,
01433                               hdyn** next_nodes, int n_next)
01434 {
01435 
01436     cerr << "evolve_system: time went backwards!\n";
01437 
01438     cerr.precision(HIGH_PRECISION);
01439     PRC(ttmp); PRC(b->get_system_time()); PRL(t);
01440 
01441     for (int i = 0; i < n_next; i++) {
01442         cerr << endl;
01443         PRC(i); next_nodes[i]->pretty_print_node(cerr);
01444         cerr << " "<< next_nodes[i]->get_time()<< " ";
01445         cerr << next_nodes[i]->get_next_time()<<endl;
01446         pp3(next_nodes[i]->get_top_level_node(), cerr);
01447     }
01448     put_node(cerr, *b, b->get_kira_options()->print_xreal);
01449     exit(0);
01450 }
01451 
01452 local void check_binary_scheduling(hdyn* b,
01453                                    hdyn** next_nodes,
01454                                    int n_next)
01455 {
01456     // Force the elder of two binary sisters to be integrated.
01457     // Is this function necessary?  (Steve, 7/00)
01458 
01459     // Old code (inefficient?):
01460 
01461 //      for (int i = 0; i < n_next; i++) {
01462 //      hdyn *bi = next_nodes[i];
01463 //
01464 //      if (bi->is_low_level_node()) {
01465 //
01466 //          hdyn *od = bi->get_parent()
01467 //                       ->get_oldest_daughter();
01468 //
01469 //          if (od->get_timestep() != bi->get_timestep()) {
01470 //              // cerr << "timesteps of sisters are different !! \n";
01471 //              od->set_timestep(bi->get_timestep());
01472 //          }
01473 //
01474 //          if (od->get_time() != bi->get_time()) {
01475 //              od->set_time(bi->get_time());
01476 //          }
01477 //
01478 //          next_nodes[i] = bi->get_parent()->get_oldest_daughter();
01479 //      }
01480 //      }
01481 
01482     // Should be better:
01483 
01484     for (int i = 0; i < n_next; i++) {
01485         hdyn *bi = next_nodes[i];
01486         if (bi->is_low_level_node()) {
01487 
01488             hdyn *od = bi->get_elder_sister();
01489             if (od) {
01490 
01491                 // We are a low-level younger sister.  Shouldn't happen!
01492 
01493                 if (od->get_timestep() != bi->get_timestep())
01494                     // cerr << "timesteps of sisters are different !! \n";
01495                     od->set_timestep(bi->get_timestep());
01496 
01497                 if (od->get_time() != bi->get_time())
01498                     od->set_time(bi->get_time());
01499 
01500                 next_nodes[i] = od;
01501             }
01502         }
01503     }
01504 }
01505 
01506 local inline void update_step(real t, real& ts, real dts)
01507 {
01508     while (ts < t)
01509         ts += dts;
01510 }
01511 
01512 
01513 
01514 local real internal_potential(hdyn* bb)
01515 {
01516     real epot, ekin, etot;
01517     calculate_energies(bb, bb->get_eps2(), epot, ekin, etot);
01518     return epot;
01519 }
01520 
01521 local void print_energy_from_pot(hdyn* b)
01522 {
01523     // Attempt faster energy computation using existing pot data.
01524 
01525     // NOTE: binary components' pots only include perturbers, *not* the
01526     // entire system, so we can't use these directly.  However, the pot
01527     // of the top-level node should be correct, apart from the internal
01528     // energy.  There will still be a tidal error in the case unperturbed
01529     // binaries...
01530 
01531     // ***** NOT WORKING YET.  There appears to be a residual error in
01532     // ***** the energy derived from pots.  Not clear if this is a bug
01533     // ***** in the computation of pot for a binary CM or if the error
01534     // ***** is inherent in the approximations made by kira...
01535     //
01536     //                                          Steve (6/99)
01537 
01538     return;
01539 
01540     real top_pot = 0, int_pot = 0;
01541 
01542     for_all_daughters(hdyn, b, bb) {
01543         top_pot += bb->get_mass()*bb->get_pot();
01544         if (bb->is_parent())
01545             int_pot += internal_potential(bb);
01546     }
01547 
01548     real kin = 0;
01549 
01550     for_all_leaves(hdyn, b, bb) {
01551         vector vel = hdyn_something_relative_to_root(bb, &hdyn::get_vel);
01552         kin += bb->get_mass()*square(vel);
01553     }
01554 
01555     top_pot *= 0.5;
01556     kin *= 0.5;
01557 
01558     int p = cerr.precision(INT_PRECISION);
01559     PRC(top_pot), PRC(int_pot), PRL(kin);
01560     PRL(get_external_pot(b));
01561     cerr << "energy_from_pot = " << kin+top_pot+int_pot+0.5*get_external_pot(b)
01562          << endl;
01563     cerr.precision(p);
01564 }
01565 
01566 // evolve_system:  Main integration loop.
01567 
01568 static hdyn **next_nodes = NULL;
01569 
01570 local void evolve_system(hdyn * b,             // hdyn array
01571                          real delta_t,         // time span of the integration
01572                          real dt_log,          // time step of the integration
01573                          int long_binary_out,
01574                          real dt_snap,         // snapshot output interval
01575                          real dt_sstar,        // timestep for single
01576                                                //     stellar evolution
01577                          real dt_esc,          // escaper removal
01578                          real dt_reinit,       // reinitialization interval
01579                          real dt_fulldump,     // full dump interval
01580                          bool exact,           // exact force calculation
01581                          real cpu_time_limit,
01582                          bool verbose,
01583                          bool save_snap_at_log, // save snap at log output
01584                          char* snap_save_file, // filename to save in
01585                          int n_stop)           // when to stop
01586 {
01587     // Modified order in which output/snapshots/reinitialization/etc. are
01588     // performed -- Steve, 7/01
01589 
01590     // Carried through option to ignore all internal forces
01591     // and added snapshot "reflection" option               -- Steve, 12/01.
01592 
01593     // Initialization:
01594 
01595     clean_up_files();
01596     cpu_init();
01597 
01598     real r_reflect = -1;
01599     if (find_qmatch(b->get_log_story(), "r_reflect")) {
01600         r_reflect = getrq(b->get_log_story(), "r_reflect");
01601         cerr << endl
01602              << "*** Reflecting boundary at radius " << r_reflect << " ***"
01603              << endl;
01604     }
01605 
01606     initialize_counters_from_log(b);
01607     kc_prev = *b->get_kira_counters();          // (make a local copy)
01608 
01609     kira_options *ko = b->get_kira_options();
01610     kira_diag *kd = b->get_kira_diag();
01611 
01612     real count = 0;
01613     real steps = 0;
01614     int grape_steps = 0;
01615     int snaps = 0;
01616 
01617     next_nodes = new hdyn *[2 * b->n_daughters()];      // Overkill?
01618 
01619     // bool next_flag[2 * b->n_daughters()];            // fails on SGI
01620     bool *next_flag = new bool[2 * b->n_daughters()];   // equivalent?
01621     real *last_dt = new real[2 * b->n_daughters()];
01622 
01623     set_n_top_level(b);
01624 
01625     // Establish limits on time steps.  Note that, other than the static
01626     // step_limit data, the "dt" data never propagate beyond this function,
01627     // so there is no particular reason to make them part of the hdyn class.
01628 
01629     real dt_max = min(dt_log, dt_sstar);        // system will be synchronized
01630                                                 // for stellar evolution occur
01631     dt_max = min(dt_max, dt_reinit);
01632     dt_max = min(dt_max, dt_fulldump);
01633     b->set_unpert_step_limit(dt_max);
01634 
01635     // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
01636 
01637     // Convenient for now to pass request for full dump and also the
01638     // dump interval via dt_snap...
01639     //
01640     // Full_dump options are becoming more complex.  Now, in addition
01641     // to specifying the full_dump frequency, we can also opt to produce
01642     // limited output to follow binary changes, and specify the length
01643     // of the worldline interval.  Worldline interval (time between
01644     // complete system dumps) is managed separately; other options are
01645     // managed via the full_dump variable (now int rather than bool):
01646     //
01647     //          full_dump  =  0                 // option off
01648     //                        1                 // dump all particles
01649     //                        2                 // track binary changes only
01650     //
01651     // Details if how these variables are used, specified and passed around
01652     // the system remain to be finalized.                       (Steve, 9/01)
01653     //
01654     // For now, we track all internal binary changes (makes the bookeeping and
01655     // reconstruction simpler -- read_bundle() should work as is).  Later, we
01656     // may decide to track only changes involvng the top-level nodes, in which
01657     // case the reconstruction code will have to become more sophisticated.
01658 
01659     int full_dump = 0;
01660     real n_dump = 1.0;                          // up to at least 30 seems OK!
01661 
01662     bool first_full_dump = false;
01663 
01664     if (dt_snap <= 0) {
01665 
01666         // Turn on full_dump mode, at frequency -dt_snap, or binary dump
01667         // mode.  Turn off regular snapshot output.  Complete output occurs
01668         // at intervals determined by dt_fulldump.
01669 
01670         n_dump = -dt_snap;
01671         dt_snap = VERY_LARGE_NUMBER;
01672 
01673         if (n_dump > 0)
01674             full_dump = 1;
01675         else
01676             full_dump = 2;
01677             
01678         // first_full_dump added by SPZ Jan 2000 to assure initial dump 
01679         // of snapshot to start worldbundle.
01680 
01681         first_full_dump = true;
01682         PRC(n_dump); PRL(full_dump);
01683     }
01684 
01685     // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
01686 
01687     // Complete the setup of static class data:
01688 
01689     real initial_step_limit = min(INITIAL_STEP_LIMIT, dt_max);
01690     initial_step_limit = min(initial_step_limit, dt_snap);
01691 
01692     real step_limit = min(dt_max, dt_snap);     // no initial_step_limit, note
01693 
01694     b->set_mbar(b->get_mass()/b->n_leaves());   // mass scale
01695     b->set_initial_step_limit(initial_step_limit);
01696     b->set_step_limit(step_limit);
01697 
01698     // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
01699 
01700     // The scheduling is such that the system will be synchronized
01701     // at *every* integer multiple of step_limit.
01702 
01703     // The behavior of the system is governed by the following times:
01704 
01705     real dt_sync = step_limit;
01706 
01707     // Check and flag some basic relationships between time scales.
01708 
01709     if (dt_reinit < dt_sync)
01710         err_exit("dt_reinit < dt_sync.");       // require dt_reinit >= dt_sync
01711     if (dt_esc < dt_sync)
01712         err_exit("dt_esc < dt_sync.");          // require dt_esc >= dt_sync
01713     if (dt_sstar < dt_sync)
01714         err_exit("dt_sstar < dt_sync.");        // require dt_sstar >= dt_sync
01715     if (dt_fulldump < dt_sync)                  // require dt_fulldump
01716         err_exit("dt_fulldump < dt_sync.");     //              >= dt_sync
01717 
01718     if (verbose) {
01719         if (dt_log < dt_sync)
01720             cerr << "Warning: dt_log < dt_sync, quoted errors unpredictable."
01721                  << endl;
01722         if (dt_snap < dt_sync)
01723             cerr << "Warning: dt_snap < dt_sync, no restart possible."
01724                  << endl;
01725         else if (dt_snap < dt_reinit)
01726             cerr << "Warning: dt_snap < dt_reinit, restart unpredictable."
01727                  << endl;
01728     }
01729 
01730     xreal t = b->get_time();            // current time
01731 
01732     real tt = t;                        // use to avoid xreal problems with
01733                                         // possible VERY_LARGE_NUMBERs below
01734                                         // -- could build this into xreal +,
01735                                         //    but may be too inefficient for
01736                                         //    general use
01737 
01738     real t_end = tt + delta_t;          // final time, at end of integration
01739     real t_log = tt;                    // time of next log output
01740     // if (t > 0) t_log += dt_log;
01741     real t_snap = tt + dt_snap;         // time of next snapshot output
01742     real t_sync = tt + dt_sync;         // time of next system synchronization
01743 
01744     // Changes by Steve (7/01):
01745 
01746     real t_esc = tt; // + dt_esc;       // time of next escaper check
01747                                         //      note: apply IMMEDIATE check
01748     real t_reinit = tt; // + dt_reinit; // time of next reinitialization
01749 
01750     // Frequency of internal escaper checks (write to story only):
01751 
01752     real dt_esc_check = min(dt_sync, 1.0/16);
01753     real t_esc_check = tt + dt_esc_check;
01754 
01755     // Time of next complete system dump (Steve, 9/01).
01756 
01757     real t_fulldump = tt;
01758 
01759     if (verbose) {
01760         cerr << endl;
01761         PRC(t), PRL(t_end);
01762         PRL(dt_sync);
01763         PRL(dt_log);
01764         PRL(long_binary_out);
01765         PRL(dt_snap);
01766         PRL(dt_esc);
01767         PRL(dt_reinit);
01768         PRL(dt_sstar);
01769         PRL(dt_sync);
01770         PRL(dt_fulldump);
01771 
01772         PRC(t_snap); PRC(t_log); PRC(t_sync); PRC(t_esc); PRL(t_fulldump);
01773 
01774         ko->print();
01775         kd->print();
01776     }
01777 
01778 #ifdef DUMP_DATA
01779     ofstream tmp_dump("TMP_DUMP");
01780 #endif
01781 
01782     // Initialize the system.  This is somewhat redundant, as immediate
01783     // reinitialization is scheduled within the while loop.  However,
01784     // we need to know time steps for fast_get_nodes_to_move().
01785 
01786     full_reinitialize(b, t, verbose);
01787 
01788     bool tree_changed = true;   // used by fast_get_nodes_to_move;
01789                                 // set by integration/evolution routines
01790 
01791 
01792 
01793 real *xxx = NULL;
01794 hdynptr *yyy = NULL;
01795 PRC(xxx); PRL(yyy);
01796 
01797 
01798 
01799     while (t <= t_end) {
01800 
01801 #ifdef T_DEBUG
01802 if (b->get_system_time() >= T_DEBUG) {
01803 
01804 //     pp3(b);
01805 
01806 //     cerr << "00" << endl << flush;
01807 //     for_all_daughters(hdyn, b, bb)
01808 //     if (bb->is_parent()) pp3(bb);
01809 //     cerr << "01" << endl << flush;
01810 
01811 //     cerr << "about to make a new real array" << endl << flush;
01812 //     xxx = new real[MAX_PERTURBERS];
01813 //     PRL(xxx);
01814 //     delete [] xxx;
01815 
01816      cerr << "0000" << endl << flush;
01817 
01818     cerr << "about to make a new real array" << endl << flush;
01819     xxx = new real[MAX_PERTURBERS];
01820     PRL(xxx);
01821     delete [] xxx;
01822 
01823     cerr << "about to make a new hdynptr array" << endl << flush;
01824     yyy = new hdynptr[MAX_PERTURBERS];
01825     PRL(yyy);
01826     delete [] yyy;
01827 
01828     if (b->get_system_time() >= 170.5) exit(0);
01829 }
01830 #endif
01831 
01832         int n_next;
01833         xreal ttmp;
01834 
01835         // Create the new time step list.
01836 
01837         fast_get_nodes_to_move(b, next_nodes, n_next, ttmp, tree_changed);
01838 
01839 
01840 #ifdef T_DEBUG
01841 if (ttmp > T_DEBUG) {
01842 
01843     cerr << 1 << endl << flush;
01844 
01845     int p = cerr.precision(HIGH_PRECISION);
01846     cerr << "evolve_system: "; PRC(n_next); PRL(ttmp);
01847     if (n_next < 4) {
01848         PRI(15);
01849         for (int ii = 0; ii < n_next; ii++)
01850             cerr << next_nodes[ii]->format_label() << " ";
01851         cerr << endl << flush;
01852     }
01853     cerr.precision(p);
01854 }
01855 #endif
01856 
01857     bool quit_now = false;
01858     hdyn *bad = NULL;
01859     for (int ii = 0; ii < n_next; ii++) {
01860         if (!next_nodes[ii]->is_valid()) {
01861             cerr << "next_node[" << ii << "] = " << next_nodes[ii]
01862                  << " is invalid" << endl << flush;
01863             bad = next_nodes[ii];
01864             quit_now = true;
01865         }
01866     }
01867     if (quit_now) {
01868         for_all_nodes(hdyn, b, bb)
01869             if (bb == bad) cerr << "invalid node contained within the tree"
01870                                 << endl;
01871         err_exit("invalid node(s) on timestep list.");
01872     }
01873 
01874 
01875         // New order of actions (Steve, 7/01):
01876         //
01877         //      1. log output
01878         //      2. flag escapers
01879         //      3. check STOP
01880         //      4. snapshot/full dump output
01881         //      5. remove escapers
01882         //      6. reinitialize
01883         //
01884         // These differ significantly from the previous version...
01885 
01886         //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
01887 
01888         bool save_snap = false;
01889 
01890         if (ttmp > t_log) {
01891 
01892             // 1. Standard log output.
01893 
01894             // System should be synchronized here, but it is not essential.
01895             // However, energy errors may not be reliable, and the system
01896             // may not be restartable (if save_snap_at_log is set).
01897 
01898             real cpu0 = cpu_time();
01899 
01900             // Encode binary log data in form suitable for sys_stats.
01901 
01902             int long_bin = 0;
01903             if (long_binary_out > 0 && dt_log > 0) {
01904                 int nlog = (int)rint((real)ttmp/dt_log);
01905                 if (nlog%long_binary_out == 0)
01906                     long_bin = 2;
01907                 else
01908                     long_bin = 1;
01909             }
01910 
01911             log_output(b, count, steps, &kc_prev, long_bin);
01912 
01913             // (Incorporate count and steps into kira_counters...?)
01914 
01915             save_snap = save_snap_at_log;
01916 
01917             cerr << endl << "Total CPU time for log output = "
01918                  << cpu_time() - cpu0 << endl;
01919 
01920             cerr << endl; flush(cerr);
01921             update_step(ttmp, t_log, dt_log);
01922         }
01923 
01924         //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
01925 
01926         if (full_dump && ttmp > t_esc_check) {
01927 
01928             // 2. Flag escapers (full_dump mode only).  System may or may not
01929             // be synchronized, but dyn functions don't know about pred_pos...
01930 
01931             refine_cluster_mass(b, 0);
01932             update_step(ttmp, t_esc_check, dt_esc_check);
01933         }
01934 
01935         //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
01936 
01937         if (ttmp > t_sync) {
01938 
01939             // 3. System is synchronized.
01940             // Check to see if we should stop the run.
01941 
01942             if (check_file("STOP")) {
01943 
01944                 t_end = ttmp - 1;       // Forces optional snap output 
01945                                         // and end of run in snap_output.
01946 
01947                 cerr << endl << "***** Calculation STOPped by user at time "
01948                      << t << " *****" << endl << endl;
01949             }
01950 
01951             tree_changed |= check_sync(b);
01952             update_step(ttmp, t_sync, dt_sync);
01953         }
01954 
01955         //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
01956 
01957         // 4. Output a snapshot to cout at the scheduled time, or at end of
01958         // run. NOTE: This is the *only* place where output to cout can occur.
01959 
01960         // Not essential to have dt_snap >= dt_reinit, but should have this
01961         // if we want full restart capability.
01962 
01963         bool reg_snap = (ttmp > t_snap
01964                          || (dt_snap < VERY_LARGE_NUMBER && ttmp > t_end)
01965                          || (fmod(steps, 1000) == 0 && check_file("DUMP")));
01966 
01967         if (reg_snap || save_snap) {
01968 
01969             // PRC(ttmp), PRC(t_snap), PRL(dt_snap);
01970 
01971             snap_output(b, steps, snaps,
01972                         reg_snap, save_snap, snap_save_file,
01973                         t, ttmp, t_end, t_snap, dt_snap, verbose);
01974 
01975             if (reg_snap)
01976                 update_step(ttmp, t_snap, dt_snap);
01977         }
01978 
01979         //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
01980 
01981         // 5. Full dumps should precede and follow major changes when the
01982         // system is properly synchronized.
01983 
01984         // bool full_dump_now = (full_dump
01985         //                    && (t == 0 || t >= t_reinit
01986         //                               || t>= t_esc || t >= t_sync));
01987 
01988         // No full output at every t_sync.
01989         // Stellar evolution forces t_sync to be 1/64 or less!
01990 
01991         // bool full_dump_now = (full_dump
01992         //                    && (t >= t_reinit || t >= t_esc || t >= t_end));
01993         //
01994         // Note that t = t_reinit = t_esc now at restart, so the second
01995         // clause of the if () test is true initially.
01996 
01997         // Now have a separate timescale for full dump.
01998 
01999         bool full_dump_now = (full_dump
02000                               && (t >= t_fulldump || t >= t_end));
02001         if (full_dump)
02002             update_step(ttmp, t_fulldump, dt_fulldump);
02003 
02004         // This dump ends the current worldbundle, so don't do it initially.
02005         // First full dump will be written below.
02006 
02007         if (full_dump_now && !first_full_dump) {
02008 
02009             // We want the last full dump (t_end) to be a complete
02010             // snapshot, so we can restart from the data at the end
02011             // of the worldbundle file.  (Steve, 7/01)
02012 
02013             int short_output = 1;
02014             if (ttmp > t_end) short_output = 4;         // new (7/01)
02015 
02016             set_complete_system_dump(true);
02017             put_node(cout, *b,
02018                      false,             // don't print xreal
02019                      short_output);     // short output (uses STARLAB_PRECISION)
02020             set_complete_system_dump(false);
02021 
02022             cerr << "Full dump (";
02023             if (short_output == 1) cerr << "t";
02024             else cerr << "h";
02025             cerr << "dyn format) at time " << t << endl;
02026         }
02027 
02028         first_full_dump = false;
02029 
02030 #if 0
02031         real tcheck1 = 17.0;
02032         real tcheck2 = 17.5;
02033         real tcheck3 = 18.0;
02034         real tcheck4 = 19.0;
02035         if (   t <= tcheck1 && ttmp > tcheck1
02036             || t <= tcheck2 && ttmp > tcheck2
02037             || t <= tcheck3 && ttmp > tcheck3
02038             || t <= tcheck4 && ttmp > tcheck4 ) {
02039 
02040             char name[10];
02041             sprintf(name, "TMP_%.1f", (real)t);
02042             ofstream f(name);
02043             if (f) {
02044 
02045                 // put_node(f, *b);
02046                 pp3(b, f);
02047                 cerr << "wrote TMP file " << name << endl;
02048 
02049                 f.close();
02050             }
02051         }
02052 #endif
02053 
02054         //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
02055 
02056         if (ttmp > t_end) return;               // return ==> stop
02057 
02058         //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
02059 
02060         bool reinit = (ttmp > t_reinit);
02061         if (reinit) update_step(ttmp, t_reinit, dt_reinit);
02062 
02063         //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
02064 
02065         bool esc = false;
02066 
02067         if (ttmp > t_esc) {
02068 
02069             // 5. Check for and remove escapers.
02070 
02071             // System is reinitialized and time step list is
02072             // recomputed if any stars are removed.
02073 
02074             // *** REQUIRE dt_esc >= dt_sync. ***
02075 
02076             int n_prev = b->n_leaves();
02077 
02078             if (b->get_scaled_stripping_radius() > 0)
02079                 check_and_remove_escapers(b, ttmp, next_nodes,
02080                                           n_next, tree_changed);
02081 
02082             int n_new = b->n_leaves();
02083 
02084             if (n_new <= n_stop) {
02085                 cerr << "N_stop reached\n";
02086                 exit(0);
02087             }
02088 
02089             if (n_new != n_prev) {
02090                 reinit = true;
02091                 esc = true;
02092             }
02093 
02094             update_step(ttmp, t_esc, dt_esc);
02095         }
02096 
02097         //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
02098 
02099         if (reinit) {
02100 
02101             // 6. Reinitialize the system.
02102 
02103             // *** REQUIRE dt_reinit >= dt_sync. ***
02104 
02105             full_reinitialize(b, t, verbose);
02106             tree_changed = true;
02107 
02108             fast_get_nodes_to_move(b, next_nodes, n_next, ttmp, tree_changed);
02109 
02110             if (esc) cerr << endl << flush;
02111         }
02112 
02113         // NOTE:  If dt_log and dt_reinit are properly chosen, escapers will
02114         // always be checked and the system will always be reinitialized
02115         // immediately after a snapshot or full dump, so continuation should
02116         // be the same as a restart from that snapshot.
02117 
02118         //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
02119 
02120         // Second full_dump output marks the start of a new worldbundle.
02121 
02122         if (full_dump_now) {
02123 
02124             set_complete_system_dump(true);
02125             put_node(cout, *b, false, 1);
02126             set_complete_system_dump(false);
02127 
02128             cerr << endl << "Full dump (tdyn format) at time " << t << endl;
02129         }
02130 
02131         //-----------------------------------------------------------------
02132 
02133         // Proceed to the next step.
02134 
02135 #ifdef T_DEBUG
02136 if (ttmp > T_DEBUG) cerr << 2 << endl << flush;
02137 #endif
02138 
02139         if (ttmp < t)
02140             backward_step_exit(b, ttmp, t, next_nodes, n_next);
02141             
02142         // Force the elder of two binary sisters to be integrated.
02143 
02144         check_binary_scheduling(b, next_nodes, n_next);
02145 
02146         xreal t_prev = b->get_system_time();
02147 
02148         b->set_system_time(t = ttmp);
02149         b->set_time(t);
02150 
02151         // Take a new step to time t (now system_time):
02152 
02153 #ifdef T_DEBUG
02154 if (ttmp > T_DEBUG) cerr << 3 << endl << flush;
02155 #endif
02156 
02157 #ifndef USE_GRAPE
02158         
02159         // We need full prediction if any top-level nodes appear on
02160         // the integration list.  Otherwise, we really only need to 
02161         // predict the perturbers (done in perturber_acc_and_jerk...).
02162         // However, if a perturber list is invalid or overflows, then
02163         // we need full prediction again...
02164 
02165         bool predict_all = false;
02166         for (int i = 0; i < n_next; i++) {
02167             hdyn* n = next_nodes[i];
02168             if (n->is_top_level_node()
02169                 || !n->get_top_level_node()->get_valid_perturbers()) {
02170                 predict_all = true;
02171                 break;
02172             }
02173         }
02174 
02175         if (predict_all)
02176             predict_loworder_all(b, t); 
02177 
02178         // GRAPE does (top-level) prediction, if present.
02179 
02180 #endif
02181 
02182         //-----------------------------------------------------------------
02183 
02184         // Integrate all particles in the current block step.
02185         // Steps counts particle steps; count counts block steps.
02186 
02187         if (0 && full_dump) {
02188             cerr << endl << "integration list (n_next = "
02189                  << n_next << "):" << endl;
02190             for (int i = 0; i < n_next; i++) {
02191                 PRI(4); PRC(i); cerr << next_nodes[i]->format_label() << endl;
02192             }
02193         }
02194 
02195         if (full_dump == 1) {
02196 
02197             // The next_nodes[] array is used to test for changes in
02198             // unperturbed status.  The last_dt[] array saves timesteps
02199             // at the start of the step.
02200             //
02201             // Not a particularly clean way to proceed...
02202             //
02203             //                                  (Steve, 10/00, 8/01)
02204 
02205             for (int i = 0; i < n_next; i++) {
02206 
02207                 if (next_nodes[i]->get_kepler())
02208                     next_flag[i] = true;
02209                 else
02210                     next_flag[i] = false;
02211 
02212                 last_dt[i] = next_nodes[i]->get_timestep();
02213             }
02214 
02215         }
02216 
02217 #ifdef T_DEBUG
02218 if (ttmp > T_DEBUG) {
02219 
02220      cerr << 4 << endl << flush;
02221 
02222 //      cerr << "about to make a new real array" << endl << flush;
02223 //      xxx = new real[MAX_PERTURBERS];
02224 //      xxx[0] = 42;
02225 //      PRL(xxx);
02226 //      delete [] xxx;
02227 
02228 }
02229 #endif
02230 
02231         int ds = integrate_list(b, next_nodes, n_next, exact,
02232                                 tree_changed, full_dump,
02233                                 r_reflect);
02234 
02235 //     for (int ii = 0; ii < n_next; ii++) {
02236 //      if (!next_nodes[ii] || !next_nodes[ii]->is_valid()) {
02237 //          cerr << "next_node[" << ii << "] = " << next_nodes[ii]
02238 //               << " is now invalid" << endl << flush;
02239 //      }
02240 //     }
02241 
02242 #ifdef T_DEBUG
02243 if (ttmp > T_DEBUG) cerr << 49 << endl << flush;
02244 #endif
02245 
02246         bool force_energy_check = false;
02247         if (ds < 0) {
02248             ds = -ds;
02249             if (kd->check_heartbeat) force_energy_check = true;
02250         }
02251 
02252         steps += ds;
02253         grape_steps += ds;
02254         count += 1;
02255 
02256         if (force_energy_check)
02257             count = 4*kd->n_check_heartbeat
02258                         * (floor(count / (4*kd->n_check_heartbeat)) + 1);
02259 
02260 #ifdef T_DEBUG
02261 if (ttmp > T_DEBUG) cerr << 5 << endl << flush;
02262 #endif
02263 
02264         if (full_dump == 1) {
02265 
02266             // Check for dump of worldline information.
02267 
02268             for (int i = 0; i < n_next; i++) {
02269 
02270                 hdyn *curr = next_nodes[i];
02271 
02272                 if (curr && curr->is_valid()) {
02273 
02274                     // Always dump new tree information (see hdyn_tree.C),
02275                     // but allow the possibility of fewer dumps during
02276                     // normal integration.  Ordinarily, dump every n_dump
02277                     // steps.
02278 
02279                     bool dump_now = (fmod(curr->get_steps(), n_dump) == 0);
02280 
02281                     // Force dump if node's unperturbed status has changed.
02282 
02283                     dump_now |=
02284                         (next_flag[i] && !curr->get_kepler()
02285                          || (!next_flag[i] && curr->get_kepler()));
02286 
02287 #if 0
02288                     // *** New treatment of lightly perturbed binaries.
02289                     // *** What about slow binaries?  Later...
02290 
02291                     if (curr->is_low_level_node()
02292                         && !curr->get_kepler()
02293                         && curr->get_perturbation_squared()
02294                                 < SMALL_TDYN_PERT_SQ) {
02295 
02296                         // Which criterion to use?
02297 
02298                         int which = 2;
02299 
02300                         if (which == 1) {
02301 
02302                             // Attempt #1: Only dump if we have just crossed
02303                             //             the parent step:
02304 
02305                             real t_par = curr->get_parent()->get_time();
02306                             dump_now = (t >= t_par && t - last_dt[i] < t_par);
02307 
02308                             // However, the parent step for a significantly
02309                             // perturbed binary may not be significantly greater
02310                             // than the internal step, so the gain may not be
02311                             // very great.  The parent timestep is sensitive
02312                             // to "wiggles" due to perturbers, and increases
02313                             // significantly as the perturbation increases.
02314 
02315                         } else if (which == 2) {
02316 
02317                             // Attempt #2: Simply increase the dump timescale
02318                             //             to come closer to a few bound orbits.
02319                             //             Possibly could be corrected to take
02320                             //             into account whether or not the
02321                             //             orbit is bound; however, if we simply
02322                             //             interpolate from the start to the end
02323                             //             of an unbound segment, should be OK.
02324 
02325                             dump_now = (fmod(curr->get_steps(),
02326                                              10*n_dump) == 0);
02327                         }
02328 
02329                         if (dump_now && !curr->get_elder_sister()) {
02330                             cerr << endl
02331                                  << curr->get_parent()->format_label()
02332                                  << " is lightly perturbed; get_steps = "
02333                                  << curr->get_steps() << endl;
02334                             PRL(sqrt(max(0.0,
02335                                          curr->get_perturbation_squared())));
02336                             real ratio = curr->get_parent()->get_timestep()
02337                                            / curr->get_timestep();
02338                             PRL(curr->get_parent()->get_timestep());
02339                             PRC(curr->get_timestep());
02340                             PRL(ratio);
02341                         }
02342                     }
02343 #endif
02344 
02345                     if (dump_now) {
02346 
02347                         // cerr << "kira: time " << b->get_system_time();
02348                         // cerr << "  put_node " << i << "/" << n_next << "  "
02349                         //      << curr->format_label() << endl;
02350 
02351                         put_single_node(cout, *curr, false, 1);
02352 
02353                         // Note that we have to use binary_sister here, not
02354                         // younger_sister, because this node may become the
02355                         // younger sister in a new binary.
02356 
02357                         if (curr->is_low_level_node()) {
02358 
02359                             // cerr << "      put_node for sister "
02360                             //      << curr->get_binary_sister()
02361                             //                      ->format_label()
02362                             //      << endl;
02363 
02364                             put_single_node(cout,
02365                                             *(curr->get_binary_sister()),
02366                                             false, 1);
02367                         }
02368                     }
02369                 }
02370             }
02371         }
02372 
02373 #ifdef DUMP_DATA
02374         if (tmp_dump && t >= 17.0 && t <= 17.5) {
02375 
02376             // Dump everything to file tmp_dump.
02377 
02378             tmp_dump << endl << "n_next = " << n_next << endl;
02379             for (int i = 0; i < n_next; i++)
02380                 if (next_nodes[i] && next_nodes[i]->is_valid()) {
02381                     tmp_dump << "i = " << i << " (" << next_nodes[i] << "):"
02382                              << endl;
02383                     pp3(next_nodes[i], tmp_dump, -1);
02384                 } else
02385                     tmp_dump << "i = " << i << " (" << next_nodes[i]
02386                              << "):  invalid" << endl;
02387         }
02388 #endif
02389 
02390 
02391 //      for (int i = 0; i < n_next; i++)
02392 //        if (next_nodes[i] && next_nodes[i]->is_valid()
02393 //            && next_nodes[i]->name_is("(1752,101752)")) {
02394 //          plot_stars(next_nodes[i]->get_top_level_node());
02395 //          pp3(next_nodes[i], cerr, -1);
02396 //        }
02397 
02398 
02399         //-------------------------------------------------------------------
02400         // (Removed numerous debugging examples to kira_debug.C -- Steve 8/98)
02401         //-------------------------------------------------------------------
02402 
02403 
02404         // check_slow_consistency(b);
02405 
02406         // Optionally check the heartbeat...
02407 
02408         if (kd->check_heartbeat && fmod(count, kd->n_check_heartbeat) == 0) {
02409             PRC(count), PRC(t), PRC(t-t_prev), PRL(cpu_time());
02410             if (fmod(count, 4*kd->n_check_heartbeat) == 0)
02411                 print_recalculated_energies(b);
02412         }
02413 
02414 
02415         // Integrate_list handles tree changes -- allows one per step.
02416 
02417         // Note: if a node is destroyed as part of the step,
02418         // the corresponding entry in next_nodes returns NULL.
02419         // (Old convention -- could now simply check node->is_valid().)
02420 
02421         // Finally, evolve the stellar system (stars and binaries).
02422         // Entire system will be reinitialized if necessary.
02423 
02424         // Note: "if" statement moved from evolve stars() (see note there).
02425         // Both stars and binaries are currently updated at fixed time
02426         // intervals (previously updated binaries after every binary step
02427         // -- pros and cons exist for either choice; details are still
02428         // under investigation).
02429 
02430 #ifdef T_DEBUG
02431 if (ttmp > T_DEBUG) cerr << 6 << endl << flush;
02432 #endif
02433 
02434         if (fmod(b->get_system_time(), dt_sstar) == 0.0
02435             && b->get_use_sstar())  {
02436 
02437            // cerr << "pre SE at t = " << b->get_system_time() << endl;
02438            // print_recalculated_energies(b);
02439 
02440             bool tmp = evolve_stars(b, full_dump);
02441 //          if (tmp)
02442 //              cerr << "tree change caused by evolve_stars at time "
02443 //                   << b->get_system_time() << endl << flush;
02444             tree_changed |= tmp;
02445 
02446             // cerr << "post SE at t = " << b->get_system_time() << endl;
02447             // print_recalculated_energies(b);
02448 
02449             // print_energy_from_pot(b);        // should be free, but
02450                                                 // doesn't quite work...
02451         }
02452 
02453         if (tree_changed) set_n_top_level(b);
02454 
02455 #ifdef USE_GRAPE
02456 
02457         // Check for GRAPE release.
02458 
02459         if (grape_steps > ko->grape_check_count) {
02460             grape_steps = 0;
02461             check_release_grape(ko, t);
02462         }
02463 
02464 #endif
02465 
02466 #ifdef T_DEBUG
02467 if (ttmp > T_DEBUG) cerr << 7 << endl << flush;
02468 #endif
02469 
02470         // Miscellaneous checks (see kira_runtime.C):
02471 
02472         if (fmod(count, kd->n_check_runtime) == 0) {
02473 
02474             if (cpu_time() > cpu_time_limit) {
02475                 cerr << endl
02476                      << "***** CPU time limit of " << cpu_time_limit
02477                      << " seconds exceeded"
02478                      << endl;
02479                 return;                         // pretty harsh...
02480             }
02481 
02482             real new_dt_log = 0;
02483             real new_dt_snap = 0;
02484             char* new_snap_save_file = new char[128];
02485             new_snap_save_file[0] = '\0';
02486 
02487             bool status
02488                 = check_kira_runtime(b, t_end,
02489                                      new_dt_log, new_dt_snap,
02490                                      long_binary_out, new_snap_save_file,
02491                                      tree_changed);
02492 
02493             if (new_dt_log > 0) {
02494                 dt_log = new_dt_log;
02495                 int i = (int)((real)b->get_system_time() / dt_log);
02496                 t_log = (i+1) * dt_log;
02497             }
02498 
02499             if (new_dt_snap > 0) {
02500                 dt_snap = new_dt_snap;
02501                 int i = (int)((real)b->get_system_time() / dt_snap);
02502                 t_snap = (i+1) * dt_snap;
02503             }
02504 
02505             if (new_snap_save_file[0] != '\0') {
02506                 save_snap_at_log = true;
02507                 snap_save_file = new_snap_save_file;
02508             } else
02509                 delete [] new_snap_save_file;
02510 
02511             if (status) return;
02512 
02513             ko = b->get_kira_options();         // (just in case...)
02514             kd = b->get_kira_diag();
02515         }
02516     }
02517 }
02518 
02519 
02520 
02521 #include <unistd.h>                             // for termination below...
02522 #include <signal.h>
02523 
02524 main(int argc, char **argv)
02525 {
02526     check_help();
02527 
02528     // Parameters to be passed directly to kira:
02529 
02530     hdyn *b;                    // hdyn root node
02531 
02532     // Time scales -- all should be powers of 2.
02533 
02534     real delta_t;               // time span of the integration
02535     real dt_log;                // output interval
02536     real dt_snap;               // snap output interval
02537     real dt_sstar;              // standard single-star evolution timestep
02538     real dt_esc;                // timestep to remove escapers
02539     real dt_reinit;             // timestep to reinitialize entire system
02540     real dt_fulldump;           // timestep for full system dumps
02541 
02542     int long_binary_out;
02543 
02544     real cpu_time_limit;
02545 
02546     bool exact;                 // force calculation using perturber list
02547     bool verbose;               // Toggle "verbose" mode
02548 
02549     bool save_snap_at_log = false;
02550     char snap_save_file[256];
02551     int  n_stop;                // n to terminate simulation
02552 
02553     if (!kira_initialize(argc, argv,
02554                          b, delta_t, dt_log, long_binary_out,
02555                          dt_snap, dt_sstar,
02556                          dt_esc, dt_reinit, dt_fulldump,
02557                          exact, cpu_time_limit, verbose,
02558                          save_snap_at_log, snap_save_file, n_stop))
02559         get_help();
02560 
02561     // b->to_com();     // don't modify input data -- use tool to do this
02562 
02563     // Control behavior of the kepler package.
02564 
02565     set_kepler_tolerance(2);
02566     set_kepler_print_trig_warning(b->get_kira_diag()
02567                                    ->report_kepler_trig_error);
02568 
02569     evolve_system(b, delta_t, dt_log, long_binary_out,
02570                   dt_snap, dt_sstar, dt_esc, dt_reinit, dt_fulldump,
02571                   exact, cpu_time_limit,
02572                   verbose, save_snap_at_log, snap_save_file, n_stop);
02573 
02574     cerr << endl << "End of run at time " << b->get_system_time()
02575          << endl
02576          << "Total CPU time for this segment = " << cpu_time()
02577          << endl;
02578 
02579     //--------------------------------------------------------------------
02580     // For unknown reasons, neomuscat sometimes dumps core at end of run...
02581     //--------------------------------------------------------------------
02582 
02583     // exit(0);                 // may still cause a core dump...
02584 
02585     // kill(getpid(), 9);       // dumb, but brute force works!
02586 
02587     //--------------------------------------------------------------------
02588 
02589     // Clean up static data (to make it easier for ccmalloc to find
02590     // real memory leaks).
02591 
02592     cerr << endl << "cleaning up hdyn_schedule" << endl << flush;
02593     clean_up_hdyn_schedule();
02594 
02595     cerr << "cleaning up hdyn_ev" << endl << flush;
02596     clean_up_hdyn_ev();
02597 
02598     cerr << "cleaning up kira_ev" << endl << flush;
02599     clean_up_kira_ev();
02600 
02601 #if defined(USE_GRAPE)
02602     cerr << "cleaning up hdyn_grape" << endl << flush;
02603     clean_up_hdyn_grape();
02604 #endif
02605 
02606     cerr << "cleaning up next_nodes" << endl << flush;
02607     if (next_nodes) delete [] next_nodes;
02608 
02609     cerr << "cleaning up kira_counters" << endl << flush;
02610     if (b->get_kira_counters()) delete b->get_kira_counters();
02611 
02612     cerr << "cleaning up perturbed_list" << endl << flush;
02613     if (b->get_perturbed_list()) delete [] b->get_perturbed_list();
02614 
02615     cerr << "cleanup complete" << endl << flush;
02616 
02617     // rmtree(b);
02618     // rmtree(b, false);        // experiment: don't delete root node
02619 
02620     //--------------------------------------------------------------------
02621     // For unknown reasons, merlot & halley dump core at end of run if
02622     // rmtree is used.
02623     //--------------------------------------------------------------------
02624 
02625 }
02626 
02627 #endif

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