Main Page   Class Hierarchy   Data Structures   File List   Data Fields   Globals  

tree_io.C

Go to the documentation of this file.
00001 
00002 // tree_io.C
00003 //
00004 //      The most important (pipeable) output routines have been
00005 //      modified to work on HP/HPUX-8.x -- S. McMillan, 3/3/93
00006 //
00007 //      Modified to read/write compressed snapshots (cout only),
00008 //      under control of environment variable STARLAB_ZIP.
00009 //                              -- S. McMillan, X. Zhuge, 6/22/98
00010 //      Minor leak fix          -- PJT , 11/24/98
00011 
00012 #include "starlab_vector.h"
00013 #include "util_io.h"
00014 #include "story.h"
00015 #include "node.h"
00016 
00017 void  node::log_comment(char * comment)
00018 {
00019     if (log_story)
00020         add_story_line(log_story, comment);
00021 }
00022 
00023 void  node::log_history(int argc, char ** argv) 
00024 {
00025     if (log_story) {
00026         char *hist = gethist(argc, argv);
00027         add_story_line(log_story, hist);
00028         delete hist;
00029     }
00030 }
00031 
00032 ostream& node::print_log_story(ostream& s)
00033 {
00034     story * the_log_story = node::get_log_story();
00035     if (the_log_story)
00036         put_story(s, *the_log_story);
00037     return s;
00038 }
00039 
00040 ostream& node::print_hydro_story(ostream& s)
00041 {
00042     if (hbase)
00043         hbase->print_hydro_story(s);
00044     return s;
00045 }
00046 
00047 ostream& node::print_star_story(ostream& s,
00048                                 int short_output)       // default = 0
00049 {
00050     if (sbase)
00051         sbase->print_star_story(s, short_output);
00052     return s;
00053 }
00054 
00055 istream & node::scan_log_story(istream& s, char * line)
00056 {
00057     node::set_log_story(get_story(s, line));
00058     return s;
00059 }
00060 
00061 istream & node::scan_hydro_story(istream& s)
00062 {
00063     if (hbase)
00064         hbase->scan_hydro_story(s);
00065     else {
00066 
00067         // No hydrobase is defined, but we have already read the
00068         // START_HYDRO string.  Must keep reading the input stream
00069         // until the matching END_HYDRO is found.
00070 
00071         char input_line[MAX_INPUT_LINE_LENGTH];
00072         while(get_line(s,input_line), !matchbracket(END_HYDRO, input_line))
00073             ;
00074     }
00075     return s;
00076 }
00077 
00078 istream & node::scan_star_story(istream& s, int level)
00079 {
00080     if (sbase)
00081         sbase->scan_star_story(s, level);
00082     else {
00083 
00084         // (See hydrobase note above.)
00085 
00086         char input_line[MAX_INPUT_LINE_LENGTH];
00087         while (get_line(s,input_line), !matchbracket(END_STAR, input_line));
00088     }
00089     return s;
00090 }
00091 
00092 #include <string.h>
00093 #define BUF_SIZE 1024
00094 
00095 static char format_string[BUF_SIZE];
00096 
00097 // Note added by Steve 7/6/98.  Do NOT use format_label() to print out
00098 // labels of more than one particle in the same print statement if the
00099 // particles are identified by index rather than by label.  Because we
00100 // use a single string here, only one format can be stored at any
00101 // time.  Therefore, since all calls to format_label() will be executed
00102 // before the string is sent to the output stream, a statement of the
00103 // form
00104 //
00105 //      cerr << bi->format_label() << bj->format_label() << endl;
00106 //
00107 // will actually print out the label of bj twice!
00108 //
00109 // Better to use print_label() instead in those circumstances.
00110 
00111 char* node::format_label()
00112 {
00113     if (is_valid()) {
00114 
00115         // Precedence:  print name string if defined
00116         //              otherwise, print index if non-negative
00117         //              otherwise, print '?'
00118 
00119         if (name != NULL) {
00120             strncpy(format_string, name, BUF_SIZE-1);
00121             format_string[BUF_SIZE-1] = '\0';
00122         } else if(index >= 0) {
00123             sprintf(format_string, "%d", index);        // SLWM removed leading
00124                                                         // "#", July 1998
00125         } else {
00126             sprintf(format_string, "?");
00127         }
00128     } else
00129         sprintf(format_string, "(invalid)");
00130         
00131     return format_string;
00132 }
00133 
00134 bool node_contains(node * b, int i)             // overloaded
00135 {
00136     if (b->is_parent()) {
00137         for_all_nodes(node, b, bi)
00138             if (bi->get_index() == i)
00139                 return true;
00140     } else
00141         if (b->get_index() == i)
00142             return true;
00143 
00144     return false;
00145 }
00146 
00147 bool node_contains(node * b, char* s)           // overloaded
00148 {
00149     if (b->is_parent()) {
00150         for_all_nodes(node, b, bi)
00151             if (bi->name_is(s))
00152                 return true;
00153     } else
00154         if (b->name_is(s))
00155             return true;
00156 
00157     return false;
00158 }
00159 
00160 bool clump_contains(node * b, int i)            // overloaded
00161 {
00162     return node_contains(b->get_top_level_node(), i);
00163 }
00164 
00165 bool clump_contains(node * b, char *s)          // overloaded
00166 {
00167     return node_contains(b->get_top_level_node(), s);
00168 }
00169 
00170 bool node::name_is(char* s)
00171 {
00172     return streq(format_label(), s);
00173 }
00174 
00175 void node::print_label(ostream & s)
00176 {
00177     s << format_label();
00178 }
00179 
00180 void node::pretty_print_node(ostream & s)
00181 {
00182     print_label(s);
00183 }
00184 
00185 void node::pretty_print_tree(int depth_level, ostream & s)
00186 {
00187     int  k = depth_level;
00188     while (k--)
00189         s << "  ";
00190     pretty_print_node(s);
00191     if (mass != 1)
00192         s << "        m = " << mass;
00193     s << endl;
00194     if (is_parent())
00195         for_all_daughters(node, this, d)
00196             d->pretty_print_tree(depth_level + 1, s);
00197 }
00198 
00199 void node::pretty_print_tree(ostream & s)
00200 {
00201     pretty_print_tree(0, s);
00202 }
00203 
00204 void pp(node * b, ostream & s)
00205 {
00206     s << "(";
00207     b->pretty_print_node(s);
00208     for_all_daughters(node, b, daughter)
00209         pp(daughter, s);        
00210     s << ")";
00211 }
00212 
00213 void pp2(node * b, ostream & s,  int level)
00214 {
00215     for (int i = 0; i<level*2; i++) {s << " ";}
00216     b->pretty_print_node(s);
00217     s << "\n";
00218     for_all_daughters(node, b, daughter)
00219         pp2(daughter, s, level + 1);    
00220 }
00221 
00222 local node * get_node_recursive(istream& s,
00223                                 npfp the_npfp,
00224                                 hbpfp the_hbpfp,
00225                                 sbpfp the_sbpfp,
00226                                 bool use_stories,
00227                                 int level)
00228 {
00229     node * b = (*the_npfp)(the_hbpfp, the_sbpfp, use_stories);
00230     char line[MAX_INPUT_LINE_LENGTH];
00231 
00232     get_line(s, line);
00233 
00234     node * elder_sister = (node *)42;   // to make some compilers happy
00235 
00236     // Would be highly desirable to have the code ignore unexpected data
00237     // when seeking e.g. a START_PARTICLE line.  Currently, the input is
00238     // very intolerant of even extra whitespace in the input stream.
00239     //
00240     // However, the logic below makes this a little tricky... (Steve, 6/01)
00241 
00242     while (!matchbracket(END_PARTICLE, line)) {
00243         if (matchbracket(START_DYNAMICS, line)) {
00244             b->scan_dyn_story(s);                       // virtual
00245         } else if (matchbracket(START_HYDRO, line)) {
00246             b->scan_hydro_story(s);
00247         } else if (matchbracket(START_STAR, line)) {
00248             b->scan_star_story(s, level);               // virtual (for tdyn)
00249         } else if (matchbracket(START_LOG, line)) {
00250 
00251                 // bug: every node gets a log story, but when you see
00252                 // one from input, you set this to be the new one
00253                 // and thus never dealloc the old one ???
00254 
00255             b->scan_log_story(s, line);
00256 
00257         } else if (matchbracket(START_PARTICLE, line)) {
00258             node * daughter =
00259                 get_node_recursive(s, the_npfp, the_hbpfp, the_sbpfp,
00260                                    use_stories, level+1);
00261             if (b->get_oldest_daughter() == NULL) {
00262                 b->set_oldest_daughter(daughter);
00263             } else {
00264                 daughter->set_elder_sister(elder_sister);
00265                 elder_sister->set_younger_sister(daughter);
00266             }
00267             daughter->set_parent(b);
00268             elder_sister = daughter;
00269         } else {
00270             char keyword[MAX_INPUT_LINE_LENGTH];
00271             const char *val = getequals(line, keyword);
00272             if (!strcmp("i",keyword)) {
00273                 int index = strtol(val, NULL, 10);
00274                 b->set_label(index);
00275             } else if (!strcmp("name",keyword)) {
00276                 char cptr[MAX_INPUT_LINE_LENGTH];
00277                 sscanf(val,"%s",cptr);
00278                 b->set_label(cptr);
00279             } else if (!strcmp("N",keyword)) {   // N is not read in here;
00280                 ;                                // instead N is recomputed
00281             }                                    // at output time.
00282             else {
00283                 cerr << line <<" unexpected\n";
00284                 exit(1);
00285             }
00286         }
00287         get_line(s, line);
00288     }
00289     return b;
00290 }
00291 
00292 local node * get_node_init(istream& s,
00293                            npfp the_npfp,
00294                            hbpfp the_hbpfp,
00295                            sbpfp the_sbpfp,
00296                            bool use_stories)
00297 {
00298 
00299     if (!check_and_skip_input_line(s, START_PARTICLE)) {
00300         return NULL;
00301     }
00302     node* root = get_node_recursive(s, the_npfp, the_hbpfp, the_sbpfp,
00303                                     use_stories, 0);
00304     root->set_root(root);
00305     return root;
00306 }
00307 
00308 static bool first_log = true;
00309 
00310 inline local void put_node_body(ostream & s, node & b,
00311                                 bool print_xreal = true,
00312                                 int short_output = 0)
00313 {
00314     // Now have one "short" option that basically is full output,
00315     // for restart purposes.  Check for it explicitly.
00316 
00317     bool short_short = (short_output && short_output != 4);
00318 
00319     if (short_short)
00320         put_string(s, "  name = ", b.format_label());
00321     else {
00322         if (b.get_index() >= 0) put_integer(s, "  i = ", b.get_index());
00323         if (b.get_name() != NULL) put_string(s, "  name = ", b.get_name());
00324         put_integer(s, "  N = ", b.n_leaves());
00325     }
00326 
00327     if (!short_short || (b.is_root() && first_log)) {
00328         b.print_log_story(s);
00329         first_log = false;
00330     }
00331 
00332     // ------------------------------------------------------------
00333     // *** Changed the way output is done (Steve, 5/01) ***
00334     //
00335     // Virtual print_dyn_story() functions now just print out
00336     // "known" quantities in the form
00337     //
00338     //          keyword = value
00339     //
00340     // and each uses its base class function to avoid repetition.
00341     // We add enclosing "parens" and any additional story output HERE.
00342 
00343     put_story_header(s, DYNAMICS_ID);                   // new
00344 
00345     b.print_dyn_story(s, print_xreal, short_output);
00346 
00347     if (!short_short && b.get_dyn_story())
00348         put_story_contents(s, *b.get_dyn_story());      // new
00349 
00350     put_story_footer(s, DYNAMICS_ID);                   // new
00351 
00352     // ------------------------------------------------------------
00353 
00354     // For now, all short output is handled as part of Dyn.
00355 
00356    if (!short_short) {
00357        b.print_hydro_story(s);
00358        b.print_star_story(s, short_output);
00359    }
00360 }
00361 
00362 inline local void put_node_recursive(ostream & s, node & b,
00363                                      bool print_xreal = true,
00364                                      int short_output = 0)
00365 {
00366     put_story_header(s, PARTICLE_ID);
00367 
00368     put_node_body(s, b, print_xreal, short_output);
00369 
00370     for(node * daughter = b.get_oldest_daughter();
00371         daughter != NULL;
00372         daughter = daughter->get_younger_sister()){
00373         put_node_recursive(s, *daughter, print_xreal, short_output);
00374     }
00375 
00376     put_story_footer(s, PARTICLE_ID);
00377 }
00378 
00379 void put_single_node(ostream & s, node & b,
00380                      bool print_xreal,          // default = true
00381                      int short_output)          // default = 0
00382 {
00383     // Same as put_node, but without recursion.
00384 
00385     put_story_header(s, PARTICLE_ID);
00386     put_node_body(s, b, print_xreal, short_output);
00387     put_story_footer(s, PARTICLE_ID);
00388 }
00389 
00390 #ifdef HAS_GZIP
00391 #include <pfstream.h>   // (May not exist on all systems...)
00392 #endif
00393 
00394 node * get_node(istream& s, npfp the_npfp, hbpfp the_hbpfp, sbpfp the_sbpfp,
00395                 bool use_stories)
00396 {
00397     // If STARLAB_USE_GZIP is defined, the input will be decompressed
00398     // by gzip first.  This is accomplished by redefining the stream s.
00399 
00400     // Note that, for compression to be carried out, we must (1) compile
00401     // HAS_GZIP set, then (2) run with STARLAB_USE_GZIP defined.
00402 
00403 #ifdef HAS_GZIP
00404     if (char * zip = getenv("STARLAB_USE_GZIP")) {
00405         ipfstream sz("|gzip -d -f");
00406         if (sz) {
00407             return get_node_init(sz, the_npfp, the_hbpfp, the_sbpfp,
00408                                  use_stories);
00409         }
00410     }
00411 #endif
00412 
00413     return get_node_init(s, the_npfp, the_hbpfp, the_sbpfp, use_stories);
00414 }
00415 
00416 // put_node: the function that does all the work of outputting nodes
00417 //           of all sorts...
00418 
00419 void put_node(ostream & s, node & b,
00420               bool print_xreal,         // default = true
00421               int short_output)         // default = 0
00422 {
00423     // If STARLAB_USE_GZIP is set, everything written to cout will be
00424     // compressed by gzip.
00425 
00426 #ifdef HAS_GZIP
00427     if (&s == (ostream *) &cout) {
00428         if (char * zip = getenv("STARLAB_USE_GZIP")) {
00429             opfstream sz("|gzip -c -f");
00430             if (sz) {
00431                 put_node_recursive(sz, b, print_xreal, short_output);
00432                 return;
00433             }
00434         }
00435     }
00436 #endif
00437     put_node_recursive(s, b, print_xreal, short_output);
00438 }
00439 
00440 local void forget_node_recursive(istream& s)
00441 {
00442     char line[MAX_INPUT_LINE_LENGTH];
00443 
00444     get_line(s, line);
00445 
00446     while(!matchbracket(END_PARTICLE, line)) {
00447         if(matchbracket(START_PARTICLE, line))                 
00448             forget_node_recursive(s);
00449         get_line(s, line);
00450     }
00451 }
00452 
00453 // forget_node: reads in a complete node structure, just as get_node does, but 
00454 //              without storing anything.  This is useful in the function
00455 //              snapprune, which prunes a long list of snapshots.
00456 //              Piet, 941125.
00457 
00458 bool forget_node(istream& s)
00459 {
00460     if(!check_and_skip_input_line(s, START_PARTICLE)) {
00461         return FALSE;
00462     }
00463     forget_node_recursive(s);
00464     return TRUE;
00465 }

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