Main Page   Class Hierarchy   Data Structures   File List   Data Fields   Globals  

perturbed_list.C

Go to the documentation of this file.
00001 
00002        //=======================================================//    _\|/_
00003       //  __  _____           ___                    ___       //      /|\ ~
00004      //  /      |      ^     |   \  |         ^     |   \     //          _\|/_
00005     //   \__    |     / \    |___/  |        / \    |___/    //            /|\ ~
00006    //       \   |    /___\   |  \   |       /___\   |   \   // _\|/_
00007   //     ___/   |   /     \  |   \  |____  /     \  |___/  //   /|\ ~
00008  //                                                       //            _\|/_
00009 //=======================================================//              /|\ ~
00010 
00011 // Functions for maintaining the list of (top-level) perturbed binaries.
00012 // "Maintenance" calls come from kira.C, kira_stellar.C, and kira_escape.C.
00013 // Major use of the list is in hdyn_ev.C (correct_acc_and_jerk)
00014 //
00015 //                                              Steve McMillan, 3/99
00016 //
00017 // Externally visible functions:
00018 //
00019 //      bool hdyn::is_perturbed_cpt
00020 //      bool hdyn::is_perturbed_cm
00021 //      void hdyn::reconstruct_perturbed_list
00022 //      void hdyn::dump_perturbed_list
00023 //      int  hdyn::get_index_on_perturbed_list
00024 //      bool hdyn::on_perturbed_list
00025 //      void hdyn::check_perturbed_list
00026 //      void hdyn::add_to_perturbed_list
00027 //      void hdyn::remove_from_perturbed_list
00028 
00029 #include "hdyn.h"
00030 
00031 // Define "perturbed", for use everywhere perturbed_list is used.
00032 
00033 bool hdyn::is_perturbed_cpt()
00034 {
00035     return (!get_kepler() || !fully_unperturbed);
00036 }
00037 
00038 bool hdyn::is_perturbed_cm()
00039 {
00040     return (is_parent() && get_oldest_daughter()->is_perturbed_cpt());
00041 }
00042 
00043 // Initial asumption was that, in use, the list would be checked
00044 // frequently, but updated relatively rarely.  Thus, we expected to
00045 // use an ordered list for convenience of searching, even though that
00046 // means updates may be significantly more expensive -- monitor this!
00047 
00048 // In fact, the only current use of these functions is to check entire
00049 // list in correct_acc_and_jerk.  In this case, individual access time
00050 // is unimportant, since we never do it, so we should perhaps optimize
00051 // the list maintenance cost (Steve, 8/00).
00052 
00053 //#define FAST_ACCESS true      // faster individual access, slower maintenance
00054 #define FAST_ACCESS false
00055 
00056 // Note from Steve (8/00):  Using the FAST_ACCESS code requires that the
00057 // list be sorted.  Currently, we sort by address.  However, this means
00058 // that the details of the perturber correction depend on where nodes lie
00059 // in memory, making the results in general non-reproducible.  Differences
00060 // crop up typically in the last bit because the order in which corrections
00061 // are applied can vary from run to run.
00062 //
00063 // **** For this and the above reason, FAST_ACCESS is presently turned off.
00064 // **** If it is restored, we must find another quantity to use for sorting
00065 // **** purposes -- perhaps define a unique index for all nodes?
00066 
00067 local int compare_ptr(const void * pi, const void * pj)
00068 {
00069     hdynptr bi = *((hdynptr*)pi);
00070     hdynptr bj = *((hdynptr*)pj);
00071 
00072     if (bi > bj)
00073         return +1;
00074     else if (bi < bj)
00075         return -1;
00076     else
00077         return 0;
00078 }
00079 
00080 void hdyn::reconstruct_perturbed_list()
00081 {
00082     if (!options->use_perturbed_list) return;
00083 
00084     if (perturbed_list) delete [] perturbed_list;
00085 
00086     perturbed_list = new hdynptr[get_root()->n_leaves()];
00087     n_perturbed = 0;
00088 
00089     for_all_daughters(hdyn, get_root(), bi)
00090         if (bi->is_perturbed_cm()) {
00091 
00092             perturbed_list[n_perturbed++] = bi;
00093 
00094             //cerr << "Added node " << bi << " " << bi->format_label()
00095             //     << " as perturbed_list[" << n_perturbed-1
00096             //     << "] at time " << bi->get_system_time()
00097             //     << endl;
00098 
00099         }
00100 
00101     if (FAST_ACCESS) {
00102 
00103         // Sort the list -- O(N log N) ops.
00104 
00105         qsort(perturbed_list, n_perturbed, sizeof(hdynptr), compare_ptr);
00106     }
00107 
00108     cerr << endl
00109          << "Rebuilt perturbed_list; n_perturbed = " << n_perturbed
00110          << endl;
00111 }
00112 
00113 void hdyn::dump_perturbed_list()
00114 {
00115     if (n_perturbed <= 0) return;
00116 
00117     cerr << "Perturbed_list (n_perturbed = " << n_perturbed << "):"
00118          << endl;
00119 
00120     for (int i = 0; i < n_perturbed; i++)
00121         cerr << "    " << i << "  " << perturbed_list[i]
00122              << " " << perturbed_list[i]->format_label() << endl;
00123 }
00124 
00125 int hdyn::get_index_on_perturbed_list(bool debug) // default = false
00126 {
00127     // If 'this' is not on the list, but is within the range defined
00128     // by the list, return the element immediately *below* it.  If this
00129     // is below the bottom of the list, return -1; if this is above the
00130     // top element, return n_perturbed.
00131     //
00132     // Note from Steve, 8/00:  The dual nature of the return from this
00133     // function is never used, as we always test for < 0 and >= n_perturbed
00134     // in the calling function.  Thus, the convention used here is not wrong,
00135     // but it is redundant and slightly inefficient...
00136 
00137     if (!FAST_ACCESS) {
00138 
00139         // Simplest O(N) version:
00140 
00141         bool below = true;
00142         for (int i = 0; i < n_perturbed; i++) {
00143             if (perturbed_list[i] == this)
00144                 return i;
00145             else if (below && perturbed_list[i] > this)
00146                 below = false;
00147         }
00148 
00149         if (below)
00150             return -1;
00151         else                            // redundant -- return value of -1
00152             return n_perturbed;         // in all out of range cases is OK
00153 
00154     } else {
00155 
00156         // Assume the list is ordered and do an O(log N) binary search.
00157 
00158         if (debug)
00159             cerr << "In get_index_on_perturbed_list for " << format_label()
00160                  << " at time " << system_time << endl;
00161 
00162         if (this < perturbed_list[0])
00163             return -1;
00164         else if (this > perturbed_list[n_perturbed-1])
00165             return n_perturbed;
00166 
00167         int ilow = 0, ihigh = n_perturbed - 1;
00168 
00169         while (ilow < ihigh) {
00170 
00171             int imid = (ilow + ihigh)/2;
00172 
00173             // Logic can probably be improved...
00174 
00175             if (imid == ilow) {
00176                 if (perturbed_list[ihigh] == this)
00177                     return ihigh;
00178                 else
00179                     return ilow;
00180             }
00181 
00182             if (perturbed_list[imid] == this)
00183                 return imid;
00184             else if (perturbed_list[imid] < this)
00185                 ilow = imid;
00186             else
00187                 ihigh = imid;
00188 
00189             if (debug) {
00190                 PRC(this), PRC(ilow), PRL(ihigh);
00191                 PRC(perturbed_list[ilow]), PRL(perturbed_list[ihigh]);
00192             }
00193         }
00194 
00195         return ilow;                    // redundant
00196     }
00197 }
00198 
00199 bool hdyn::on_perturbed_list()
00200 {
00201     int i = get_index_on_perturbed_list();
00202     return (i >= 0 && i < n_perturbed && perturbed_list[i] == this);
00203 }
00204 
00205 void hdyn::check_perturbed_list()
00206 {
00207     // Note: checking and reconstruction are O(N log N) operations
00208     //       if FAST_ACCESS is true; otherwise checking is O(N^2),
00209     //       reconstruction is O(N).
00210 
00211     if (!perturbed_list) {
00212 
00213         cerr << endl
00214              << "check_perturbed_list:  perturbed_list = NULL!"
00215              << endl;
00216 
00217     } else {
00218 
00219         int i;
00220         bool reconstruct_list = false;
00221 
00222         // Check that all perturbed top-level binaries are on the list.
00223 
00224         for_all_daughters(hdyn, get_root(), bi)
00225             if (bi->is_perturbed_cm()) {
00226                 if ((i = bi->get_index_on_perturbed_list()) < 0
00227                     || i >= n_perturbed
00228                     || perturbed_list[i] != bi) {
00229                     cerr << "check_perturbed_list:  " << bi->format_label()
00230                          << " not on perturbed_list" << endl;
00231                     reconstruct_list = true;
00232                 }
00233             }
00234 
00235         // Check that all list entries are perturbed top-level binaries.
00236 
00237         for (i = 0; i < n_perturbed; i++) {
00238             if (!perturbed_list[i]->is_perturbed_cm()) {
00239                 cerr << "check_perturbed_list:  entry " << i
00240                      << " " << perturbed_list[i]->format_label()
00241                      << " is not perturbed" << endl;
00242                  reconstruct_list = true;
00243              }
00244         }
00245 
00246         // Check that the list is properly ordered.
00247 
00248         for (i = 0; i < n_perturbed-1; i++) {
00249              if (perturbed_list[i] >= perturbed_list[i+1]) {
00250                  cerr << "perturbed_list corrupted at i = " << i << endl;
00251                  reconstruct_list = true;
00252              }
00253         }
00254 
00255         // Fix any problems.
00256 
00257         if (reconstruct_list) {
00258             dump_perturbed_list();
00259             reconstruct_perturbed_list();
00260         }
00261     }
00262 }
00263 
00264 void hdyn::add_to_perturbed_list(int id) // default = 0
00265 {
00266     if (!options->use_perturbed_list) return;
00267 
00268     if (!perturbed_list) {
00269         perturbed_list = new hdynptr[get_root()->n_leaves()];
00270         n_perturbed = 0;
00271     }
00272 
00273     // This is an O(N) operation if we have to place a node in the middle
00274     // of the list.  Adding to the end is O(1), but the test for membership
00275     // is O(N) instead of O(log N) in the case FAST_ACCESS = false, so there
00276     // isn't really much advantage...
00277 
00278     int i = get_index_on_perturbed_list();
00279 
00280     if (i >= 0 && i < n_perturbed && perturbed_list[i] == this) {
00281 
00282         cerr << "***** warning: add_to_perturbed_list: node "
00283              << this << " " << format_label() << " already on list"
00284              << endl;
00285 
00286         check_perturbed_list();
00287 
00288     } else {
00289 
00290         if (FAST_ACCESS) {
00291 
00292             // Redefine i to be the insertion point for 'this'.  Note
00293             // the convention that, if 'this' lies above the range of the
00294             // present list, i = n_perturbed.
00295 
00296             if (i < n_perturbed) i++;
00297 
00298             // Make room for the new node.
00299 
00300             for (int j = n_perturbed; j > i; j--)
00301                 perturbed_list[j] = perturbed_list[j-1];
00302 
00303         } else
00304 
00305             i = n_perturbed;
00306 
00307         perturbed_list[i] = this;
00308         n_perturbed++;
00309 
00310         if (diag->report_adjust_perturbed_list) {
00311 
00312             cerr << "added node " << this << " " << format_label()
00313                  << " to perturbed_list at time " << system_time
00314                  << endl
00315                  << "    index = " << i
00316                  << "  n_perturbed = " << n_perturbed;
00317 
00318             if (id > 0) cerr << " (ID = " << id << ")";
00319 
00320             cerr << endl;
00321         }
00322     }
00323 }
00324 
00325 void hdyn::remove_from_perturbed_list(int id) // default = 0
00326 {
00327     if (!options->use_perturbed_list) return;
00328 
00329     // Same O(N) method, regardless of FAST_ACCESS.
00330 
00331     for_all_nodes(node, get_root(), bb)
00332         if(bb!=bb->get_starbase()->get_node()) {
00333             PRC(bb->format_label());
00334             PRC(bb);PRL(bb->get_starbase()->get_node());
00335         }
00336 
00337     if (!perturbed_list || n_perturbed <= 0) return;
00338 
00339     int i = get_index_on_perturbed_list();
00340 
00341     if (i < 0 || i >= n_perturbed || perturbed_list[i] != this) {
00342 
00343         cerr << "***** warning: remove_from_perturbed_list: node "
00344              << this << " " << format_label() << " not on list"
00345              << endl;
00346 
00347         check_perturbed_list();
00348 
00349     } else {
00350 
00351         // Remove 'this' and contract the list.
00352 
00353         for (int j = i; j < n_perturbed-1; j++)
00354             perturbed_list[j] = perturbed_list[j+1];
00355 
00356         n_perturbed--;
00357 
00358         if (diag->report_adjust_perturbed_list) {
00359 
00360             cerr << "removed node " << this << " " << format_label()
00361                  << " from perturbed_list at time " << system_time
00362                  << endl
00363                  << "    index = " << i
00364                  << "  n_perturbed = " << n_perturbed;
00365 
00366             if (id > 0) cerr << " (ID = " << id << ")";
00367 
00368             cerr << endl;
00369         }
00370     }
00371 
00372     for_all_nodes(node, get_root(), bb)
00373         if(bb!=bb->get_starbase()->get_node()) {
00374             PRC(bb->format_label());
00375             PRC(bb);PRL(bb->get_starbase()->get_node());
00376         }
00377 }

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