Main Page   Class Hierarchy   Data Structures   File List   Data Fields   Globals  

make_tree.C

Go to the documentation of this file.
00001 
00012 
00013 #include "sdyn.h"
00014 
00015 // pp: Recursively pretty-print a node:
00016 
00017 local void pp(sdyn* b, ostream & s, int level = 0) {
00018 
00019     s.precision(4);
00020 
00021     for (int i = 0; i < 2*level; i++) s << " ";
00022 
00023     b->pretty_print_node(s);
00024     s << " \t"<< b->get_mass() << " \t"
00025       << b->get_pos() << "   "
00026       << b->get_vel() <<endl;
00027 
00028     for_all_daughters(sdyn, b, daughter) pp(daughter, s, level + 1);    
00029 }
00030 
00031 #ifndef TOOLBOX
00032 
00033 static char id_string[50];
00034 
00035 // id: Return a node's name or number as a character string.
00036 
00037 char* id(sdyn* bb)
00038 {
00039     if (bb->get_name() != NULL)
00040         return bb->get_name();
00041     else {
00042         sprintf(id_string, "%d", bb->get_index());
00043         return id_string;
00044     }
00045     return NULL;
00046 }
00047 
00048 
00049 // count_daughters: Return the number of daughters of the specified node.
00050 
00051 local int count_daughters(sdyn* b)
00052 {
00053     int n = 0;
00054     for_all_daughters(sdyn, b, bb) n++;
00055 
00056     return n;
00057 }
00058 
00059 
00060 // find_neighbors: Determine near-neighbors and next-nearest neighbors of
00061 //                 all particles.
00062 
00063 local void find_neighbors(sdyn* b)
00064 {
00065     for_all_daughters(sdyn, b, bb) {
00066         bb->set_nn_dr2(VERY_LARGE_NUMBER);
00067         bb->set_nn_ptr(NULL);
00068         bb->set_nnn_dr2(VERY_LARGE_NUMBER);
00069         bb->set_nnn_ptr(NULL);
00070     }
00071 
00072     for_all_daughters(sdyn, b, bi)
00073         for (sdyn* bj = bi->get_younger_sister(); 
00074              bj != NULL; bj = bj->get_younger_sister()) {
00075 
00076             real rij2 = square(bi->get_pos() - bj->get_pos());
00077 
00078             if (rij2 < bi->get_nn_dr2()) {
00079                 bi->set_nn_dr2(rij2);
00080                 bi->set_nn_ptr(bj);
00081             } else if (rij2 < bi->get_nnn_dr2()) {
00082                 bi->set_nnn_dr2(rij2);
00083                 bi->set_nnn_ptr(bj);
00084             }
00085 
00086             if (rij2 < bj->get_nn_dr2()) {
00087                 bj->set_nn_dr2(rij2);
00088                 bj->set_nn_ptr(bi);
00089             } else if (rij2 < bj->get_nnn_dr2()) {
00090                 bj->set_nnn_dr2(rij2);
00091                 bj->set_nnn_ptr(bi);
00092             }
00093         }
00094 }
00095 
00096 
00097 // detach_from_tree: Cut all links between the specified node and the tree,
00098 //                   correct the tree structure accordingly.
00099 
00100 local void detach_from_tree(sdyn* bi)
00101 {
00102     sdyn* parent = bi->get_parent();
00103     sdyn* elder = bi->get_elder_sister();
00104     sdyn* younger = bi->get_younger_sister();
00105 
00106     if (younger != NULL) younger->set_elder_sister(elder);
00107 
00108     if (elder == NULL)
00109         parent->set_oldest_daughter(younger);
00110     else
00111         elder->set_younger_sister(younger);
00112 }
00113 
00114 
00115 // add_node: Insert a new node as the eldest daughter of the root node.
00116 
00117 local void add_node(sdyn* root, sdyn* new_node)
00118 {
00119     new_node->set_parent(root);
00120     new_node->set_elder_sister(NULL);
00121 
00122     sdyn* od = root->get_oldest_daughter();
00123     new_node->set_younger_sister(od);
00124 
00125     if (od) od->set_elder_sister(new_node);
00126     root->set_oldest_daughter(new_node);
00127 }
00128 
00129 
00130 // m_sum: Calculate the total mass of the nodes on the list.
00131 
00132 local real m_sum(sdyn* list[], int k_tuple)
00133 {
00134     real sum = 0;
00135     for (int i = 0; i < k_tuple; i++) sum += list[i]->get_mass();
00136 
00137     return sum;
00138 }
00139 
00140 
00141 // pos_sum: Calculate the weighted m * pos sum for the nodes on the list.
00142 
00143 local vector pos_sum(sdyn* list[], int k_tuple)
00144 {
00145     vector sum = vector(0,0,0);
00146 
00147     for (int i = 0; i < k_tuple; i++)
00148         sum += list[i]->get_mass() * list[i]->get_pos();
00149 
00150     return sum;
00151 }
00152 
00153 
00154 // vel_sum: Calculate the weighted m * vel sum for the nodes on the list.
00155 
00156 local vector vel_sum(sdyn* list[], int k_tuple)
00157 {
00158     vector sum = vector(0,0,0);
00159 
00160     for (int i = 0; i < k_tuple; i++)
00161         sum += list[i]->get_mass() * list[i]->get_vel();
00162 
00163     return sum;
00164 }
00165 
00166 
00167 // tuple_size: Determine the instantaneous radius of the specified clump,
00168 //             relative to its center of mass.
00169 
00170 local real tuple_size(sdyn* list[], int k_tuple)
00171 {
00172     real max_dist = 0;
00173     vector cmpos = pos_sum(list, k_tuple) / m_sum(list, k_tuple);
00174 
00175     for (int i = 0; i < k_tuple; i++)
00176         max_dist = max(max_dist, abs(list[i]->get_pos() - cmpos));
00177 
00178     return max_dist;
00179 }
00180 
00181 
00182 // tuple_virial_radius: Return the virial radius of the specified clump.
00183 
00184 local real tuple_virial_radius(sdyn* list[], int k_tuple)
00185 {
00186     real total_mass = m_sum(list, k_tuple);
00187     real potential = 0;
00188 
00189     for (int i = 0; i < k_tuple; i++)
00190         for (int j = i+1; j < k_tuple; j++)
00191             potential -= list[i]->get_mass() * list[j]->get_mass()
00192                           / abs(list[i]->get_pos() - list[j]->get_pos());
00193 
00194     return -0.5 * total_mass * total_mass / potential;
00195 }
00196 
00197 
00198 // distance_sq: Return the square of the minimum distance between any
00199 //              element of the first list and any element of the second.
00200 
00201 local real distance_sq(sdyn* list[], int k_tuple, sdyn* rest[], int n_rest)
00202 {
00203     real min_dist_sq = VERY_LARGE_NUMBER;
00204 
00205     for (int i = 0; i < k_tuple; i++)
00206         for (int j = 0; j < n_rest; j++)
00207             min_dist_sq = min(min_dist_sq,
00208                               square(list[i]->get_pos() - rest[j]->get_pos()));
00209 
00210     return min_dist_sq;
00211 }
00212 
00213 
00214 // is_bound: Return TRUE iff the specified clump is bound,
00215 
00216 local bool is_bound(sdyn* list[], int k_tuple)
00217 {
00218     vector cmvel = vel_sum(list, k_tuple) / m_sum(list, k_tuple);
00219 
00220     real kinetic = 0;
00221     for (int i = 0; i < k_tuple; i++)
00222         kinetic += list[i]->get_mass() * square(list[i]->get_vel());
00223     kinetic /= 2;
00224 
00225     real potential = 0;
00226     for (int i = 0; i < k_tuple; i++)
00227         for (int j = i+1; j < k_tuple; j++)
00228             potential -= list[i]->get_mass() * list[j]->get_mass()
00229                           / abs(list[i]->get_pos() - list[j]->get_pos());
00230 
00231     if (kinetic + potential >= 0) return FALSE;
00232     return TRUE;
00233 }
00234 
00235 
00236 // make_tuple_cm: Combine the specified nodes, placing their center of mass
00237 //                at the start of the daughter list.
00238 
00239 local sdyn* make_tuple_cm(sdyn* list[], int k_tuple, real radius,
00240                           bool meta = FALSE)
00241 {
00242     if (k_tuple < 2) return NULL;
00243 
00244     sdyn* root = list[0]->get_parent();
00245 
00246     // Remove the list elements (and any daughters) from the tree.
00247 
00248     for (int i = 0; i < k_tuple; i++)
00249         detach_from_tree(list[i]);
00250 
00251     // Place the new CM at the start of the list (as the oldest daughter of
00252     // root) to prevent it from being picked up in the loop through the system.
00253 
00254     sdyn* cm = new sdyn;
00255     add_node(root, cm);
00256 
00257     // Reattach list elements;
00258 
00259     cm->set_oldest_daughter(list[0]);
00260     list[0]->set_elder_sister(NULL);
00261     for (int i = 0; i < k_tuple; i++) {
00262         list[i]->set_parent(cm);
00263         if (i > 0) list[i]->set_elder_sister(list[i-1]);
00264         if (i < k_tuple-1) list[i]->set_younger_sister(list[i+1]);
00265     }
00266     list[k_tuple-1]->set_younger_sister(NULL);
00267 
00268     // Determine CM mass, position, and velocity.
00269 
00270     real m_total = m_sum(list, k_tuple);
00271     vector cmpos = pos_sum(list, k_tuple) / m_total;
00272     vector cmvel = vel_sum(list, k_tuple)/ m_total;
00273 
00274     cm->set_mass(m_total);
00275     cm->set_pos(cmpos);
00276     cm->set_vel(cmvel);
00277     cm->set_time(root->get_time());
00278 
00279     cm->set_radius(radius);
00280 
00281     // Set the CM neighbor pointers to NULL for convenience in the
00282     // "find_and_make" loop.
00283 
00284     cm->set_nn_ptr(NULL);
00285     cm->set_nnn_ptr(NULL);
00286 
00287     // Offset the new components relative to the center of mass:
00288 
00289     for (int i = 0; i < k_tuple; i++) {
00290         list[i]->inc_pos(-cmpos);
00291         list[i]->inc_vel(-cmvel);
00292     }
00293 
00294     // New CM ID:
00295 
00296     bool index = TRUE;
00297     for (int i = 0; i < k_tuple; i++)
00298         if (list[i]->get_index() <= 0) index = FALSE;
00299 
00300     if (index) {
00301         int sum = 100 * list[0]->get_index();
00302         for (int i = 1; i < k_tuple; i++) sum += list[i]->get_index();
00303         cm->set_index(sum);                                    // (For now...)
00304     }
00305 
00306     bool name = TRUE;
00307     for (int i = 0; i < k_tuple; i++)
00308         if (list[i]->get_name() == NULL) name = FALSE;
00309 
00310     if (name) {
00311         char temp[100];
00312         temp[0] = '\0';
00313         strcat(temp, (meta ? "{" : "("));
00314         for (int i = 0; i < k_tuple; i++) {
00315             strcat(temp, list[i]->get_name());
00316             if (i < k_tuple-1) strcat(temp, ",");
00317         }
00318         strcat(temp, (meta ? "}" : ")"));
00319         cm->set_name(temp);
00320     }
00321 
00322     return cm;
00323 }
00324 
00325 
00326 // identify_node: Print node address and ID.
00327 
00328 local void identify_node(char* string, sdyn* bb)
00329 {
00330     cerr << string << " = " << bb;
00331     if (bb != NULL) cerr << " = " << id(bb);
00332     cerr << endl;
00333 }
00334 
00335 
00336 // Specify the following as parameters?
00337 
00338 #define MIN_PERI_FACTOR 2       // Unconditionally unstable within this peri
00339 #define MAX_PERI_FACTOR 6       // Unconditionally stable outside this peri
00340 #define ISOL_FACTOR 4           // For multiples only
00341 #define ISOL_FACTOR_SQ          (ISOL_FACTOR * ISOL_FACTOR)
00342 
00343 #define QUARANTINE_TIME_LIMIT   100     // Unit = outer orbit period
00344 #define QSMA_TOL                0.01    // Acceptable variation in outer sma
00345 #define QECC_TOL                0.1     // Acceptable variation in outer ecc
00346 
00347 
00348 // set_tqflag: Recursively set the temporary quarantine flag of a node and
00349 //             its descendents.
00350 
00351 local void set_tqflag(sdyn* b, int flag) {
00352 
00353     b->set_temp_quarantine_flag(flag);
00354     for_all_daughters(sdyn, b, daughter) set_tqflag(daughter, flag);    
00355 }
00356 
00357 
00358 // check_tqflag: Recursively clear all quarantine flags that aren't current.
00359 
00360 local void check_tqflag(sdyn* b) {
00361 
00362     if (b->get_temp_quarantine_flag() == 0) b->set_quarantine_flag(0);
00363     for_all_daughters(sdyn, b, daughter) check_tqflag(daughter);
00364 }
00365 
00366 
00367 // set_quar: Recursively set the quarantine flag, time, and other parameters
00368 //           of the leaves lying under a node.
00369 
00370 local void set_quar(sdyn* b, int flag, real time, real sma, real ecc) {
00371 
00372     if (b->get_oldest_daughter() == NULL) {
00373         b->set_quarantine_flag(flag);
00374         b->set_quarantine_time(time);
00375         b->set_quarantine_sma(sma);
00376         b->set_quarantine_ecc(ecc);
00377     }else
00378         for_all_daughters(sdyn, b, daughter)
00379             set_quar(daughter, flag, time, sma, ecc);
00380 }
00381 
00382 
00383 // check_quar: Recursively check all quarantine flags, returning FALSE
00384 //             if any flag is not equal to the specified flag, or if any
00385 //             time, semi-major axis, or eccentricity is not equal to the
00386 //             specified value.  (This is a multiply redundant check,
00387 //             since all leaves in a quarantined system should contain the
00388 //             same information.)
00389 
00390 local bool check_quar(sdyn* b, int flag, real time, real sma, real ecc) {
00391 
00392     // Only check leaves.  CM nodes are created at each invocation of
00393     // make_tree, so they do not contain any useful information.
00394 
00395     if (b->get_oldest_daughter() == NULL) {
00396         if (b->get_quarantine_flag() < 0
00397             || b->get_quarantine_flag() != flag
00398             || b->get_quarantine_time() != time
00399             || b->get_quarantine_sma() != sma
00400             || b->get_quarantine_ecc() != ecc) return FALSE;
00401     } else
00402         for_all_daughters(sdyn, b, daughter)
00403             if (!check_quar(daughter, flag, time, sma,ecc)) return FALSE;
00404 
00405     return TRUE;
00406 }
00407 
00408 
00409 // check_quarantine: check quarantine status of the potentially stable
00410 //                   multiple consisting of node b and neighbor n.  If not
00411 //                   already in quarantine, begin new quarantine.  If already
00412 //                   in quarantine, return TRUE if time limit is exceeded.
00413 //                   Extend and/or return FALSE in all other cases. In all
00414 //                   cases, set the temp_quarantine_flag of all particles to 1.
00415 
00416 local bool check_quarantine(sdyn* b, sdyn* n, real sma, real ecc, int debug)
00417 {
00418     set_tqflag(b, 1);
00419     set_tqflag(n, 1);
00420 
00421     // Check that all particles under b and n have same flag and time.
00422     // If they do, check current time, return TRUE iff quarantine limit is up.
00423     // If they don't, start new quarantine.  A FALSE return means that the
00424     // system is not (yet) stable.
00425 
00426     // Note that b and/or n may be compound. In order to preserve quarantine
00427     // information between invocations of make_tree, copies of all data are 
00428     // stored in all nodes involved in the subsystem.
00429 
00430     sdyn* first = first_leaf(b);
00431 
00432     int  qflag = first->get_quarantine_flag();
00433     real qtime = first->get_quarantine_time();
00434     real qsma = first->get_quarantine_sma();
00435     real qecc = first->get_quarantine_ecc();
00436 
00437     if (check_quar(b, qflag, qtime, qsma, qecc)
00438         && check_quar(n, qflag, qtime, qsma, qecc)) {
00439 
00440         // System is already in quarantine.
00441 
00442         if (abs(sma - qsma) < QSMA_TOL * qsma
00443              && abs(ecc - qecc) < QECC_TOL * qecc) {
00444 
00445             // Outer orbit parameters are acceptable.  Check the time since
00446             // the system was placed in quarantine.
00447 
00448             if (b->get_time() - qtime > QUARANTINE_TIME_LIMIT *
00449                 TWO_PI * sqrt( (b->get_mass() + n->get_mass()) / pow(sma, 3)))
00450                 return TRUE;
00451             else
00452                 return FALSE;
00453         }
00454     }
00455 
00456     // Start a new quarantine if this is a new system, or if the
00457     // parameters of an old system have drifted too much.
00458 
00459     qflag = (int)b / 4 + (int)n / 4;
00460     qtime = b->get_time();
00461 
00462     set_quar(b, qflag, qtime, sma, ecc);
00463     set_quar(n, qflag, qtime, sma, ecc);
00464 
00465     if (debug) cerr << ": new quarantine";
00466     return FALSE;
00467 }
00468 
00469 
00470 // find_and_make_binaries: Search for isolated, mutual near-neighbors.  Use the
00471 //                         additional constraint that the pair be bound if the
00472 //                         dynamics flag is set.  Also insist that the two
00473 //                         components be isolated *at periastron* if the
00474 //                         stability flag is set.
00475 //
00476 //                         Keep searching and creating binary nodes until the
00477 //                         system has been entirely checked, or until some
00478 //                         neighbor pointer has been corrupted (in which case
00479 //                         we reset the pointers externally and repeat).
00480 
00481 local int find_and_make_binaries(sdyn* b, bool dynamics, bool stability, 
00482                                  int debug)
00483 {
00484     int n_bin = 0;
00485 
00486     sdyn* bb = b->get_oldest_daughter();
00487     sdyn* last_bb = NULL;
00488 
00489     while (bb) {
00490         sdyn* nn = bb->get_nn_ptr();
00491 
00492         if (debug > 1) {
00493             identify_node("bb", bb);
00494             identify_node("nn", nn);
00495         }
00496 
00497         if (nn != NULL && nn->get_nn_ptr() == bb) {             // mutual
00498 
00499             real radius = abs(bb->get_pos() - nn->get_pos());
00500             bool is_binary = TRUE;
00501             bool meta = FALSE;
00502 
00503             if (debug) cerr << "mutual pair " << id(bb)
00504                             << " " << id(nn) << flush;
00505 
00506             if (dynamics) {
00507 
00508                 real m_total = bb->get_mass() + nn->get_mass();
00509                 real eij = 0.5 * square(bb->get_vel() - nn->get_vel())
00510                            - m_total / radius;
00511 
00512                 if (eij < 0) {                                  // bound
00513 
00514                     real sma = -0.5 * m_total / eij;            // (> 0, note)
00515                     if (debug) cerr << ": bound, a = " << sma << flush;
00516 
00517                     if (stability) {
00518 
00519                         // Determine periastron and check stability.
00520 
00521                         vector rel_pos = bb->get_pos() - nn->get_pos();
00522                         vector rel_vel = bb->get_vel() - nn->get_vel();
00523 
00524                         real rdotv = rel_pos * rel_vel;
00525                         real temp = 1 - radius / sma;
00526 
00527                         real ecc = sqrt(max(0.0, rdotv * rdotv
00528                                                     / (m_total * sma)
00529                                                   + temp * temp));
00530                         real periastron = sma * (1 - ecc);
00531                         real size = max(bb->get_radius(), nn->get_radius());
00532         
00533                         // Stability is based on periastron distance.
00534                         // Implement quarantine here too.
00535 
00536                         if (periastron < MIN_PERI_FACTOR * size) {
00537 
00538                             // Unconditionally unstable
00539 
00540                             is_binary = FALSE;
00541                             nn->set_nn_ptr(NULL);   // Avoid repeated effort
00542 
00543                             if (debug) cerr << ": unstable, e = " << ecc
00544                                             << flush;
00545 
00546                         } else if (periastron < MAX_PERI_FACTOR * size) {
00547 
00548                             // Set or check quarantine before deciding
00549                             // stability in this case.
00550 
00551                             if ( (is_binary = check_quarantine(bb, nn,
00552                                                                sma, ecc,
00553                                                                debug))
00554                                    == FALSE) {
00555                                 nn->set_nn_ptr(NULL);
00556                                 if (debug) cerr << ": quarantined, e = " << ecc
00557                                                 << flush;
00558                             } else {
00559                                 if (debug) cerr << ": metastable, e = " << ecc
00560                                                 << flush;
00561                                 meta = TRUE;
00562                             }
00563                         } else
00564 
00565                             // Unconditionally stable
00566 
00567                             if (debug) cerr << ": stable, e = " << ecc
00568                                             << flush;
00569                     }
00570 
00571                     radius = sma;       // binary radius = semi-major axis
00572 
00573                 } else {
00574 
00575                     is_binary = FALSE;
00576                     nn->set_nn_ptr(NULL);           // Avoid repeated effort
00577                     if (debug) cerr << ": not bound, separation = " << radius
00578                                     << flush;
00579                 }
00580             }
00581 
00582             if (is_binary) {
00583 
00584                 radius += bb->get_radius() + nn->get_radius();
00585                 real r_crit_sq = ISOL_FACTOR_SQ * radius * radius;
00586 
00587                 if (bb->get_nnn_dr2() > r_crit_sq
00588                     && nn->get_nnn_dr2() > r_crit_sq) {         // isolated
00589 
00590                     sdyn* list[2];
00591                     list[0] = bb;
00592                     list[1] = nn;
00593                     make_tuple_cm(list, 2, radius, meta);
00594 
00595                     n_bin++;
00596                     bb = last_bb;
00597 
00598                     // Don't consider neighbors of bb or nn this time around
00599 
00600                     for_all_daughters(sdyn, b, bbb)
00601                         if (bbb->get_nn_ptr() == bb
00602                             || bbb->get_nn_ptr() == nn
00603                             || bbb->get_nnn_ptr() == bb
00604                             || bbb->get_nnn_ptr() == nn)
00605                             bbb->set_nn_ptr(NULL);
00606                 } else {
00607                     nn->set_nn_ptr(NULL);
00608                     if (debug) cerr << ": not isolated" << flush;
00609                 }
00610             }
00611             if (debug) cerr << endl;
00612         }
00613 
00614         last_bb = bb;
00615 
00616         // Find the next node to condsider:
00617 
00618         if (bb != NULL)
00619 
00620             bb = bb->get_younger_sister();
00621 
00622         else {
00623 
00624             // We have just merged the first non-center-of-mass element
00625             // on the list.  Find the next node by looking for a particle
00626             // whose nn pointer is non-null (CM pointers are NULL by
00627             // construction).  Note that some non-CM particles will also
00628             // have NULL nn pointers, if they lay too close to a binary,
00629             // so also terminate if the last daughter is reached.
00630 
00631             bb = b->get_oldest_daughter();
00632             while (bb != NULL && bb->get_nn_ptr() == NULL)
00633                 bb = bb->get_younger_sister();
00634         }
00635     }
00636 
00637     return n_bin;
00638 }
00639 
00640 
00641 // find_and_make_tuple: Search for an isolated k-tuple.  Use the additional
00642 //                      constraint that a tuple be bound if the dynamics
00643 //                      flag is set.  Return when the first tuple is found.
00644 //                      Treat binaries (k_tuple = 2) as a special case.
00645 
00646 local int find_and_make_tuple(sdyn* b, int k_tuple, bool dynamics,
00647                               bool stability, int debug)
00648 {
00649     if (debug > 1) cerr << "find_and_make_tuple: k = " << k_tuple << endl;
00650 
00651     if (k_tuple < 2)
00652 
00653         return 0;
00654 
00655     else if (k_tuple == 2)
00656 
00657         return find_and_make_binaries(b, dynamics, stability, debug);
00658 
00659     else {
00660 
00661         sdyn** list = new sdyn*[k_tuple+1];
00662 
00663         for_all_daughters(sdyn, b, bi) {
00664             list[0] = bi;
00665             int nlist = 1;
00666             for (int i = 1; i <= k_tuple; i++) {
00667                 sdyn* nn = list[i-1]->get_nn_ptr();
00668                 bool dup = FALSE;
00669                 for (int j = 0; j < i; j++)             // nn already on list?
00670                     if (list[j] == nn) dup = TRUE;
00671                 if (!dup)
00672                     list[nlist++] = nn;
00673                 else
00674                     break;
00675             }
00676 
00677             if (debug > 1) cerr << "bi = " << id(bi)
00678                                 << "  nlist = " << nlist << endl;
00679 
00680             // All near-neighbors but the were put on the list.
00681 
00682             if (nlist == k_tuple) { 
00683 
00684                 // Now list(0,...,k_tuple-1) is a candidate k-tuple set,
00685                 // since the nearest neighbor of each element is also a
00686                 // member of the set.
00687 
00688                 if (debug) {
00689                     cerr << "candidate " << k_tuple << "-tuple";
00690                     for (int i = 0; i < k_tuple; i++)
00691                         cerr << " " << id(list[i]);
00692                     cerr << flush;
00693                 }
00694 
00695                 // Make a list of the other particles in the system.
00696 
00697                 int n = count_daughters(b);
00698                 sdyn** rest = new sdyn*[n-k_tuple+1];
00699                 int n_rest = 0;
00700 
00701                 for_all_daughters(sdyn, b, bj) {
00702                     bool dup = FALSE;
00703                     for (int i = 0; i < k_tuple; i++)
00704                         if (bj == list[i]) {
00705                             dup = TRUE;
00706                             break;
00707                         }
00708                     if (!dup) rest[n_rest++] = bj;
00709                 }
00710 
00711                 // Optionally check bound-ness:
00712 
00713                 bool is_binary = TRUE;
00714                 if (dynamics && !is_bound(list, k_tuple)) is_binary = FALSE;
00715 
00716                 if (is_binary) {
00717 
00718                     // Check isolation (NOTE definition of tuple radius):
00719 
00720                     real radius = max(tuple_size(list, k_tuple),
00721                                       tuple_virial_radius(list, k_tuple));
00722 
00723                     for (int i = 0; i < k_tuple; i++)
00724                         radius += list[i]->get_radius(); // [or max(radius)?]
00725 
00726                     real r_crit_sq = ISOL_FACTOR_SQ * radius * radius;
00727 
00728                     real dist_sq = distance_sq(list, k_tuple, rest, n_rest);
00729                     delete rest;
00730 
00731                     if (r_crit_sq < dist_sq) {
00732                         sdyn* cm = make_tuple_cm(list, k_tuple, radius);
00733                         if (debug) {
00734                             cerr << ", radius = " << radius << endl;
00735                             pp(cm, cerr);
00736                         }
00737                         return 1;
00738                     }
00739                     if (debug) cerr << ": not isolated\n";
00740 
00741                 } else {
00742                     delete rest;
00743                     if (debug) cerr << ": not bound\n";
00744                 }
00745             }
00746         }
00747         delete list;
00748     }
00749 
00750     return 0;
00751 }
00752 
00753 
00754 // make_tree: Recursively seek k-tuples, for k >= 2.  Continue search at
00755 //            the k = 2 level if any structure is found.
00756 
00757 void make_tree(sdyn* b, bool dynamics, bool stability, int k_max, int debug)
00758 {
00759     b->flatten_node();  // (Just in case...)
00760 
00761     // Look for tuples and create a tree.
00762 
00763     if (k_max <= 0) k_max = 1000000;
00764     set_tqflag(b, 0);
00765 
00766     int nt;
00767     do {
00768         nt = 0;
00769         for (int k_tuple = 2;
00770              k_tuple < min(k_max + 1, count_daughters(b));
00771              k_tuple++) {
00772 
00773             // If k_tuple = 2, initialize the neighbor pointers.
00774             // If k_tuple = 3, reconstruct the pointers, in case some
00775             //                 were corrupted during the binary search
00776 
00777             if (k_tuple < 4) find_neighbors(b);
00778 
00779             if ( (nt = find_and_make_tuple(b, k_tuple, dynamics,
00780                                            stability, debug)) > 0)
00781                 break;
00782         }
00783     } while (nt > 0);
00784 
00785     check_tqflag(b);
00786 }
00787 
00788 #else
00789 
00790 local void delete_node(sdyn* b)
00791 {
00792 
00793     // Recursively delete node b and its descendents.
00794 
00795     sdyn* bi = b->get_oldest_daughter();
00796     while (bi) {
00797         sdyn* tmp = bi->get_younger_sister();
00798         delete_node(bi);
00799         bi = tmp;
00800     }
00801     delete b;
00802 }
00803 
00804 #define USAGE "    Usage:  make_tree [-b] [-d] [-D [#]] [-k #] [-o] [-s]"
00805 
00806 main(int argc, char **argv)
00807 {
00808     sdyn* root;             // pointer to the N-body system
00809 
00810     int  debug = 0;
00811     bool dynamics = FALSE;
00812     int k_max = 10000000;
00813     bool output = TRUE;
00814     bool stability = FALSE;
00815 
00816     check_help();
00817 
00818     int i = 0;
00819     while (++i < argc) if (argv[i][0] == '-')
00820         switch (argv[i][1]) {
00821             case 'b': k_max = 2;
00822                       break;
00823             case 'd': dynamics = 1 - dynamics;
00824                       break;
00825             case 'D': i++;
00826                       if (i == argc || argv[i][0] == '-') {
00827                           debug = 1;
00828                           i--;
00829                       } else
00830                           debug = atoi(argv[i]);
00831                       break;
00832             case 'k': k_max = atoi(argv[++i]);
00833                       break;
00834             case 'o': output = 1 - output;
00835                       break;
00836             case 's': stability = 1 - stability;
00837                       break;
00838             default:  cerr << USAGE << endl;
00839                       get_help();
00840         }
00841 
00842     // Note that we are simply assuming that the tree is flat initially...
00843 
00844     while (root = get_sdyn(cin)) {
00845 
00846 //        sdyn* copy_root;            // pointer to a copy of the N-body system
00847 //        copy_tree(root, copy_root); // Should really save a copy
00848                                       // before proceeding...
00849 
00850         if (root->get_name() == NULL) root->set_name("root");
00851 
00852         make_tree(root, dynamics, stability, k_max, debug);
00853 
00854         if (debug) pp(root, cerr);
00855         if (output) put_sdyn(cout, *root);
00856 
00857         // Delete the newly constructed tree.
00858 
00859         delete_node(root);
00860     }
00861 }
00862 #endif

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