Main Page   Class Hierarchy   Data Structures   File List   Data Fields   Globals  

worldline2.C

Go to the documentation of this file.
00001 
00002        //=======================================================//    _\|/_
00003       //  __  _____           ___                    ___       //      /|\ ~
00004      //  /      |      ^     |   \  |         ^     |   \     //          _\|/_
00005     //   \__    |     / \    |___/  |        / \    |___/    //            /|\ ~
00006    //       \   |    /___\   |  \   |       /___\   |   \   // _\|/_
00007   //     ___/   |   /     \  |   \  |____  /     \  |___/  //   /|\ ~
00008  //                                                       //            _\|/_
00009 //=======================================================//              /|\ ~
00010 
00015 //
00016 //----------------------------------------------------------------------
00017 //
00018 // Other externally visible functions:
00019 //
00020 //      pdyn *create_interpolated_tree2(worldbundle *wb, real t)
00021 //      char *set_center(worldbundleptr wh[], int nh,
00022 //                       int center_number, bool verbose)
00023 //      int get_center()
00024 //      char *get_center_id(int center_number)
00025 //      vector get_center_pos()
00026 //      vector get_center_vel()
00027 //
00028 //----------------------------------------------------------------------
00029 
00030 #include "worldline.h"
00031 #include "inline.h"
00032 
00033 #define NEW 1
00034 
00035 #ifndef TOOLBOX
00036 
00037 //----------------------------------------------------------------------
00038 #include "print_local.C"        // avoid repeating local print functions
00039 //----------------------------------------------------------------------
00040 
00041 // Creation of an entire interpolated tree at some specific time.
00042 
00043 //----------------------------------------------------------------------
00044 #include "print_local2.C"       // avoid repeating local print functions
00045 //----------------------------------------------------------------------
00046 
00047 //----------------------------------------------------------------------
00048 #include "attach_new_node.C"    // avoid repeating local functions
00049 //----------------------------------------------------------------------
00050 
00051 //----------------------------------------------------------------------
00052 #include "update_node.C"        // avoid repeating local functions
00053 //----------------------------------------------------------------------
00054 
00055 #if 0
00056 local void dealloc_tree(pdyn *b,
00057                         bool delete_b = true)
00058 {
00059     // This is rmtree, except that it uses our own memory management,
00060     // if present (dealloc_pdyn).
00061 
00062     pdyn* d = b->get_oldest_daughter();
00063     while (d) {
00064         pdyn* tmp = d->get_younger_sister();
00065         dealloc_tree(d);
00066         d = tmp;
00067     }
00068     if (delete_b) dealloc_pdyn(b);  // optionally leave node itself untouched
00069 }
00070 #endif
00071 
00072 local INLINE void clean_up_subtree(worldbundle *wb, pdyn *old, bool debug)
00073 {
00074     if (old) {
00075         old = old->get_top_level_node();            // should be OK, as
00076                                                     // pdyn root is defined
00077 
00078         if (debug)
00079             cerr << "cleanup below " << old->format_label() << endl;
00080 
00081         // Zero out all tree_node() pointers, since it is likely
00082         // that not all will be reset during this function call.
00083 
00084         int ndel = 0;
00085 
00086         for_all_nodes(pdyn, old, o) {
00087 
00088             if (debug)
00089                 cerr << "deleting " << o->format_label() << endl;
00090             ndel++;
00091 
00092             int wi = o->get_worldline_index();
00093 
00094             if (wi <= 0)
00095                 cerr << "clean_up_subtree: error: "
00096                      << "deleting node with no worldline index." << endl;
00097             else {
00098                 wb->get_bundle()[wi]->clear_tree_node();
00099                 wb->get_bundle()[wi]->set_t_curr(-VERY_LARGE_NUMBER);
00100             }
00101         }               
00102         
00103         detach_node_from_general_tree(*old);
00104 
00105         // Function rmtree() actually deletes the old nodes.
00106         // May not be necessary to go that far.
00107 
00108         rmtree(old);
00109 
00110         // Replace by dealloc_tree() if we do our own memory management.
00111 
00112         if (debug)
00113             cerr << "deleted " << ndel << " nodes" << endl;
00114     }
00115 }
00116 
00117 local INLINE void update_interpolated_tree(worldbundle *wb,
00118                                            worldline *w, segment *s,
00119                                            pdyn *root, real t, real t_int,
00120                                            bool vel, bool debug)
00121 {
00122     // Current worldline is w, segment is s, and w has not yet been
00123     // updated, according to t_curr.
00124 
00125     // *** By construction, on entry, w and s represent a leaf. ***
00126 
00127     // If times t and t_int lie in different segments, we must
00128     // rebuild the portion of the tree containing this particle.
00129 
00130     // Note that the "=" here are necessary.  If t_int was at the end
00131     // of the previous power-of-two segment, or at the start of the next,
00132     // we must still rebuild.
00133 
00134     // PROBLEM: This will cause an unnecessary rebuild if t_int happens
00135     // to be at the start or end of the proper segment (e.g. the start
00136     // or end of the worldbundle time range), which can slow the code
00137     // significantly.
00138     //
00139     // FIX: Save and compare the previous s rather than t_int.
00140 
00141     // bool rebuild = (t_int <= s->get_t_start() || t_int >= s->get_t_end());
00142 
00143     // Probably only need the last part of this test...
00144 
00145     bool rebuild = (t_int < s->get_t_start() || t_int > s->get_t_end()
00146                     || w->get_current_segment() != s);
00147 
00148     // Rebuild/update the current subtree.  Start by finding the base
00149     // node (containing all relevant tree information) for this particle,
00150     // and the current event.
00151 
00152     // Need to be careful with top-level tdyn nodes, as they
00153     // generally won't have parent nodes (no root), so standard
00154     // functions like is_top_level_node() and get_top_level_node()
00155     // may fail.
00156 
00157     tdyn *bn = s->get_first_event();
00158     tdyn *top = bn;
00159 
00160     while (top->get_parent()
00161            && unique_id(top->get_parent()) > 0)
00162         top = top->get_parent();
00163 
00164     if (debug) {
00165         cerr << "s = " << s << endl
00166              << "first event = " << bn << " "
00167              << bn->format_label() << " "
00168              << bn->get_time() << endl;
00169 
00170         print_details(wb, bn, t);
00171 
00172         PRC(top); PRL(top->format_label());
00173         // put_node(cerr, *top, false);
00174     }
00175 
00176     // Create the portion of the tree corresponding to the top-level
00177     // node of bn.  Note that top will probably be bn most of the time.
00178 
00179     // Copy the entire tree below top into the new tree.
00180 
00181     for_all_nodes(tdyn, top, bb) {
00182 
00183         // Find the worldline of bb.
00184 
00185         worldline *ww;
00186 
00187         if (bb == bn)
00188             ww = w;
00189         else {
00190             ww = wb->find_worldline(bb);
00191             if (!ww)
00192                 cerr << "update_interpolated_tree: error:"
00193                      << "can't find worldline of subtree member."
00194                      << endl;
00195         }
00196 
00197         if (ww) {
00198 
00199             // Create and attach a new node, if necessary.
00200 
00201             if (rebuild) {
00202 
00203                 // Delete the old subtree.  The tree_node() pointer
00204                 // still points into the old tree if not NULL, so use
00205                 // this to locate and delete the out-of-date structure.
00206                 // Note that the old "subtree" may consist of two
00207                 // separate pieces (e.g. in a binary-binary interaction).
00208 
00209                 // For efficiency, binary components are now handled
00210                 // together, rather than separately.  Attach the younger
00211                 // component of a binary too when we create the elder
00212                 // one, because update_node will expect it to exist.
00213 
00214                 if (bb == top || !bb->get_elder_sister()) {
00215 
00216                     // Function clean_up_subtree will check whether or
00217                     // not there is any work to be done.
00218 
00219                     clean_up_subtree(wb, ww->get_tree_node(), debug);
00220                     attach_new_node(wb, ww, root, top, bb, debug);
00221 
00222                     if (debug)
00223                         cerr << "attached " << bb->format_label()
00224                              << " at time " << t << endl;
00225 
00226                     if (bb != top) {
00227 
00228                         // Clean up and attach the binary sister too.
00229 
00230                         tdyn *bbsis = bb->get_younger_sister();
00231                         worldline *wwsis = wb->find_worldline(bbsis);
00232 
00233                         clean_up_subtree(wb, wwsis->get_tree_node(), debug);
00234                         attach_new_node(wb, wwsis, root, top, bbsis, debug);
00235 
00236                         if (debug)
00237                             cerr << "attached " << bbsis->format_label()
00238                                  << " at time " << t << endl;
00239                     }
00240                 }
00241             }
00242 
00243             // Update the tree entry: copy or interpolate all relevant
00244             // quantities from bb to curr.
00245 
00246             if (ww->get_tree_node())
00247                 update_node(wb, ww, t, bb, top, vel, debug);
00248             else {
00249                 cerr << "update_interpolated_tree: no tree_node"
00250                      << " for " << bb->format_label() << " at time " << t
00251                      << " t_int = " << t_int
00252                      << endl;
00253                 PRL(rebuild);
00254             }
00255         }
00256     }
00257 
00258     w->set_current_segment(s);          // note that only w has segment set;
00259                                         // other subtree members are unchanged
00260 }
00261 
00262 // For center tracking.  The position and velocity of the current
00263 // center are computed in create_interpolated_tree2.  To change the
00264 // center type, just swap in the new root pos and vels from the stories
00265 // and set jerk = 0.  The rest will be handled automatically by the
00266 // interpolation routines.
00267 
00268 static int n_center = 2;
00269 static int which_center = 0;    // 0 to n_center-1 are legal
00270 static int which_std = 0;       // 1 or 2 is legal
00271 
00272 static char *center_id[] = {"standard-center", "bound-center"};
00273 static char *std_center_id[] = {"density-center", "modified-com"};
00274 
00275 int get_n_center() {return n_center;}
00276 int get_center() {return which_center;}
00277 
00278 char *get_center_id(int center_number)          // default = -1
00279 {
00280     // Don't attempt to tie the descriptive string to the strings used
00281     // in the root dyn stories.
00282 
00283     if (center_number < 0)
00284         return get_center_id(which_center);     // print the current center
00285     else if (center_number >= n_center)
00286         return NULL;
00287     else if (center_number == 0) {
00288         if (which_std == 1)
00289             return std_center_id[0];
00290         else if (which_std == 2)
00291             return std_center_id[1];
00292         else
00293             return center_id[center_number];
00294     } else
00295         return center_id[center_number];
00296 }
00297 
00298 local bool scan_root_nodes(worldbundleptr wh[],
00299                            int nh,
00300                            bool verbose,
00301                            char *pos_id,
00302                            char *vel_id,
00303                            bool check)
00304 {
00305     for (int ih = 0; ih < nh; ih++) {
00306 
00307         worldbundle *wb = wh[ih];
00308         worldline *w = wb->get_bundle()[0];     // root worldline
00309 
00310         // Each root worldline should contain only one segment, made
00311         // up of two events, but do this more generally and check.
00312 
00313         segment *s = w->get_first_segment();
00314         int is = 0;
00315 
00316         while (s) {
00317 
00318             tdyn *b = s->get_first_event();
00319             int ie = 0;
00320 
00321             while (b) {
00322 
00323                 if (check) {
00324 
00325                     // Look for pos and vel entries in the dyn story.
00326 
00327                     if (!find_qmatch(b->get_dyn_story(), pos_id)
00328                         || !find_qmatch(b->get_dyn_story(), vel_id))
00329                         return false;
00330                 } else {
00331 
00332                     // Story entries exist.  Set the root pos and vels.
00333                     // (Actually, only pos is currently needed, but...)
00334 
00335                     b->set_pos(getvq(b->get_dyn_story(), pos_id));
00336                     b->set_vel(getvq(b->get_dyn_story(), vel_id));
00337                     b->clear_acc();
00338                     b->clear_jerk();
00339 
00340                     if (which_center != 0)
00341                         which_std = 0;
00342                     else if (which_std == 0)
00343                         which_std = getiq(b->get_dyn_story(), "center_type");
00344                 }
00345 
00346                 b = b->get_next();
00347                 ie++;
00348             }
00349 
00350             if (verbose & ie == 1)
00351                 cerr << "warning: set_next_center: segment "
00352                      << is << "is a single event" << endl;
00353 
00354             s = s->get_next();
00355             is++;
00356         }
00357 
00358         if (verbose & is != 1)
00359             cerr << "warning: set_next_center: root worldline  "
00360                 << ih << "contains more than one segment" << endl;
00361     }
00362 
00363     return true;
00364 }
00365 
00366 char *set_center(worldbundleptr wh[],   // entire worldbundle array
00367                  int nh,
00368                  int new_center,
00369                  bool verbose)          // default = false
00370 {
00371     // Set all root nodes to use the specified center, and return
00372     // a string describing that center.
00373 
00374     if (new_center < 0 || new_center >= n_center) {
00375         if (verbose)
00376             cerr << "set_next_center: invalid center number" << endl;
00377         return NULL;
00378     }
00379 
00380     int old_center = which_center;
00381     which_center = new_center;
00382 
00383     char center_pos_id[128], center_vel_id[128];
00384     if (which_center == 0) {
00385         strcpy(center_pos_id, "center_pos");    // default in read_tdyn
00386         strcpy(center_vel_id, "center_vel");
00387     } else if (which_center == 1) {
00388         strcpy(center_pos_id, "bound_center_pos");
00389         strcpy(center_vel_id, "bound_center_vel");
00390     }
00391 
00392     // Only make the change if the specified id exists in all root entries.
00393     // Scan the entire worldbundle array; also make some other basic checks.
00394 
00395     bool change = scan_root_nodes(wh, nh, verbose,
00396                                   center_pos_id, center_vel_id, true);
00397     if (change) {
00398         scan_root_nodes(wh, nh, false, center_pos_id, center_vel_id, false);
00399         if (verbose)
00400             cerr << "set_next_center: new center is "
00401                  << get_center_id(which_center) << endl;
00402     } else {
00403         if (verbose)
00404             cerr << "set_next_center: unable to change center to "
00405                  << get_center_id(which_center) << endl;
00406         which_center = old_center;
00407     }
00408 
00409     return get_center_id(which_center);
00410 }
00411 
00412 static vector center_pos = 0;
00413 vector get_center_pos() {return center_pos;}
00414 
00415 static vector center_vel = 0;
00416 vector get_center_vel() {return center_vel;}
00417 
00418 // Membership determination:
00419 
00420 bool is_member(worldbundle *wb, pdyn *p)
00421 {
00422     // A node is a member if any of its children is.
00423     // Use knowledge of t_esc to determine the precise time of escape.
00424 
00425     for_all_leaves(pdyn, p, pp) {
00426         worldline *w = wb->find_worldline(pp);
00427         if (w && w->is_member(p->get_system_time())) return true;
00428     }
00429     return false;
00430 }
00431 
00432 local void interpolate_tree(worldbundle *wb, real t, real t_int,
00433                             pdynptr& root, bool vel, bool debug)
00434 {
00435     // Compute the new tree for worldbundle wb at time t, with root
00436     // as the root node.
00437 
00438     // Find the array of worldlines (worldbundle), and initialize
00439     // the tree_node pointers.
00440 
00441     worldlineptr *bundle = wb->get_bundle();
00442 
00443     // All leaves on the bundle list are still current, by construction.
00444     // Find the base segment corresponding to each and use it to update
00445     // the pdyn tree interpolated to the current time.
00446 
00447     // Create a root node, if necessary.
00448 
00449     if (!root) {
00450         root = new pdyn(NULL, NULL, false);
00451         // if (!root) root = alloc_pdyn(NULL, NULL, false, true, debug);
00452         root->set_name("root");
00453         root->set_worldline_index(wb->find_index(root));
00454     }
00455 
00456     root->set_system_time(t);
00457 
00458     root->set_pos(0);                   // unnecessary, but not wrong...
00459     root->set_vel(0);
00460 
00461     // Establish root as the global root node (should clean up problems
00462     // with "top_level_node" functions...).  Stored in location 0 of the
00463     // worldline array.
00464 
00465     root->set_root(root);
00466     bundle[0]->set_tree_node(root);
00467 
00468     // bundle[0]->set_t_curr(t);        // will be set in the loop below
00469 
00470     // Loop through remaining worldlines and take action for leaves only.
00471     // Logic: we are really dealing with top-level nodes, but we don't know
00472     // which component we will encounter first.  When we find a component
00473     // of a clump of particles, we update the entire clump, and flag all
00474     // components accordingly.
00475 
00476     // Handle the interpolation of the root node here too...
00477     // Root acc and jerk have been set up on input, so just interpolate
00478     // them as worldline 0 in the following loop.
00479 
00480     for (int i = 0; i < wb->get_nw(); i++) {
00481 
00482         worldline *w = bundle[i];
00483 
00484         if (w->get_t_curr() != t) {
00485 
00486             // Worldline needs to be updated.
00487 
00488             unique_id_t id = w->get_id();
00489 
00490             if (i == 0 || id_n_clump(id) == 1) {
00491 
00492                 // Worldline w represents a leaf.  Locate its current segment.
00493 
00494                 if (debug) {
00495                     cerr.precision(16);
00496                     cerr << endl
00497                          << "updating worldline " << i << ", id = "
00498                          << w->get_id() << endl;
00499                 }
00500 
00501                 // If possible, start at the previous segment visited in
00502                 // this worldline (may speed things up in normal use).
00503                 // -- hard to see much improvememt in speed...
00504 
00505                 segment *s;
00506 #if 1
00507                 s = w->get_current_segment();
00508                 if (!s || s->get_t_start() > t)
00509 #endif
00510                     s = w->get_first_segment();
00511 
00512                 while (s && s->get_t_end() < t) s = s->get_next();
00513 
00514                 if (debug) {
00515                     PRC(w); cerr << "segment "; PRC(s);
00516                     print_events(s, t);
00517                 }
00518 
00519                 // If s is NULL, it should mean that w refers to a CM node
00520                 // that does not exist at time t.  Particle worldlines
00521                 // should be continuous -- check in debugging mode...
00522 
00523                 if (s) {
00524                     if (i == 0) {
00525 
00526                         // Root node.
00527 
00528                         tdyn *b = s->get_first_event();
00529                         update_node(wb, w, t, b, b, vel, debug);
00530 
00531                         center_pos = root->get_pos();
00532                         center_vel = root->get_vel();
00533 
00534                         // PRC(b->get_pos());
00535                         // PRL(center_pos);
00536 
00537                     } else
00538 
00539                         // Update entire clump of nodes, if necessary.
00540 
00541                         update_interpolated_tree(wb, w, s,
00542                                                  root, t, t_int,
00543                                                  vel, debug);
00544                 } else if (debug)
00545                     cerr << "NULL segment for leaf..." << endl;
00546             }
00547         }
00548     }
00549 }
00550 
00551 #define EPS  1.e-12
00552 #define EPS1 1.e-12                             // kludge -- should be 0
00553 
00554 local bool trim(worldbundle *wb, real& t)
00555 {
00556     // Try to take care of rounding error in t.  Management of worldbundles
00557     // should be the responsibility of the calling program.  (This would not
00558     // be an issue if timesteps were constrained to be powers of 2...)
00559 
00560     // TEMPORARY BUG WORKAROUND: don't allow t to be exactly t_min or t_max!!!
00561 
00562     real dt = t - wb->get_t_max();
00563     if (dt > EPS)
00564         return false;
00565     else if (dt > -EPS1)
00566         t = wb->get_t_max() - EPS1;
00567 
00568     dt = t - wb->get_t_min();
00569     if (dt < -EPS)
00570         return false;
00571     else if (dt < EPS1)
00572         t = wb->get_t_min() + EPS1;
00573 
00574     return true;
00575 }
00576 
00577 pdyn *create_interpolated_tree2(worldbundle *wb, real t,
00578                                 bool vel)               // default = false
00579 {
00580     static worldbundle *wb_last = NULL;         // last worldbundle handled
00581     static real t_int = -VERY_LARGE_NUMBER;     // last interpolation time
00582 
00583     static pdyn *root = NULL;                   // root node of the
00584                                                 // interpolated tree
00585 
00586     if (!wb_last) set_kepler_fast_flag();       // use the "fast" kepler solver
00587 
00588     // Try to take care of rounding error in t.
00589 
00590     if (!trim(wb, t)) return NULL;
00591 
00592     if (wb != wb_last) {
00593         if (wb->get_pdyn_root()) {
00594             root = wb->get_pdyn_root();         // restore an existing tree
00595             t_int = wb->get_t_int();
00596         } else {
00597             root = NULL;                        // build a new tree
00598             t_int = -VERY_LARGE_NUMBER;
00599         }
00600     }
00601 
00602     if (t == t_int && root) return root;
00603 
00604     // We no longer create the tree from scratch each time.  Rather,
00605     // we modify all or part of an existing tree (starting at root)
00606     // if possible.
00607 
00608     // All leaves on the bundle list are still current, by construction.
00609     // Find the base segment corresponding to each and use it to update
00610     // the pdyn tree interpolated to the current time.
00611 
00612     bool debug = false;
00613 
00614     // Build the new tree.
00615 
00616     interpolate_tree(wb, t, t_int, root, vel, debug);
00617 
00618     wb->set_t_int(t);
00619     if (wb != wb_last) wb->set_pdyn_root(root);
00620 
00621     wb_last = wb;
00622     t_int = t;
00623 
00624     return root;
00625 }
00626 
00627 void preload_pdyn(worldbundleptr wh[], int nh,
00628                   bool verbose)                 // default = false
00629 {
00630     for (int i = 0; i < nh; i++) {
00631         create_interpolated_tree2(wh[i], wh[i]->get_t_min());
00632         if (verbose)
00633             cerr << "allocated memory for worldbundle " << i
00634                  << ",  t_min = " << wh[i]->get_t_min() << endl;
00635     }
00636 }
00637 
00638 #else
00639 
00640 main(int argc, char *argv[])
00641 {
00642     // Fixed format on the command line:  filename  time.
00643 
00644     if (argc <= 2) exit(1);
00645 
00646     ifstream s(argv[1]);
00647     if (!s) exit(2);
00648 
00649     real t = atof(argv[2]);
00650 
00651     worldbundle *wb = read_bundle(s);
00652 
00653     pdyn *root = create_interpolated_tree2(wb, t, true);
00654     put_node(cout, *root, false);
00655 
00656 #if 0
00657     // Some statistics:
00658 
00659     wb->print();
00660 
00661     cerr << wb->get_nw() << " worldlines, "
00662          << count_segments(wb) << " segments, "
00663          << count_events(wb) << " events, t = "
00664          << wb->get_t_min() << " to " << wb->get_t_max()
00665          << endl;
00666 #endif
00667 
00668 #if 0
00669     // Locate a specific time along the worldline of some particle.
00670 
00671     char name[128];
00672     real t;
00673     while (1) {
00674         cerr << endl << "time, name: "; cin >> t >> name;
00675         if (cin.eof()) {
00676             cerr << endl;
00677             break;
00678         }
00679         int loc = wb->find_index(name);
00680         if (loc >= 0) {
00681             PRC(unique_id(name)); PRL(loc);
00682             worldline *w = wb->get_bundle()[loc];
00683             segment *s = w->get_first_segment();
00684             while (s && s->get_t_start() > t) s = s->get_next();
00685             print_event(w, s->get_first_event(), t);
00686         } else
00687             cerr << "not found" << endl;
00688     }
00689 #endif
00690 
00691 #if 0
00692     // Print out the entire worldline of a specified particle,
00693     // taking steps of the specified length.
00694 
00695     real dt;
00696     char name[128];
00697     while (1) {
00698 
00699         cerr << endl << "dt, name: " << flush; cin >> dt >> name;
00700         if (cin.eof()) {
00701             cerr << endl;
00702             break;
00703         }
00704 
00705         wb->print_worldline(name, dt);
00706     }
00707 #endif
00708 
00709 #if 0
00710     real t = 0.8;
00711     while (t < 0.85) {
00712         pdyn *root = create_interpolated_tree2(wb, t);
00713         put_node(cout, *root, false);
00714         t += 0.01;
00715     }
00716 #endif
00717 
00718 }
00719 
00720 #endif

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