Main Page   Class Hierarchy   Data Structures   File List   Data Fields   Globals  

worldline.C

Go to the documentation of this file.
00001 
00002 
00003        //=======================================================//    _\|/_
00004       //  __  _____           ___                    ___       //      /|\ ~
00005      //  /      |      ^     |   \  |         ^     |   \     //          _\|/_
00006     //   \__    |     / \    |___/  |        / \    |___/    //            /|\ ~
00007    //       \   |    /___\   |  \   |       /___\   |   \   // _\|/_
00008   //     ___/   |   /     \  |   \  |____  /     \  |___/  //   /|\ ~
00009  //                                                       //            _\|/_
00010 //=======================================================//              /|\ ~
00011 
00018 //
00019 //----------------------------------------------------------------------
00020 //
00021 // Worldbundle member functions:
00022 //
00023 //      worldbundle::worldbundle(tdyn *b)
00024 //      void worldbundle::print()
00025 //      void worldbundle::dump()
00026 //      int worldbundle::find_index(real id)
00027 //      int worldbundle::find_index(char *name)
00028 //      int worldbundle::find_index(_pdyn_ *b)
00029 //      worldline *worldbundle::find_worldline(real id)
00030 //      worldline *worldbundle::find_worldline(char *name)
00031 //      worldline *worldbundle::find_worldline(_pdyn_ *b)
00032 //      void worldbundle::attach(tdyn *bn, int verbose)
00033 //      void worldbundle::print_worldline(char *name, real dt)
00034 //
00035 // Worldline member function:
00036 //
00037 //      void worldline::dump(int offset)
00038 //
00039 // Segment member function:
00040 //
00041 //      void segment::print(char *label)
00042 //
00043 // Other externally visible functions:
00044 //
00045 //      unique_id_t unique_id(char *name)
00046 //      unique_id_t unique_id(node *b)
00047 //      void print_id(void *id, char *label)
00048 //      worldbundle *read_bundle(istream &s, int verbose)
00049 //      tdyn *find_event(worldline *w, tdyn *bn, real t)
00050 //      void print_event(worldline *w, tdyn *bn, real t)
00051 //      vector interpolate_pos(tdyn *p, real t, tdyn *bn)
00052 //      vector interpolate_pos(tdyn *p, real t, vector& pos, bool inc, tdyn *bn)
00053 //      void set_interpolated_pos(tdyn *p, real t, vector& pos, tdyn *bn)
00054 //      void set_interpolated_pos(tdyn *p, real t, pdyn *curr, tdyn *bn);
00055 //      void inc_interpolated_pos(tdyn *p, real t, vector& pos, tdyn *bn)
00056 //      vector get_pos(worldline *w, tdyn *b, tdyn *bn, real t)
00057 //      pdyn *create_interpolated_tree(worldbundle *wb, real t)
00058 //
00059 //      real physical_mass_scale()
00060 //
00061 //----------------------------------------------------------------------
00062 
00063 #include "worldline.h"
00064 #include "inline.h"
00065 #include <ctype.h>
00066 
00067 #define NEW 0
00068 
00069 #ifndef TOOLBOX
00070 
00071 // Functions to define unique identification for particles.
00072 
00073 #ifndef NEW_UNIQUE_ID_T
00074 
00075     // For use in old code:
00076 
00077     //#define ID_FAC    (1.0/8192)              // power of 2...
00078     //#define ID_FAC    (1.0/131072)            // power of 2...
00079 
00080 #   define ID_FAC 0.000001                      // easier to read
00081 
00082     // To keep ids unique, need 1/FAC to exceed the maximum particle index.
00083     // Should possibly allow this to be varied at run time...
00084 
00085 #else
00086 
00087 //  For use in case NEW_UNIQUE_ID_T:
00088 
00089 #   define ID_SHIFT 20
00090 
00091 #endif
00092 
00093 // Overloaded function...
00094 
00095 unique_id_t unique_id(int index)
00096 {
00097 #ifndef NEW_UNIQUE_ID_T
00098     return (unique_id_t)(1 + ID_FAC*index);
00099 #else
00100     return (unique_id_t)((1<<ID_SHIFT) + index);
00101 #endif
00102 }
00103 
00104 unique_id_t unique_id(char *name)
00105 {
00106     // Associate a unique identifier with the specified name.
00107     // This ID will be used to track the particle throughout.
00108     // Old style: a leaf has 1 < id < 2, a binary CM has 2 < id < 3, etc.
00109     // New style: a leaf has id>>20 = 1, binary CM has id>>20 = 2, etc.
00110     //
00111     // NOTE (Steve, 12/01): actually only necessary that the id be unique
00112     // at any given instant.  Not necessary that the id is unique for all
00113     // times (successive segments of a worldline may then refer to
00114     // different nodes, but that is OK...).
00115 
00116     // First see if name can be interpreted as an integer.
00117 
00118     int index = atoi(name);
00119     if (index > 0) return unique_id(index);
00120 
00121     // This is presumably a center of mass node.  Turn its
00122     // name into an identifying number.
00123 
00124     // Parse the name.
00125 
00126     unique_id_t id = 0;
00127     int n = 0;
00128 
00129 #if 0
00130 
00131     // Old version:
00132     //
00133     // Look for commas and parentheses separating integers.
00134     // Combine ((a,b),c) --> a + ID_FAC*(b + ID_FAC*c), etc.
00135     // Factor ID_FAC is ~arbitrary (but see above).
00136     // Really need a better way of generating unique IDs...
00137 
00138     char tname[1024];
00139     strcpy(tname, name);        // work with a local copy of the name
00140     int l = strlen(tname);
00141 
00142     real fac = 1;
00143     int num = 0;
00144 
00145     for (int i = 0; i < l; i++) {
00146         if (tname[i] >= '0' && tname[i] <= '9') {
00147             if (num == 0) {
00148                 fac *= ID_FAC;
00149                 num = i+1;
00150             }
00151         } else {
00152             if (num > 0) {
00153                 tname[i] = '\0';
00154                 id += fac*atoi(tname+num-1);
00155                 n++;
00156                 num = 0;
00157             }
00158         }
00159     }
00160 
00161 #else
00162 
00163     // Improved code:  no copy and uses strtol (Steve, 12/01).
00164     //
00165     // New (12/01) version encodes only the *first* number found
00166     // in name, relying on the value of n to keep id unique.
00167     //
00168     // New new version (12/01) uses an int to store the data, rather than
00169     // a real.  Versions distinguished by value of NEW_UNIQUE_ID_T.
00170 
00171     char *c = name, *end;
00172     bool num = false;
00173 
00174     while (1) {
00175 
00176         // Find the next digit in name.
00177 
00178         while (*c && !isdigit(*c)) c++;
00179 
00180         if (*c) {
00181 
00182             // New number starts at c.  Read and count it.  With the new code,
00183             // it may be quicker just to count commas rather than use strol
00184             // for numbers that won't be used.
00185 
00186             long int i = strtol(c, &end, 10);
00187             n++;
00188 
00189             if (n == 1) {
00190 
00191 #ifndef NEW_UNIQUE_ID_T
00192                 id = (unique_id_t)(ID_FAC*i);   // new (12/01)
00193 #else
00194                 id = (unique_id_t)(i);          // new new (12/01)
00195 #endif
00196             }
00197 
00198             c = end;            // starting point for next search
00199 
00200         } else
00201             break;
00202     }
00203 
00204 #endif
00205 
00206     // Portion of id before the decimal point or shifted by 20 indicates
00207     // the number of numbers found in the name.
00208 
00209 #ifndef NEW_UNIQUE_ID_T
00210     id += n;
00211 #else
00212     id += (n<<ID_SHIFT);                                // new new (12/01)
00213 #endif
00214 
00215     return id;
00216 }
00217 
00218 unique_id_t unique_id(node *b)
00219 {
00220     // Return a unique non-negative real number identifying this node.
00221     // Use the index if available (assume unique!), otherwise, construct
00222     // an integer from the node name.  If the node has no name or index,
00223     // ignore it (id = -1).
00224 
00225     // The root node should be called "root", and will therefore
00226     // be assigned an ID of 0.
00227 
00228     if (b->get_index() > 0)
00229         return unique_id(b->get_index());
00230 
00231     else if (b->get_name())
00232         return unique_id(b->format_label());
00233 
00234     else
00235         return -1;
00236 }
00237 
00238 void print_id(void *id, char *s = NULL, int offset = 0)
00239 {
00240     real *r = (real *)id;
00241     unsigned long long *u = (unsigned long long *)id;
00242 
00243     real rr = *r;
00244     unsigned long long uu = *u;
00245 
00246     if (offset > 0) PRI(offset);
00247     if (s)
00248         cerr << s << ": ";
00249     else
00250         cerr << "    ";
00251 
00252     fprintf(stderr, "%.16lf = %qu = %qx\n", rr, uu, uu);
00253 }
00254 
00255 void worldline::dump(int offset,        // default = 0
00256                      real t1,           // default = 0
00257                      real t2)           // default = VERY_LARGE_NUMBER
00258 {
00259     // Print a worldline, from time t1 to time t2.
00260 
00261     PRI(offset+4); PRC(start_esc_flag); PRC(end_esc_flag); PRL(t_esc);
00262 
00263     segment *s = get_first_segment();
00264     int is = 0;
00265     while (s) {
00266         real t_start = s->get_t_start();
00267         real t_end = s->get_t_end();
00268         if (t_start <= t2 && t_end >= t1) { 
00269             PRI(offset+4); cerr << "segment " << is << " (" << s << "): ";
00270             PRC(t_start); PRL(t_end);
00271             print_id(&id, "id", offset+8);
00272         }
00273         tdyn *b = s->get_first_event();
00274         int ie = 0;
00275         while (b) {
00276             real t = b->get_time();
00277             if (t >= t1 && t <= t2) {
00278                 PRI(offset+8);
00279                 cerr << "event " << ie << ": name = "
00280                      << b->format_label() << ", ";
00281                 PRL(t);
00282             }
00283             b = b->get_next();
00284             ie++;
00285         }
00286         if (t_start <= t2 && t_end >= t1) { 
00287             if (ie == 1) {
00288                 PRI(offset+8); cerr << "*** single event ***" << endl;
00289             }
00290         }
00291         s = s->get_next();
00292         is++;
00293     }
00294 }
00295 
00296 local void check_print_worldline_header(bool& print, int i)
00297 {
00298     cerr << "worldline " << i << ":" << endl;
00299     print = false;
00300 }
00301 
00302 void worldline::check(int i)    // default = -1
00303 {
00304     // Check a worldline, start to finish.
00305 
00306     bool print = true;
00307 
00308     segment *s = get_first_segment();
00309     int is = 0;
00310     while (s) {
00311         tdyn *b0 = s->get_first_event();
00312         tdyn *b = b0;
00313         int ie = 0;
00314         while (b) {
00315             real t = b->get_time();
00316             if (b != b0) {
00317                 tdyn *p = b->get_prev();
00318                 if (!p) {
00319                     if (print) check_print_worldline_header(print, i);
00320                     cerr << "    segment " << is << ", event "
00321                          << ie << " has prev = NULL" << endl;
00322                 } else if (p->get_next() != b) {
00323                     if (print) check_print_worldline_header(print, i);
00324                     cerr << "    segment " << is << ", event "
00325                          << ie << " has prev->next != this" << endl;
00326                 }
00327             }
00328             b = b->get_next();
00329             ie++;
00330         }
00331         if (ie == 1) {
00332             if (print) check_print_worldline_header(print, i);
00333             cerr << "    *** single event in segment " << is << " ***" << endl;
00334         }
00335 
00336         s = s->get_next();
00337         is++;
00338     }
00339 }
00340 
00341 void segment::print(char *label)
00342 {
00343     if (label == NULL) label = "    ";
00344     cerr << label << "name " << first_event->format_label()
00345          << ", id = " << id
00346          << ", t_start = " << t_start
00347          << ", t_end = " << t_end
00348          << endl;
00349 }
00350 
00351 //======================================================================
00352 
00353 local int wlcompare(const void *a, const void *b)       // a and b are actually
00354                                                         // of type worldlineptr*
00355 {
00356     worldlineptr wa = *((worldlineptr*)a);              // ugly!
00357     worldlineptr wb = *((worldlineptr*)b);
00358 
00359     int result = 0;
00360 //    cerr << "comparing " << wa->get_id() << " and " << wb->get_id() << endl;
00361 
00362     if (wa->get_id() < wb->get_id())
00363         result = -1;
00364     else if (wa->get_id() > wb->get_id())
00365         result = 1;
00366 
00367 //    PRL(result);
00368     return result;
00369 }
00370 
00371 worldbundle::worldbundle(tdyn *b)
00372 {
00373     // Create a new worldbundle from the nodes below b.
00374 
00375     nw_max = 0;
00376     for_all_nodes(tdyn, b, bb) nw_max++;
00377 
00378     nw_max *= 2;                                // conservative
00379 
00380     bundle = new worldlineptr[nw_max];
00381     nw = 0;
00382 
00383     t_min = VERY_LARGE_NUMBER;
00384     t_max = -VERY_LARGE_NUMBER;
00385 
00386     t_int = -VERY_LARGE_NUMBER;
00387     root = NULL;
00388 
00389     // Add nodes to the list.
00390 
00391     for_all_nodes(tdyn, b, bb) {
00392 
00393         // *** Flag recomputation of acc and jerk. ***
00394 
00395         bb->clear_jerk();
00396 
00397         real t = bb->get_time();
00398         worldline *w = new worldline(bb);
00399 
00400         bundle[nw++] = w;
00401 
00402         t_min = min(t_min, t);
00403         t_max = max(t_max, t);
00404     }
00405 
00406     // Sort the list by ID.
00407 
00408     qsort((void*)bundle, (size_t)nw, sizeof(worldlineptr), wlcompare);
00409 
00410 //    for (int i = 0; i < nw; i++) {
00411 //      PRC(i); PRC(bundle[i]->get_id());
00412 //      cerr << bundle[i]->get_first_segment()
00413 //                       ->get_first_event()->format_label() << endl;
00414 //    }
00415 }
00416 
00417 void worldbundle::print()
00418 {
00419     // Print out basic information about this worldbundle.
00420 
00421     for (int i = 0; i < nw; i++) {
00422 
00423         worldline *w = bundle[i];
00424         segment *s = w->get_first_segment();
00425         int segnum = 0;
00426 
00427         cerr << i << " (" << s->get_first_event()->format_label();
00428         int p = cerr.precision(HIGH_PRECISION);
00429         cerr << ", id = " << w->get_id() << ")";
00430         cerr.precision(p);
00431         cerr << "  t_start = " << w->get_t_start()
00432              << ", t_end = " << w->get_t_end()
00433              << endl;
00434 
00435         while (s) {
00436 
00437             segnum++;
00438             int nn = 1;
00439 
00440             tdyn *b = s->get_first_event();
00441             while (b->get_next()) {
00442                 b = b->get_next();
00443                 nn++;
00444             }
00445 
00446             cerr << "        segment " << segnum << ":  "
00447                  << s->get_t_start() << " (" << nn << ") " << s->get_t_end()
00448                  << endl;
00449 
00450             s = s->get_next();
00451         }
00452     }
00453 }
00454 
00455 void worldbundle::dump(int offset)      // default = 0
00456 {
00457     for (int i = 0; i < get_nw(); i++) {
00458         PRI(offset); cerr << "worldline " << i << ":" << endl;
00459         get_worldline(i)->dump(offset);
00460     }
00461 }
00462 
00463 void worldbundle::check()
00464 {
00465     cerr << "checking worldbundle " << this << endl;
00466     for (int i = 0; i < get_nw(); i++)
00467         get_worldline(i)->check(i);
00468 }
00469 
00470 //======================================================================
00471 
00472 int worldbundle::find_index(unique_id_t id)
00473 {
00474     // Find the index of the worldline corresponding to id.
00475 
00476     // Return values:   0 - nw-1        index of id
00477     //                  -1              id out of range below
00478     //                  -nw-1           id out of range above
00479     //                  -nw -- -2       -(first index above id) - 1
00480     //
00481     // (so -find_index - 1 is where a new worldline should go in the list).
00482 
00483     // The list is ordered in id; use bisection to search it.
00484 
00485     int loc;
00486 
00487     if (nw <= 0 || id < bundle[0]->get_id()) {
00488         PRC(id); PRL(bundle[0]->get_id());
00489         loc = -1;
00490     }
00491 
00492     else if (id > bundle[nw-1]->get_id())
00493         loc = -nw-1;
00494 
00495     else {
00496 
00497         int low = 0, high = nw-1;
00498         loc = (low+high)/2;
00499 
00500         if (bundle[low]->get_id() == id)
00501             loc = low;
00502 
00503         else if (bundle[high]->get_id() == id)
00504             loc = high;
00505 
00506         else if (bundle[loc]->get_id() != id) {
00507 
00508             bool found = false;
00509 
00510             while (low < high-1) {
00511 
00512                 if (bundle[loc]->get_id() < id)
00513                     low = loc;
00514                 else if (bundle[loc]->get_id() > id)
00515                     high = loc;
00516                 else {
00517                     found = true;
00518                     break;
00519                 }
00520 
00521                 loc = (low+high)/2;
00522             }
00523 
00524             if (!found) loc = -high - 1;
00525         }
00526     }
00527 
00528     return loc;
00529 }
00530 
00531 int worldbundle::find_index(char *name) {return find_index(unique_id(name));}
00532 int worldbundle::find_index(_pdyn_ *b)  {return find_index(unique_id(b));}
00533 
00534 worldline *worldbundle::find_worldline(unique_id_t id)
00535 {
00536     int i = find_index(id);
00537     if (i >= 0 && i < nw)
00538         return bundle[i];
00539     else
00540         return NULL;
00541 }
00542 
00543 worldline *worldbundle::find_worldline(char *name)
00544 {return find_worldline(unique_id(name));}
00545 
00546 worldline *worldbundle::find_worldline(_pdyn_ *b)
00547 {return find_worldline(unique_id(b));}
00548 
00549 //======================================================================
00550 
00551 // Update the world bundle.
00552 
00553 void worldbundle::attach(tdyn *bn,
00554                          int verbose)           // default = 0
00555 {
00556     // Locate and attach all components of bn in the 4tree hierarchy.
00557 
00558     if (bn) {
00559 
00560         for_all_nodes(tdyn, bn, b) {
00561 
00562             // *** Flag recomputation of acc and jerk. ***
00563 
00564             b->clear_jerk();
00565 
00566             // Find the start of b's current worldline segment, or
00567             // add b to the list.  There are three possibilities:
00568             //
00569             //  (1) b's ID is on the list and b is valid
00570             //                          ==> extend the current segment
00571             //                              or begin a new one if the
00572             //                              previous b was defunct
00573             //
00574             //  (2) b's ID is on the list and b is defunct
00575             //                          ==> end the current segment
00576             //
00577             //  (3) b's ID is not on the list
00578             //                          ==> extend the list and open
00579             //                              a new segment
00580             //
00581             // Cases (1) and (2) are handled at the same time.
00582 
00583             // Find b on the worldline list or add it to the list
00584             // (maintaining the list ordering).
00585 
00586             unique_id_t id = unique_id(b);
00587 
00588             if (id >= 0) {
00589 
00590                 real t = b->get_time();
00591                 int loc = find_index(id);
00592 
00593 //              int p;
00594 //              bool deb = false;
00595 //              if (t >= 13.275 && t <= 13.313) {
00596 //                  if (node_contains(b, "(12,25)")) {
00597 //                      deb = true;
00598 //                      p = cerr.precision(HIGH_PRECISION);
00599 //                      PRC(b->format_label()); PRL(b->is_defunct());
00600 //                  }
00601 //              }
00602 
00603                 if (loc >= 0) {
00604 
00605                     // Extend an existing worldline.
00606 
00607                     worldline *w = bundle[loc];
00608                     segment *s = w->get_last_segment(); // "last" = "current"
00609 
00610 //                  if (deb) {
00611 //                      PRC(s); PRL(t);
00612 //                      PRC(b->format_label()); PRL(id);
00613 //                      w->dump(0, 13.25);
00614 //                  }
00615 
00616                     // Check case (2) for previous instance of b.
00617 
00618                     if (s->get_last_event()->is_defunct()) {
00619 
00620                         if (verbose)
00621                             cerr << "starting new segment for "
00622                                  << b->format_label()
00623                                  << " (id = " << id
00624                                  << ") at t = " << t
00625                                  << endl;
00626 
00627                         // Create a new segment starting at b.
00628 
00629                         s = new segment(b);
00630                         w->add_segment(s, true);  // "true" ==> skip id check
00631                                                   // (see comments below...)
00632 
00633                         if (verbose)
00634                             cerr << "new segment = " << s << endl;
00635 
00636                     } else {
00637 
00638                         // Case (1): extend the current segment.
00639 
00640                         s->add_event(b, true);    // "true" ==> skip id check
00641 
00642                         // Note from Steve (8/01):  For unknown reasons,
00643                         // the id checks in add_event() and add_segment()
00644                         // may cause errors when optimization is turned on.
00645                         // Problems arise in multiple systems (so we are
00646                         // working near the last significant digit), where
00647                         // the ids may return unequal even though the bits
00648                         // are identical.  Didn't occur in the July 29,
00649                         // 2001 version of the code.  Does occur in the
00650                         // August 2 version!
00651                         //
00652                         // Workaround for now: skip the check, which is
00653                         // redundant here anyway.  Longer-term: improve
00654                         // the handling of unique_id.  Comparing reals is
00655                         // probably always a bad idea...
00656                     }
00657 
00658                     // if (deb) cerr.precision(p);
00659 
00660                     w->set_t_end(t);
00661 
00662                 } else {
00663 
00664                     // Case (3): create a new worldline starting at b.
00665                     // Maintain the ordering of the array by placing the
00666                     // new pointer at location -loc - 1.
00667 
00668                     if (nw >= nw_max) {
00669 
00670                         // Extend the storage array -- use new and
00671                         // delete to mimic realloc().
00672 
00673                         nw_max *= 5;
00674                         nw_max /= 4;
00675 
00676                         cerr << "extending bundle array for worldbundle "
00677                              << this << ":  nw_max = "
00678                              << nw_max << endl;
00679 
00680                         worldlineptr *tmp = new worldlineptr[nw_max];
00681                         for (int i = 0; i < nw; i++)
00682                             tmp[i] = bundle[i];
00683                         delete [] bundle;
00684                         bundle = tmp;
00685                     }
00686 
00687                     // Where to insert the new worldline:
00688 
00689                     loc = -loc - 1;
00690 
00691                     for (int i = nw-1; i >= loc; i--)
00692                         bundle[i+1] = bundle[i];
00693 
00694                     bundle[loc] = new worldline(b);
00695                     nw++;
00696 
00697                     if (verbose)
00698                         cerr << "adding " << b->format_label()
00699                              << " (id = " << id
00700                              << ") at t = " << b->get_time()
00701                              << endl;
00702                 }
00703 
00704                 t_max = max(t_max, t);
00705             }
00706         }
00707     }
00708 }
00709 
00710 //======================================================================
00711 
00712 static real physical_mass = 0;
00713 
00714 real mass_scale_factor()
00715 {
00716     return physical_mass;
00717 }
00718 
00719 local void check_final_escapers(worldbundle *wb, tdyn *b)
00720 {
00721     for_all_nodes(tdyn, b, bb) {
00722         worldline *w = NULL;
00723         if (bb->get_prev()) {                   // esc flag is set
00724             bb->set_prev(NULL);
00725             w = wb->find_worldline(bb);
00726             if (w) w->set_end_esc_flag(1);
00727         }
00728         if (bb->get_next()) {                   // t_esc is specified
00729             real *t_esc = (real*)bb->get_next();
00730             bb->set_next(NULL);
00731             if (!w) w = wb->find_worldline(bb);
00732             if (w) w->set_t_esc(*t_esc);
00733             delete t_esc;
00734         }
00735     }
00736 }
00737 
00738 // From Steve (10/00):
00739 //
00740 // Root dumps are done by kira twice per synchronization interval, so each
00741 // worldbundle is self-contained (this is the *same* as the way in which
00742 // tree changes are handled...).
00743 
00744 worldbundle *read_bundle(istream &s,
00745                          int verbose)                   // default = 0
00746 {
00747     // Read a bundle of worldlines, from root dump to root dump.
00748 
00749     // First read the base root node.  Assume without checking that
00750     // the next portion of input data starts with a complete system.
00751 
00752     tdyn *b = get_tdyn(s, NULL, NULL, false);           // "stripped tdyn"
00753     if (!b || !streq(b->format_label(), "root")) return NULL;
00754 
00755     // Need to keep track of the physical initial mass, but this only
00756     // appears in the first Log story and is not saved in the usual
00757     // story structure, to save space.  Grab it here and make it
00758     // globally accessible.
00759 
00760     if (b->get_log_story())
00761         physical_mass = getrq(b->get_log_story(), "physical_initial_mass");
00762 
00763     // Create the initial list of node IDs, esc_flags, etc.  Note that
00764     // we use the prev pointer in tdyn to carry temporary information
00765     // about cluster membership.  These should be new worldline(b),
00766     // which is called by new worldbundle(b).  We do *not* check here!
00767 
00768     worldbundle *wb = new worldbundle(b);
00769 
00770     if (verbose)
00771         cerr << endl
00772              << "new worldbundle: created initial list, nw = "
00773              << wb->get_nw() << endl;
00774 
00775     // Now read in individual nodes and attach them to the 4tree.
00776     // Stop when another tree is read in.
00777 
00778     while (b = get_tdyn(s, NULL, NULL, false)) {        // "stripped tdyn"
00779 
00780         // A new tree fragment will be read in every time the tree
00781         // changes, so pointers should be correctly maintained.
00782         // Links are found at the start of each worldline segment.
00783 
00784         // If this is the terminating full snapshot, we must check
00785         // the prev pointers for updated information on escapers
00786         // before we attach to the 4tree.
00787 
00788         bool stop = (b->get_oldest_daughter()
00789                      && streq(b->format_label(), "root"));
00790         if (stop)
00791             check_final_escapers(wb, b);
00792 
00793         // Connect b to the 4tree.
00794 
00795         wb->attach(b, verbose);
00796 
00797         // Stop once we have read in another complete system.
00798 
00799         if (stop) {
00800             if (verbose)
00801                 cerr << "break at t = " << b->get_time() << endl;
00802             break;
00803         }
00804     }
00805 
00806     if (verbose) {
00807 
00808         cerr << "after last input:  nw = " << wb->get_nw()
00809              << endl;
00810 
00811         // Print some global diagnostics:
00812 
00813         for (int i = 0; i < wb->get_nw(); i++) {
00814             worldline *w = wb->get_bundle()[i];
00815 
00816             // First check segments.
00817 
00818             int seg = 0, nseg = 0;
00819             segment *s = w->get_first_segment();
00820             tdyn *b = s->get_first_event();
00821             real t = s->get_t_start();
00822 
00823             while (s) {
00824                 nseg++;
00825                 s = s->get_next();
00826             }
00827 
00828             s = w->get_first_segment();
00829             int n_jump = 0;
00830 
00831             while (s) {
00832 
00833                 if (s->get_t_start() >= s->get_t_end()) {
00834                     int p = cerr.precision(HIGH_PRECISION);
00835                     cerr << "worldline " << i << " (" << b->format_label()
00836                          << "), id = " << w->get_id() << endl;
00837                     cerr.precision(p);
00838                     PRI(10); cerr << "zero-length segment at t = "
00839                                   << s->get_t_start()
00840                                   << ";  segment " << seg << " of " << nseg
00841                                   << endl;
00842                 }
00843 
00844                 if (s->get_t_start() > t) {
00845                     n_jump++;
00846                     if (verbose > 1) {
00847                         int p = cerr.precision(HIGH_PRECISION);
00848                         cerr << "worldline " << i << " (" << b->format_label()
00849                             << "), id = " << w->get_id() << endl;
00850                         cerr.precision(p);
00851                         PRI(10); cerr << "jump from " << t
00852                                       << " to " << s->get_t_start()
00853                                       << " after segment " << seg
00854                                       << " of " << nseg
00855                                       << endl;
00856                     }
00857                 }
00858 
00859                 t = s->get_t_end();
00860                 seg++;
00861                 s = s->get_next();
00862             }
00863 
00864             if (verbose == 1 && n_jump > 0) {
00865                 cerr << "worldline " << i << " (" << b->format_label()
00866                      << "), id = " << w->get_id()
00867                      << " has " << n_jump << " jump";
00868                 if (n_jump > 1) cerr << "s";
00869                 cerr << endl;
00870             }
00871 
00872             // Then check events within each segment.
00873 
00874             seg = 0;
00875             s = w->get_first_segment();
00876             while (s) {
00877 
00878                 b = s->get_first_event();
00879 
00880                 if (b->get_time() != s->get_t_start()) {
00881                     int p = cerr.precision(HIGH_PRECISION);
00882                     cerr << "worldline " << i << " (" << b->format_label()
00883                          << "), id = " << w->get_id() << endl;
00884                     cerr.precision(p);
00885                     PRI(10); cerr << "t_start =  " << s->get_t_start()
00886                                   << ", t = "
00887                                   << b->get_time() << " in segment " << seg
00888                                   << " of " << nseg << endl;
00889                 }
00890 
00891                 while (b && b->get_next()) b = b->get_next();
00892 
00893                 if (b->get_time() != s->get_t_end()) {
00894                     int p = cerr.precision(HIGH_PRECISION);
00895                     cerr << "worldline " << i << " (" << b->format_label()
00896                          << "), id = " << w->get_id() << endl;
00897                     cerr.precision(p);
00898                     PRI(10); cerr << "t_end =  " << s->get_t_end() << ", t = "
00899                                   << b->get_time() << " in segment " << seg
00900                                   << " of " << nseg << endl;
00901                 }
00902 
00903                 seg++;
00904                 s = s->get_next();
00905             }
00906         }
00907     }
00908 
00909     return wb;
00910 }
00911 
00912 int count_segments(worldbundle *wb)
00913 {
00914     int ns = 0;
00915     for (int i = 0; i < wb->get_nw(); i++) {
00916         worldline *w = wb->get_worldline(i);
00917         segment *s = w->get_first_segment();
00918         while (s) {
00919             ns++;
00920             s = s->get_next();
00921         }
00922     }
00923     return ns;
00924 }
00925 
00926 int count_events(worldbundle *wb)
00927 {
00928     int ne = 0;
00929     for (int i = 0; i < wb->get_nw(); i++) {
00930         worldline *w = wb->get_worldline(i);
00931         segment *s = w->get_first_segment();
00932         while (s) {
00933             tdyn *b = s->get_first_event();
00934             while (b) {
00935                 ne++;
00936                 b = b->get_next();
00937             }
00938             s = s->get_next();
00939         }
00940     }
00941     return ne;
00942 }
00943 
00944 //======================================================================
00945 
00946 // Navigation of the 4tree data and diagnostic output.
00947 
00948 tdyn *find_event(worldline *w, tdyn *bn, real t)
00949 {
00950     // Find time t along the segment of worldline w starting at base
00951     // node bn.  Return a pointer to the event immediately preceding t.
00952     //
00953     // If worldline w is set, first see if any current_event pointer
00954     // exists; if so, start our search there.  The logic in the calling
00955     // function should ensure that time t lies in the current segment.
00956 
00957     // Default is forward search starting at bn.  This may be modified
00958     // if current_event information exists.
00959 
00960     tdyn *b = bn;
00961 
00962     if (w) {
00963 
00964         tdyn *curr = w->get_current_event();
00965 
00966         if (curr) {
00967 
00968             real t_curr = curr->get_time();
00969             real t_bn = bn->get_time();         // evaluating bn->get_time() in
00970                                                 // if (..) below causes strange
00971                                                 // error on margaux (DecUNIX)...
00972 
00973             if (t_curr > t) {
00974 
00975                 if (t > 0.5*(t_bn + t_curr)) {
00976 
00977                     // Do a backward search from curr.
00978 
00979                     b = curr;
00980 #if 0
00981                     if (b != bn && !b->get_prev()) {
00982                         cerr << endl << "prev = NULL for node " << b << endl;
00983                         PRC(b); PRL(bn);
00984                         cerr << "worldline dump:" << endl;
00985                         w->dump();
00986                         cerr << "checking worldline..." << endl;
00987                         w->check(-1);
00988                     }
00989 #endif
00990 
00991                     tdyn *p;
00992                     while (b && (p = b->get_prev()) && b->get_time() > t)
00993                         b = p;
00994 
00995                     return b;
00996                 }
00997 
00998             } else {
00999 
01000                 // Explicitly test the most obvious possibility first.
01001                 // Case next = NULL probably means an error in the data,
01002                 // but do something reasonable anyway (return curr).
01003 
01004                 tdyn *n = curr->get_next();
01005                 if (!n || n->get_time() >= t) return curr;
01006 
01007                 // Do a forward search from n.
01008 
01009                 b = n;
01010 
01011             }
01012         }
01013     }
01014 
01015     // Do a forward search from b.  Note that repeated "get_next" calls
01016     // may be quite time consuming if we keep going outside the cache.
01017 
01018     tdyn *n;
01019     while (b && (n = b->get_next()) && n->get_time() < t)
01020         b = n;
01021 
01022     // The portion of the trajectory spanning t runs from b to b->next.
01023 
01024     return b;
01025 }
01026 
01027 void print_event(worldline *w, tdyn *bn, real t)
01028 {
01029     // Print info on the portion of the worldline portion
01030     // starting at bn that spans t.
01031 
01032     tdyn *b = find_event(w, bn, t);
01033 
01034     if (b) {
01035         PRC(t); PRC(b->get_time()); PRL(b->get_next());
01036         if (b->get_next()) PRL(b->get_next()->get_time());
01037     }
01038 }
01039 
01040 //----------------------------------------------------------------------
01041 #include "print_local.C"        // avoid repeating local print functions
01042 //----------------------------------------------------------------------
01043 
01044 local inline bool check_and_initialize(tdyn *p,
01045                                        real tp,
01046                                        real t,
01047                                        vector& pos,
01048                                        bool inc,
01049                                        tdyn *bn)
01050 {
01051     if (tp < t) {
01052 
01053         tdyn *n = p->get_next();
01054 
01055         if (!n) {
01056 
01057             cerr << "interpolate_pos: error 2: next node not found: ";
01058             PRC(p->format_label()); PRL(t);
01059             int pr = cerr.precision(HIGH_PRECISION);
01060             PRL(unique_id(p)); cerr.precision(pr);
01061             PRI(26); PRC(bn); PRL(bn->get_time());
01062             PRI(26); PRC(p); PRL(p->get_time());
01063             PRI(26); PRL(p->get_time()-t);
01064             if (bn) {
01065                 PRI(26); PRL(bn->format_label());
01066                 pr = cerr.precision(HIGH_PRECISION);
01067                 PRL(unique_id(bn)); cerr.precision(pr);
01068             }
01069             // print_details(wb, p, t);
01070 
01071             if (inc)
01072                 pos += p->get_pos();
01073             else
01074                 pos = p->get_pos();
01075             return false;
01076 
01077         } else if (n->get_time() < t) {
01078 
01079             cerr << "interpolate_pos: error 3: specified time above range: ";
01080             PRC(p->format_label()); PRC(t); PRL(p->get_time());
01081             // print_details(wb, p, t);
01082 
01083             if (inc)
01084                 pos += p->get_pos();
01085             else
01086                 pos = p->get_pos();
01087             return false;
01088         }
01089 
01090         // We now have tp < t <= n->time.  We will interpolate using
01091         // a fit to pos and vel.  Check to see if the interpolating
01092         // coefficients must be set.
01093 
01094         if (p->get_jerk()[0] == 0) {
01095 
01096             // Recompute acc/2 and jerk/6 to fit pos and vel.
01097 
01098             // Note that we overwrite acc and jerk by equivalent
01099             // vectors that guarantee continuity of pos and vel.
01100 
01101             // *** Flag this to prevent recalculation by setting ***
01102             // *** jerk = 0 as the tree is constructed.          ***
01103 
01104             // Set up the interpolating acc and jerk.
01105 
01106             real dt = n->get_time() - tp;
01107             real dti = 1/dt;
01108 
01109             if (streq(p->get_name(), "root")) {         // infrequent...
01110 
01111                 // Use linear interpolation for the cluster center.
01112                 // Discard vel information to make pos continuous.
01113 
01114                 p->set_vel(dti*(n->get_pos() - p->get_pos()));
01115                 p->set_acc(0);
01116                 p->set_jerk(vector(VERY_SMALL_NUMBER, 0, 0));
01117 
01118             } else {
01119 
01120                 // Standard fourth-order interpolation otherwise.
01121 
01122                 p->set_acc((3*(n->get_pos()-p->get_pos())
01123                             - dt*(2*p->get_vel()+n->get_vel()))*dti*dti);
01124                 p->set_jerk((p->get_vel()+n->get_vel()
01125                              - 2*dti*(n->get_pos()-p->get_pos()))*dti*dti);
01126             }
01127         }
01128         return true;
01129 
01130     } else if (tp > t) {
01131 
01132         cerr << "interpolate_pos: error 1: specified time below range: ";
01133         PRC(p->format_label()); PRC(t); PRL(p->get_time());
01134         // print_details(wb, p, t); // wb not available here...
01135     }
01136 
01137     // (Special case tp == t is handled here.)
01138 
01139     if (inc)
01140         pos += p->get_pos();
01141     else
01142         pos = p->get_pos();
01143 
01144     return false;
01145 }
01146 
01147 // Interpolation of part of the 4tree to a specific time.
01148 
01149 // Retain numerous "interpolate_pos" functions for timing and testing...
01150 // Apparently very little time difference between them.  New code may be
01151 // marginally faster, by perhaps 5 percent, but its use unaccountably
01152 // increases the time spent in other portions of the code, for a net
01153 // improvement of only 1 percent or so.  See profile_*_interp.txt.  The
01154 // function node::next_node() seems to be used 4 times more frequently
01155 // in the new code, offsetting most of the gain in the other functions.
01156 
01157 // Old version:
01158 
01159 vector interpolate_pos(tdyn *p, real t,
01160                        tdyn *bn)                // default = NULL; specifies
01161                                                 // actual base node
01162 {
01163     // The range (p to p->next) includes time t.
01164     // Interpolate and return the pos of this particle.
01165 
01166     // Check...
01167 
01168     if (p->get_time() > t) {
01169         cerr << "interpolate_pos: error 1: specified time below range: ";
01170         PRC(p->format_label()); PRC(t); PRL(p->get_time());
01171         // print_details(wb, p, t); // wb not available here...
01172 
01173         return p->get_pos();
01174     }
01175 
01176     // Special case:
01177 
01178     if (p->get_time() == t) return p->get_pos();
01179 
01180     tdyn *n = p->get_next();
01181 
01182     if (!n) {
01183         cerr << "interpolate_pos: error 2: next node not found: ";
01184         PRC(p->format_label()); PRL(t);
01185         int pr = cerr.precision(HIGH_PRECISION);
01186         PRL(unique_id(p)); cerr.precision(pr);
01187         PRI(26); PRC(bn); PRL(bn->get_time());
01188         PRI(26); PRC(p); PRL(p->get_time());
01189         PRI(26); PRL(p->get_time()-t);
01190         if (bn) {
01191             PRI(26); PRL(bn->format_label());
01192             pr = cerr.precision(HIGH_PRECISION);
01193             PRL(unique_id(bn)); cerr.precision(pr);
01194         }
01195         // print_details(wb, p, t);
01196 
01197         return p->get_pos();
01198     }
01199 
01200     if (n->get_time() < t) {
01201         cerr << "interpolate_pos: error 3: specified time above range: ";
01202         PRC(p->format_label()); PRC(t); PRL(p->get_time());
01203         // print_details(wb, p, t);
01204 
01205         return p->get_pos();
01206     }
01207 
01208     // Time t is included in the range.
01209 
01210     // Interpolate using pos and vel for now...
01211     // Note that we overwrite acc and jerk by equivalent
01212     // vectors that guarantee continuity of pos and vel.
01213 
01214     real tp = p->get_time();
01215     real dt = n->get_time() - tp;
01216 
01217     if (dt > 0) {
01218 
01219         // Recompute acc/2 and jerk/6 to fit pos and vel.
01220 
01221         // *** Flag this to prevent recalculation by setting ***
01222         // *** jerk = 0 as the tree is constructed.          ***
01223 
01224         if (p->get_jerk()[0] == 0) {
01225 
01226             // Set up the interpolating acc and jerk.
01227 
01228             real dti = 1/dt;
01229 
01230             if (streq(p->get_name(), "root")) {         // infrequent...
01231 
01232                 // Use linear interpolation for the cluster center.
01233                 // Discard vel information to make pos continuous.
01234 
01235                 p->set_vel(dti*(n->get_pos() - p->get_pos()));
01236                 p->set_acc(0);
01237                 p->set_jerk(vector(VERY_SMALL_NUMBER, 0, 0));
01238 
01239             } else {
01240 
01241                 // Standard fourth-order interpolation otherwise.
01242 
01243                 p->set_acc((3*(n->get_pos()-p->get_pos())
01244                             - dt*(2*p->get_vel()+n->get_vel()))*dti*dti);
01245                 p->set_jerk((p->get_vel()+n->get_vel()
01246                              - 2*dti*(n->get_pos()-p->get_pos()))*dti*dti);
01247             }
01248         }
01249 
01250         dt = t - tp;
01251 
01252         return p->get_pos() + dt * (p->get_vel()
01253                                     + dt * (p->get_acc()
01254                                             + dt * p->get_jerk()));
01255     } else
01256 
01257         return p->get_pos();
01258 }
01259 
01260 // Overloaded (and not used?):
01261 
01262 void interpolate_pos(tdyn *p,
01263                      real t,
01264                      vector& pos,
01265                      bool inc,                  // default = false
01266                      tdyn *bn)                  // default = NULL; specifies
01267                                                 // the actual base node
01268 {
01269     // The range (p to p->next) includes time t.
01270     // Interpolate and return the pos of this particle.
01271 
01272     real tp = p->get_time();
01273 
01274     if (check_and_initialize(p, tp, t, pos, inc, bn)) {
01275 
01276         real dt = t - tp;
01277 
01278         if (inc)
01279             pos += p->get_pos() + dt * (p->get_vel()
01280                                            + dt * (p->get_acc()
01281                                                       + dt * p->get_jerk()));
01282         else
01283             pos = p->get_pos() + dt * (p->get_vel()
01284                                           + dt * (p->get_acc()
01285                                                      + dt * p->get_jerk()));
01286     }
01287 }
01288 
01289 // New versions (NEW_INTERP):
01290 
01291 void set_interpolated_pos(tdyn *p,
01292                           real t,
01293                           vector& pos,
01294                           tdyn *bn)             // default = NULL; specifies
01295                                                 // the actual base node
01296 {
01297     // The range (p to p->next) includes time t.
01298     // Interpolate and set the value of pos.
01299 
01300     real tp = p->get_time();
01301 
01302     if (check_and_initialize(p, tp, t, pos, false, bn)) {
01303 
01304         real dt = t - tp;
01305         pos = p->get_pos() + dt * (p->get_vel()
01306                                       + dt * (p->get_acc()
01307                                                  + dt * p->get_jerk()));
01308     }
01309 }
01310 
01311 // Overloaded:
01312 
01313 void set_interpolated_pos(tdyn *p,
01314                           real t,
01315                           pdyn *curr,
01316                           tdyn *bn)             // default = NULL; specifies
01317                                                 // the actual base node
01318 {
01319     // The range (p to p->next) includes time t.
01320     // Interpolate and set the value of pos.
01321 
01322     real tp = p->get_time();
01323     vector pos;
01324 
01325     if (check_and_initialize(p, tp, t, pos, false, bn)) {
01326 
01327         real dt = t - tp;
01328         curr->set_pos(p->get_pos() + dt * (p->get_vel()
01329                                             + dt * (p->get_acc()
01330                                                      + dt * p->get_jerk())));
01331     } else
01332 
01333         curr->set_pos(pos);
01334 }
01335 
01336 void inc_interpolated_pos(tdyn *p,
01337                           real t,
01338                           vector& pos,
01339                           tdyn *bn)             // default = NULL; specifies
01340                                                 // the actual base node
01341 {
01342     // The range (p to p->next) includes time t.
01343     // Interpolate and increment the value of pos.
01344 
01345     real tp = p->get_time();
01346 
01347     if (check_and_initialize(p, tp, t, pos, true, bn)) {
01348 
01349         real dt = t - tp;
01350         pos += p->get_pos() + dt * (p->get_vel()
01351                                        + dt * (p->get_acc()
01352                                                   + dt * p->get_jerk()));
01353     }
01354 }
01355 
01356 vector interpolate_vel(tdyn *p, real t,
01357                        tdyn *bn)                // default = NULL; specifies
01358                                                 // actual base node
01359 {
01360     // Interpolate and return the vel of this particle.
01361 
01362     // Only called after a call to interpolate_pos, so skip checks
01363     // and recomputation of acc and jerk.
01364 
01365     // Special case:
01366 
01367     if (p->get_time() == t) return p->get_vel();
01368 
01369     tdyn *n = p->get_next();
01370     real tp = p->get_time();
01371     real dt = n->get_time() - tp;
01372 
01373     if (dt > 0) {
01374 
01375         dt = t - tp;
01376         return p->get_vel() + dt * (2*p->get_acc()
01377                                     + dt * 3*p->get_jerk());
01378     } else
01379 
01380         return p->get_vel();
01381 }
01382 
01383 // Older versions of interpolate_pos() and interpolate_vel() are
01384 // (for now) saved in old_interpolate.C
01385 
01386 local vector get_pos(worldline *w,
01387                      tdyn *b, tdyn *bn,
01388                      real t = VERY_LARGE_NUMBER)
01389 {
01390     // Return the current absolute position of node b, properly
01391     // corrected for its location in the tree.
01392 
01393     // The node of interest is b; the base node for the segment of
01394     // worldline w (containing all parental information) is bn.
01395 
01396     if (t == -VERY_LARGE_NUMBER) t = b->get_time();
01397 
01398     vector pos;
01399     set_interpolated_pos(b, t, pos, bn);
01400 
01401     // The tree structure associated with the base node should extend
01402     // to the top level, but will not contain the root node unless bn
01403     // is part of a full dump.
01404 
01405     // Ascend the base tree, including parent contributions (at time t)
01406     // as needed.  Exclude root, but note that is_root() will fail, as
01407     // it simply checks for a null parent.  For now, check the name
01408     // explicitly...
01409 
01410     tdyn *bp = bn->get_parent();
01411 
01412     while (bp) {
01413 
01414         // Find the portion of the parent worldline spanning t.
01415 
01416         tdyn *p = find_event(w, bp, t);
01417 
01418         inc_interpolated_pos(p, t, pos, bn);
01419         bp = bp->get_parent();
01420     }
01421 
01422     return pos;
01423 }
01424 
01425 void worldbundle::print_worldline(char *name,
01426                                   real dt)      // default = 0
01427 {
01428     // Print out the entire worldline (all segments) of particle 'name'.
01429     // Take steps of length dt (0 ==> just use the stored times).
01430 
01431     int loc = find_index(name);                 // find the worldline
01432                                                 // for particle 'name'
01433     if (loc >= 0) {
01434 
01435         worldline *w = bundle[loc];
01436         segment *s = w->get_first_segment();
01437 
01438         if (dt == 0) {
01439 
01440             while (s) {                             // loop over segments
01441 
01442                 tdyn *bn = s->get_first_event();    // starting point
01443                 tdyn *b = bn;
01444                 while (b) {                         // loop over events
01445                     cout << "    " << b->get_time()
01446                          << " " << get_pos(w, b, bn) << endl << flush;
01447                     b = b->get_next();
01448                 }
01449 
01450                 s = s->get_next();
01451             }
01452 
01453         } else {
01454 
01455             real t = get_t_min();
01456             while (t < get_t_max() - 0.5*dt) {
01457 
01458                 // Code here assumes that we are moving sequentially
01459                 // through the data, as we start with the previous s.
01460 
01461                 while (s && s->get_t_end() < t) s = s->get_next();
01462 
01463                 if (s) {
01464                     tdyn *bn = s->get_first_event();
01465                     tdyn *b = find_event(w, bn, t);
01466                     cout << "    " << t
01467                          << " " << get_pos(w, b, bn) << endl << flush;
01468                 }
01469 
01470                 t += dt;
01471             }
01472         }
01473 
01474     } else
01475         cerr << name << " not found" << endl;
01476 }
01477 
01478 //======================================================================
01479 
01480 // Creation of an entire interpolated tree at some specific time.
01481 
01482 //----------------------------------------------------------------------
01483 #include "print_local2.C"       // avoid repeating local print functions
01484 //----------------------------------------------------------------------
01485 
01486 //----------------------------------------------------------------------
01487 #include "attach_new_node.C"    // avoid repeating local print functions
01488 //----------------------------------------------------------------------
01489 
01490 //----------------------------------------------------------------------
01491 #include "update_node.C"        // avoid repeating local functions
01492 //----------------------------------------------------------------------
01493 
01494 local INLINE void add_to_interpolated_tree(worldbundle *wb,
01495                                            worldline *w, segment *s,
01496                                            pdyn *root, real t, bool vel,
01497                                            bool debug)
01498 {
01499     // Current worldline is w, segment is s.  Find the base node
01500     // (containing all relevant tree information) for this particle,
01501     // and the current event.
01502 
01503     // *** By construction, on entry, w and s represent a leaf. ***
01504 
01505     tdyn *bn = s->get_first_event();
01506 
01507     if (debug) {
01508         cerr << "s = " << s << endl
01509              << "first event = " << bn << " "
01510              << bn->format_label() << " "
01511              << bn->get_time() << endl;
01512 
01513         print_details(wb, bn, t);
01514     }
01515 
01516     // Create the entire portion of the tree corresponding to the
01517     // top-level node of bn.  Note that top will probably be bn most
01518     // of the time.
01519 
01520     // Need to be careful with top-level nodes, as they  generally
01521     // won't have parent nodes (no root), so standard functions like
01522     // "is_top_level_node()" and "get_top_level_node()" may fail.
01523     // (Choice of root in calling function should correct this...)
01524 
01525     tdyn *top = bn;
01526     while (top->get_parent()
01527            && unique_id(top->get_parent()) > 0)
01528         top = top->get_parent();
01529 
01530     if (debug) {
01531         PRC(top); PRL(top->format_label());
01532         // put_node(cerr, *top, false);
01533     }
01534 
01535     // Copy the entire tree below top to the new tree.
01536 
01537     for_all_nodes(tdyn, top, bb) {
01538 
01539         // Find the worldline of bb.
01540 
01541         worldline *ww;
01542 
01543         if (bb == bn)
01544             ww = w;
01545         else {
01546             ww = wb->find_worldline(bb);
01547             if (!ww)
01548                 cerr << "create_interpolated_tree: error:"
01549                      << "can't find worldline of subtree member." << endl;
01550         }
01551 
01552         if (ww) {
01553 
01554             // Create and attach a new node.
01555 
01556             attach_new_node(wb, ww, root, top, bb, debug);
01557 
01558             // Update the new tree entry: copy or interpolate all
01559             // relevant quantities from bb to curr.
01560 
01561             update_node(wb, ww, t, bb, top, vel, debug);
01562         }
01563     }
01564 }
01565 
01566 int id_n_clump(unique_id_t id)                  // number of particles in id
01567 {
01568 #ifndef NEW_UNIQUE_ID_T
01569     return (int) id;
01570 #else
01571     return (id>>ID_SHIFT);                      // new new (12/01)
01572 #endif
01573 }
01574 
01575 local inline bool id_is_leaf(unique_id_t id)
01576 {
01577     return (id_n_clump(id) == 1);
01578 }
01579 
01580 #define EPS 1.e-12
01581 
01582 pdyn *create_interpolated_tree(worldbundle *wb, real t,
01583                                bool vel)                // default = false
01584 {
01585     // All leaves on the bundle list are still current, by construction.
01586     // Find the base segment corresponding to each and use it to build
01587     // a new pdyn tree interpolated to the current time.
01588 
01589     bool debug = false;
01590 
01591     // Try to take care of rounding error in t.  Management of worldbundles
01592     // should be the responsibility of the calling program.  (This would not
01593     // be an issue if timesteps were constrained to be powers of 2...)
01594 
01595     real dt = t - wb->get_t_max();
01596     if (dt > EPS)
01597         return NULL;
01598     else if (dt > 0)
01599         t = wb->get_t_max();
01600 
01601     dt = t - wb->get_t_min();
01602     if (dt < -EPS)
01603         return NULL;
01604     else if (dt < 0)
01605         t = wb->get_t_min();
01606 
01607     // Find the array of worldlines (worldbundle), and initialize
01608     // the tree_node pointers.
01609 
01610     worldlineptr *bundle = wb->get_bundle();
01611 
01612     for (int i = 0; i < wb->get_nw(); i++)
01613         bundle[i]->clear_tree_node();
01614 
01615     // Create a root node.
01616 
01617     pdyn *root = new pdyn(NULL, NULL, false);
01618 
01619     // Replace by alloc_pdyn() if we do our own memory management.
01620 
01621     root->set_system_time(t);
01622     root->set_pos(0);
01623 
01624     // Establish root as the global root node (should clean up problems
01625     // with "top_level_node" functions...).  Stored in location 0 of the
01626     // worldline array.
01627 
01628     root->set_root(root);
01629     bundle[0]->set_tree_node(root);
01630 
01631     // Loop through remaining worldlines and take action for leaves only.
01632     // Logic: we are really dealing with top-level nodes, but we don't know
01633     // which component we will encounter first.  When we find a component
01634     // of a clump of particles, we update the entire clump, and flag all
01635     // components accordingly.
01636 
01637     for (int i = 1; i < wb->get_nw(); i++) {
01638 
01639         worldline *w = bundle[i];
01640 
01641         if (!w->get_tree_node()) {
01642 
01643             // Tree entry for this node has not yet been created/updated.
01644 
01645             unique_id_t id = w->get_id();
01646 
01647 //          if (id >= 1 && id < 2) {
01648             if (id_is_leaf(id)) {
01649 
01650                 // Worldline w represents a leaf.  Locate its current segment.
01651 
01652                 if (debug) {
01653                     cerr.precision(16);
01654                     cerr << endl
01655                          << "following worldline " << i << ", id = "
01656                          << w->get_id() << endl;
01657                 }
01658 
01659                 segment *s = w->get_first_segment();
01660                 while (s && s->get_t_end() < t) s = s->get_next();
01661 
01662                 if (debug) {
01663                     PRC(w); cerr << "segment "; PRC(s);
01664                     print_events(s, t);
01665                 }
01666 
01667                 // If s is NULL, it should mean that w refers to a CM node
01668                 // that does not exist at time t.  Particle worldlines
01669                 // should be continuous -- could check in debugging mode...
01670 
01671                 if (s) add_to_interpolated_tree(wb, w, s,
01672                                                 root, t, vel, debug);
01673             }
01674         }
01675     }
01676 
01677     return root;
01678 }
01679 
01680 #else
01681 
01682 main(int argc, char *argv[])
01683 {
01684     // Fixed format on the command line:  filename  time.
01685 
01686     if (argc <= 2) exit(1);
01687 
01688     ifstream s(argv[1]);
01689     if (!s) exit(2);
01690 
01691     real t = atof(argv[2]);
01692 
01693     worldbundle *wb = read_bundle(s);
01694 
01695     pdyn *root = create_interpolated_tree(wb, t, true);
01696     put_node(cout, *root, false);
01697     rmtree(root);
01698 
01699 #if 0
01700     // Some statistics:
01701 
01702     wb->print();
01703 
01704     cerr << wb->get_nw() << " worldlines, "
01705          << count_segments(wb) << " segments, "
01706          << count_events(wb) << " events, t = "
01707          << wb->get_t_min() << " to " << wb->get_t_max()
01708          << endl;
01709 #endif
01710 
01711 #if 0
01712     // Locate a specific time along the worldline of some particle.
01713 
01714     char name[128];
01715     real t;
01716     while (1) {
01717         cerr << endl << "time, name: "; cin >> t >> name;
01718         if (cin.eof()) {
01719             cerr << endl;
01720             break;
01721         }
01722         int loc = wb->find_index(name);
01723         if (loc >= 0) {
01724             PRC(unique_id(name)); PRL(loc);
01725             worldline *w = wb->get_bundle()[loc];
01726             segment *s = w->get_first_segment();
01727             while (s && s->get_t_start() > t) s = s->get_next();
01728             print_event(w, s->get_first_event(), t);
01729         } else
01730             cerr << "not found" << endl;
01731     }
01732 #endif
01733 
01734 #if 0
01735     // Print out the entire worldline of a specified particle,
01736     // taking steps of the specified length.
01737 
01738     real dt;
01739     char name[128];
01740     while (1) {
01741 
01742         cerr << endl << "dt, name: " << flush; cin >> dt >> name;
01743         if (cin.eof()) {
01744             cerr << endl;
01745             break;
01746         }
01747 
01748         wb->print_worldline(name, dt);
01749     }
01750 #endif
01751 
01752 #if 0
01753     real t = 0.8;
01754     while (t < 0.85) {
01755         pdyn *root = create_interpolated_tree(wb, t);
01756         put_node(cout, *root, false);
01757         rmtree(root);
01758         t += 0.01;
01759     }
01760 #endif
01761 
01762 }
01763 
01764 #endif

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