00001
00002 //=======================================================// _\|/_
00003 // __ _____ ___ ___ // /|\ ~
00004 // / | ^ | \ | ^ | \ // _\|/_
00005 // \__ | / \ |___/ | / \ |___/ // /|\ ~
00006 // \ | /___\ | \ | /___\ | \ // _\|/_
00007 // ___/ | / \ | \ |____ / \ |___/ // /|\ ~
00008 // // _\|/_
00009 //=======================================================// /|\ ~
00010
00011 //
00012 // hdyn_tree.C: functions related to tree evolution in kira.
00013 //.............................................................................
00014 // version 1: Nov 1995 Jun Makino, Steve McMillan
00015 //.............................................................................
00016 //
00017 // Externally visible functions:
00018 //
00019 // real hdyn::distance_to_sister_squared
00020 // hdyn* hdyn::new_sister_node
00021 // int hdyn::adjust_tree_structure
00022 //
00023 // void split_top_level_node
00024 // void combine_top_level_nodes
00025 //
00026 // The functions that actually make changes to the tree structure are
00027 //
00028 // void split_top_level_node
00029 // void combine_top_level_nodes
00030 // void combine_low_level_nodes (local)
00031 //
00032 //.............................................................................
00033 //
00034 // NOTE (SLWM, 7/97): when a binary node is created, update_binary_sister
00035 // is not called, so the components' timesteps, etc. may not be up to date
00036 // until the next time step is taken. This is not generally a problem,
00037 // but may cause difficulties in set_unperturbed_timestep if a lower-level
00038 // node takes a step before the higher-level binary is advanced.
00039 //
00040 //.............................................................................
00041
00042 #include "hdyn.h"
00043 #include <star/dstar_to_kira.h>
00044 #include <star/single_star.h>
00045
00046 // Note: The *only* places in kira where "close" is defined, for
00047 // purposes of making binary trees, are too_close() and
00048 // new_sister_node().
00049 //
00050 // Close_criterion is now a variable, part of kira_options:
00051 //
00052 // 0: "close" criterion based on distance
00053 // 1: potential
00054 // 2: force
00055
00056 // Both criteria 1 and 2 expand the binary distance criterion as masses
00057 // increase. Both appear to work (Steve, 7/29/98).
00058
00059 real hdyn::distance_to_sister_squared()
00060 {
00061 vector d_sep = pos - get_binary_sister()->get_pos();
00062 return d_sep * d_sep;
00063 }
00064
00065 local void init_predictor_tree(hdyn * b)
00066 {
00067 if (! b->is_root()) {
00068 b->init_pred();
00069 b->store_old_force();
00070 }
00071 for_all_daughters(hdyn,b,bb) init_predictor_tree(bb);
00072 }
00073
00074 // synchronize_branch: Synchronize parent and sister nodes up to, but
00075 // not including, the specified ancestor.
00076
00077 local void synchronize_branch(hdyn * bi, hdyn * ancestor)
00078 {
00079 if (!is_descendent_of(bi, ancestor, 0))
00080 err_exit("synchronize_branch: bi not descended from ancestor");
00081
00082 for (hdyn * bb = bi; bb != ancestor; bb = bb->get_parent()) {
00083
00084 // Synchronize sister node:
00085
00086 bb->get_binary_sister()->synchronize_node();
00087
00088 // Synchronize parent:
00089
00090 bb->get_parent()->synchronize_node();
00091 }
00092 }
00093
00094 local inline real max_mass(hdyn* b)
00095 {
00096 real m_max = 0;
00097 if (b->is_parent()) {
00098 for_all_daughters(hdyn, b, bb)
00099 if (bb->get_mass() > m_max)
00100 m_max = max(m_max, max_mass(bb));
00101 } else
00102 m_max = b->get_mass();
00103
00104 return m_max;
00105 }
00106
00107 local inline real n_mass(hdyn* b)
00108 {
00109 // Choose which mass we use in the binary criterion.
00110
00111 // Must be careful to avoid "polymerization" of clumps containing
00112 // very massive stars. Try limiting the mass of a node to the
00113 // maximum mass of any of its leaves...
00114
00115 // return b->get_mass();
00116
00117 return max_mass(b);
00118 }
00119
00120 local bool number_of_daughter_nodes_exceeds(node * b, int n)
00121 {
00122 int nn = 0;
00123
00124 for_all_daughters(node, b, bb)
00125 if (++nn > n)
00126 return true;
00127
00128 return false;
00129 }
00130
00131 local void halve_timestep(hdyn * b)
00132 {
00133 b->set_timestep(0.5 * b->get_timestep());
00134 }
00135
00136 local void print_relative_energy_and_period(hdyn* bi, hdyn* bj)
00137 {
00138 real E, P;
00139 get_total_energy_and_period(bi, bj, E, P);
00140
00141 cerr << "relative E/mu = " << E << flush;
00142
00143 if (E < 0)
00144 cerr << " P = " << P; // no endl, note
00145 }
00146
00147
00148 local bool too_close(hdyn * bi, hdyn * bj, real limit_sq,
00149 bool print = true)
00150 {
00151 if (bi == bj)
00152 return false;
00153
00154 real gap_sq = square(bi->get_pos() - bj->get_pos());
00155
00156 // Binary criterion modified 7/98 by SLWM and SPZ to depend on
00157 // acceleration; modified again by SLWM and JM to include potential.
00158 // The criteria below are chosen to reduce to the simple distance
00159 // expressions when all masses are equal.
00160
00161 bool close;
00162 real mass_factor = 1; // default (DISTANCE criterion:
00163 // rij < d_min)
00164
00165 if (bi->get_kira_options()->close_criterion > 0) {
00166
00167 mass_factor = 0.5 * (n_mass(bi) + n_mass(bj)) / bi->get_mbar();
00168
00169 if (bi->get_kira_options()->close_criterion == 1) {
00170
00171 // POTENTIAL criterion: (mi + mj) / rij > 2 <m> / d_min
00172 //
00173 // ==> rij < 0.5 * (mi+mj) * d_min / <m>
00174
00175 mass_factor *= mass_factor;
00176
00177 } else if (bi->get_kira_options()->close_criterion == 2) {
00178
00179 // FORCE criterion: (mi + mj) / rij^2 > 2 <m> / d_min^2
00180 //
00181 // ==> rij^2 < 0.5 * (mi + mj) * d_min^2 / <m>
00182
00183 }
00184
00185 }
00186
00187 close = (gap_sq < mass_factor * limit_sq);
00188
00189 if (close && print && bi->get_kira_diag()->tree
00190 && bi->get_kira_diag()->tree_level > 0) {
00191 cerr << endl << "*** "; bi->print_label(cerr);
00192 cerr << " too close to "; bj->print_label(cerr);
00193 cerr << " (criterion " << bi->get_kira_options()->close_criterion
00194 << ")" << endl;
00195 }
00196
00197 return close;
00198 }
00199
00200 local bool too_big(hdyn * bi, real limit_sq)
00201 {
00202 hdyn *od = bi->get_oldest_daughter();
00203 if (od == NULL)
00204 return false;
00205
00206 // The next if statement prevents an unperturbed binary from being
00207 // split even if it is large.
00208
00209 if (od->get_kepler()) return false;
00210
00211 // Expand this to extend binaries with small perturbation which are
00212 // not actually unperturbed. May need other checks on nn distance,
00213 // timestep, etc... (Steve, 12/12/01)
00214
00215 if (od->get_valid_perturbers()) {
00216 real pert2 = od->get_perturbation_squared();
00217 // if (pert2 >= 0 && pert2 <= od->get_gamma2()) return false;
00218 if (pert2 >= 0 && pert2 <= 1.e-10) return false;
00219 }
00220
00221 bool big = !too_close(od, od->get_younger_sister(), limit_sq, false);
00222
00223 // Don't allow a slow binary to be split, but schedule the slow
00224 // motion to be stopped at next apocenter.
00225
00226 if (big && od->get_slow()) {
00227 if (!od->get_slow()->get_stop()) {
00228 cerr << "too_big: scheduling end of slow motion for "
00229 << bi->format_label() << " at time " << bi->get_system_time()
00230 << endl;
00231 od->get_slow()->set_stop();
00232 }
00233 return false;
00234 }
00235
00236 if (big && bi->get_kira_diag()->tree
00237 && bi->get_kira_diag()->tree_level > 0)
00238 cerr << endl << "*** " << bi->format_label() << " too big" << endl;
00239
00240 return big;
00241 }
00242
00243 // new_sister_node: Check to see if a given node is too near any other.
00244 // Return a pointer to the node that should become the
00245 // new sister, or NULL if the tree is OK as is.
00246 //
00247 // **** Used only by adjust_low_level_node. ****
00248 // **** Called twice, with 'this' = either component. ****
00249
00250 hdyn* hdyn::new_sister_node(bool & top_level_combine)
00251 {
00252 top_level_combine = false; // if true, combine top level nodes on return;
00253 // if false, combine lower level nodes if a
00254 // non-NULL value is returned
00255
00256 // Note on multiples from Steve, 10/21/98; extended discussion
00257 // from Steve for Steve added 6/6-13/00. Some care is needed in
00258 // dealing with multiples because of a "feature" of function
00259 // calculate_acc_and_jerk_on_low_level_node (hdyn_ev.C):
00260 //
00261 // If (A, B) is the top-level binary of a multiple, and if A is
00262 // a leaf with nn under B, then both A and B's nn pointers will
00263 // be correctly set (A to the leaf under B, B to A). However, if
00264 // A is a composite node containing B's nn, then A's nn will be
00265 // B (or a leaf under B), but B's nn will be A (efficiency issue
00266 // in hdyn_ev). Note that 'this' in this function may be either
00267 // A or B, leading (for a triple) to four distinct possibilities.
00268 // Suppose (a,b) is a binary where b is about to become the sister
00269 // of a perturber c. Then, depending on the ordering of the
00270 // particles and which one is 'this', we can have:
00271 //
00272 //
00273 // O A = (a,b), B = c, 'this' = A
00274 // / \ nn of A is c, nn of c is A
00275 // A c nn of a is b, nn of b is c
00276 // / \ ~
00277 // a b exchange will not be detected until
00278 // component a is advanced (return at *)
00279 //
00280 //
00281 // O A = (a,b), B = c, 'this' = c
00282 // / \ nn of A is c, nn of c is A
00283 // A c nn of a is b, nn of b is c
00284 // / \ ~
00285 // a b exchange will not be detected until
00286 // component a is advanced (return at *)
00287 //
00288 //
00289 // O A = c, B = (a,b), 'this' = c
00290 // / \ nn of c is b, nn of B is c
00291 // c B nn of a is b, nn of b is c
00292 // / \ ~
00293 // a b exchange will be detected when c
00294 // is advanced
00295 //
00296 //
00297 // O A = c, B = (a,b), 'this' = B
00298 // / \ nn of c is b, nn of B is c
00299 // c B nn of a is b, nn of b is c
00300 // / \ ~
00301 // a b exchange will be detected when c
00302 // is advanced
00303 //
00304 // Thus, a close encounter between (e.g.) triple members will not be
00305 // picked up on integration of the outer binary if A is composite,
00306 // but it will be if A is a leaf. An exchange in the former case must
00307 // be detected when A's internal motion is integrated (leaves under A
00308 // have the correct nn pointers). This is OK, as there is currently
00309 // no provision for such changes to be triggered by the parent node.
00310 // However, proper account must then be taken of the fact that B's nn
00311 // may not be a leaf, but A. Failure to do this can lead to runaway
00312 // time steps (--> 0) when a close encounter goes undetected.
00313 //
00314 // Additional note (Steve, 6/14/00). Unfortunately, it is possible
00315 // that the internal motion never gets the chance to trigger the
00316 // exchange, as the parent node time step may run away first.
00317 // Specific example: A is a receding unbound pair and B happens to
00318 // pass close to A's center of mass. We flag this by checking for
00319 // (a) a strongly perturbed binary with nn lying between its components
00320 // (i.e. the cause), or (b) disparate center of mass and component
00321 // time steps in a strongly perturbed binary (the effect). (See the
00322 // use of "check_binary_params" below.) We then synchronize the
00323 // daughter nodes and reduce their time steps in order to guarantee
00324 // that they will be on the integration list next time around, and
00325 // identify the configuration at the component level by including
00326 // an explicit check (**) on the perturbation within this function.
00327
00328 if (nn->get_parent() == parent) // already sisters, so no change needed
00329 return NULL; // (* - see note above)
00330
00331 real mass_factor = 1; // default (DISTANCE criterion)
00332
00333 if (options->close_criterion > 0) {
00334
00335 real m = n_mass(this);
00336 mass_factor = (m + n_mass(get_binary_sister())) / (m + n_mass(nn));
00337
00338 if (options->close_criterion == 1) {
00339
00340 // POTENTIAL criterion:
00341
00342 mass_factor *= mass_factor;
00343
00344 } else if (options->close_criterion == 2) {
00345
00346 // FORCE criterion:
00347
00348 }
00349 }
00350
00351 bool nn_too_close = (distance_to_sister_squared()
00352 > d_nn_sq * lag_factor * mass_factor);
00353
00354 if (!nn_too_close) { // (** Steve 6/14/00) Relax the distance
00355 // criterion for a strongly perturbed binary,
00356 // as described above. Perhaps better to
00357 // check explicitly the position of nn
00358 // relative to the parent node?
00359
00360 nn_too_close = (perturbation_squared > 1
00361 && distance_to_sister_squared() > d_nn_sq);
00362
00363 if (nn_too_close && diag->tree && diag->tree_level > 1) {
00364 cerr << "in new_sister_node for " << format_label()
00365 << " at time " << system_time << ":" << endl;
00366 cerr << " candidate new sister for strongly perturbed binary is "
00367 << nn->format_label() << endl;
00368 }
00369
00370 }
00371
00372 if (nn_too_close) {
00373
00374 // Nearest neighbor is closer than binary sister.
00375 //
00376 // Should check whether or not this and nn are mutual nearest
00377 // neighbors. If they are, then we are done. If not, then we
00378 // must be a little more careful. We should further check if
00379 // one of nn's ancestors can become the new sister.
00380 //
00381 // Criterion: If the nearest neighbor of any ancestor
00382 // of nn is a component of this node, connect these two.
00383
00384 hdyn * new_sister = nn;
00385 hdyn * root = get_root();
00386
00387 // The nn of new_sister may be a node (see note above). Take care
00388 // of this possibility before proceeding. Expect that the nn is
00389 // the binary sister (should be the only way in which this can
00390 // occur -- see hdyn_ev), but do the search generally, anyway.
00391
00392 hdyn *snn = new_sister->get_nn();
00393
00394 if (snn && snn->is_valid() && !snn->is_leaf()) {
00395
00396 // The true nn lies below snn. Locate it, and modify
00397 // new_sister->nn accordingly. Its distance should
00398 // be new_sister->d_nn_sq, but let's not tempt fate...
00399
00400 real d_sq_min = VERY_LARGE_NUMBER;
00401 hdyn * local_nn = NULL;
00402 vector s_pos = hdyn_something_relative_to_root(new_sister,
00403 &hdyn::get_pos);
00404
00405 for_all_leaves(hdyn, snn, bb) {
00406 vector b_pos = hdyn_something_relative_to_root(bb,
00407 &hdyn::get_pos);
00408 real d_sq = square(b_pos - s_pos);
00409 if (d_sq < d_sq_min) {
00410 local_nn = bb;
00411 d_sq_min = d_sq;
00412 }
00413 }
00414
00415 if (local_nn) {
00416
00417 snn = local_nn;
00418 new_sister->set_nn(snn);
00419
00420 if (diag->tree && diag->tree_level > 0) {
00421 cerr << "new_sister_node: computed local nn for "
00422 << new_sister->format_label() << endl;
00423 PR(local_nn);
00424 cerr << " (" << snn->format_label() << ")" << endl;
00425 PRC(new_sister->get_d_nn_sq()); PRL(d_sq_min);
00426 }
00427 }
00428 }
00429
00430 // Attach to the highest possible ancestor of new_sister.
00431
00432 if (snn && snn->is_valid() && common_ancestor(snn, this) != this) {
00433
00434 hdyn* ns = new_sister;
00435
00436 do {
00437 new_sister = new_sister->get_parent();
00438 } while(new_sister != root
00439 && new_sister->get_nn() != NULL
00440 && new_sister->get_nn()->is_valid()
00441 && new_sister->parent != parent
00442 && common_ancestor(new_sister->get_nn(), this) != this);
00443
00444 if (new_sister == root
00445 || new_sister->get_nn() == NULL
00446 || !new_sister->get_nn()->is_valid()
00447 || new_sister->parent == parent
00448 || common_ancestor(new_sister, this)== this
00449 || common_ancestor(new_sister, this)== new_sister
00450 ) return NULL;
00451
00452 if (diag->tree && diag->tree_level > 0) {
00453 cerr << "new_sister_node: ascended tree from "
00454 << ns->format_label();
00455 cerr << " to " << new_sister->format_label() << endl;
00456 }
00457 }
00458
00459 hdyn * ancestor = common_ancestor(this, new_sister);
00460
00461 if (ancestor->is_root()) {
00462
00463 top_level_combine = TRUE;
00464 return new_sister;
00465
00466 } else {
00467
00468 // The new sister node is in the same subtree.
00469 // Attach this node to the location as high up as possible.
00470
00471 if (parent != ancestor) {
00472 while (new_sister->get_parent() != ancestor) {
00473 new_sister = new_sister->get_parent();
00474 }
00475 }
00476
00477 if (new_sister->kep == NULL) {
00478 if (diag->tree && diag->tree_level > 0) {
00479 cerr << "new sister node for "; pretty_print_node(cerr);
00480 cerr << " (nn = "; nn->pretty_print_node(cerr);
00481 cerr << ") is " ; new_sister->pretty_print_node(cerr);
00482 PRI(2); PRL(top_level_combine);
00483 }
00484 return new_sister;
00485 }
00486 }
00487 }
00488 return NULL;
00489 }
00490
00491
00492 local void check_merge_esc_flags(hdyn *bi, hdyn *bj)
00493 {
00494 // Update any escaper flags in two nodes being combined.
00495 // The CM node is flagged as escaping iff both components are.
00496
00497 bool iesc = find_qmatch(bi->get_dyn_story(), "t_esc");
00498 bool jesc = find_qmatch(bj->get_dyn_story(), "t_esc");
00499
00500 if (iesc && jesc) {
00501
00502 // Both components are flagged as escapers.
00503
00504 real t_esc = max(getrq(bi->get_dyn_story(), "t_esc"),
00505 getrq(bj->get_dyn_story(), "t_esc"));
00506 putrq(bi->get_parent()->get_dyn_story(), "esc", 1);
00507 putrq(bi->get_parent()->get_dyn_story(), "t_esc", t_esc);
00508
00509 } else {
00510
00511 // One component wasn't flagged as escaping.
00512
00513 putrq(bi->get_parent()->get_dyn_story(), "esc", 0);
00514
00515 if (iesc) {
00516 putrq(bi->get_dyn_story(), "esc", 0);
00517 rmq(bi->get_dyn_story(), "t_esc");
00518 }
00519
00520 if (jesc) {
00521 putrq(bj->get_dyn_story(), "esc", 0);
00522 rmq(bj->get_dyn_story(), "t_esc");
00523 }
00524 }
00525 }
00526
00527 void combine_top_level_nodes(hdyn * bj, hdyn * bi,
00528 int full_dump) // default = 0
00529 {
00530 // Combine two top-level nodes into a binary. Original node names
00531 // and addresses are retained, so neighboring perturber lists are
00532 // unaffected. bi is the node whose step caused the change; bj is
00533 // its nearest neighbor. For obscure reasons, the new CM node
00534 // will be (bj, bi).
00535
00536 if (bi->get_kira_diag()->tree) {
00537
00538 cerr << endl << "combine_top_level_nodes: attaching ",
00539 bj->pretty_print_node(cerr);
00540 cerr << " to ", bi->pretty_print_node(cerr);
00541 cerr << " at time " << bi->get_system_time();
00542
00543 if (bj->get_kira_diag()->tree_level > 0) {
00544
00545 cerr << endl;
00546 pp2(bi, cerr);
00547 print_binary_from_dyn_pair(bj, bi);
00548 cerr << endl;
00549 if (bj->is_parent()) {
00550 print_binary_from_dyn_pair(bj->get_oldest_daughter(),
00551 bj->get_oldest_daughter()
00552 ->get_younger_sister());
00553 cerr << endl;
00554 }
00555 if (bi->is_parent()) {
00556 print_binary_from_dyn_pair(bi->get_oldest_daughter(),
00557 bi->get_oldest_daughter()
00558 ->get_younger_sister());
00559 cerr << endl;
00560 }
00561
00562 if (bj->get_kira_diag()->tree_level > 1) {
00563
00564 // Not really necessary if pp3 (new node) occurs below:
00565 //
00566 // cerr << endl;
00567 // pp3(bi, cerr);
00568 // pp3(bj, cerr);
00569
00570 if (bj->get_kira_diag()->tree_level > 2) {
00571 cerr << endl;
00572 put_node(cerr, *bj, bj->get_kira_options()->print_xreal);
00573 put_node(cerr, *bi, bi->get_kira_options()->print_xreal);
00574 }
00575
00576 cerr << endl;
00577 plot_stars(bj);
00578 }
00579
00580 } else {
00581
00582 cerr << endl << " ";
00583 print_relative_energy_and_period(bj, bi);
00584 cerr << endl;
00585 }
00586 }
00587
00588 // Make sure bi and bj are up to date.
00589
00590
00591 predict_loworder_all(bi->get_root(), bi->get_system_time());
00592
00593 // print_recalculated_energies(bi->get_root(), 1);
00594 // pp3((bi->get_root()), cerr);
00595 // synchronize_tree(bi->get_root(), time);
00596 // print_recalculated_energies(bi->get_root(), 1);
00597 // pp3((bi->get_root()), cerr);
00598
00599 bi->synchronize_node();
00600 bj->synchronize_node();
00601
00602 if (full_dump) {
00603
00604 // Components are synchronized, but lower levels are not.
00605 // The 4tree software needs trees to be synchronous, but
00606 // synchronizing everything here will likely lead to runaway
00607 // timesteps. Function put_node in this case must use
00608 // *predicted* quantities and system time as time.
00609 // All necessary predictions have already been done.)
00610
00611 // Dump out the "before" system (bi and bj), for use in 4tree
00612 // applications, with "defunct" flags attached (final "3").
00613
00614 // cerr << "combine_top_level_nodes: time " << bi->get_system_time();
00615 // cerr << " put_node for " << endl << " " << bi->format_label();
00616 // cerr << " and " << bj->format_label() << endl;
00617
00618 put_node(cout, *bi, false, 3);
00619 put_node(cout, *bj, false, 3);
00620 }
00621
00622 // Remove any slow_perturbed references to the components from
00623 // other top-level nodes. Only possible if a component is a slow
00624 // binary...
00625
00626 for (hdyn *bb = bi; bb != bj; bb = bj)
00627 if (bb->get_kappa() > 1) {
00628 hdyn *pnode = bb->find_perturber_node();
00629 if (pnode && pnode->get_valid_perturbers())
00630 for (int k = 0; k < pnode->get_n_perturbers(); k++) {
00631 hdyn *p = pnode->get_perturber_list()[k]
00632 ->get_top_level_node();
00633 if (p->get_sp())
00634 p->remove_slow_perturbed(bb);
00635 }
00636 }
00637
00638 create_binary_from_toplevel_nodes(bi, bj); // --> (bj, bi)
00639
00640 // Copy any slow_perturbed lists to the new top-level node, and
00641 // delete the low-level lists.
00642
00643 bi->copy_slow_perturbed(bi->get_parent());
00644 bi->clear_slow_perturbed();
00645 bj->copy_slow_perturbed(bj->get_parent());
00646 bj->clear_slow_perturbed();
00647
00648 // Delete any slow_perturbed element in the new CM node that refers
00649 // to either component.
00650
00651 if (bi->get_parent()->get_sp()) {
00652 bi->get_parent()->remove_slow_perturbed(bi);
00653 bi->get_parent()->remove_slow_perturbed(bj);
00654 }
00655
00656 // Reset all perturber lists below the newly-formed top-level
00657 // node -- probably not necessary for bi and bj if low-level
00658 // perturber lists are allowed, but cleaner to clear and
00659 // recompute the lists.
00660
00661 for_all_nodes(hdyn, bj->get_parent(), bb) {
00662 bb->set_valid_perturbers(false);
00663 bb->set_perturbation_squared(-1);
00664 }
00665
00666 // Shrink timesteps for safety...
00667
00668 // halve_timestep(bi);
00669 // halve_timestep(bj);
00670
00671 halve_timestep(bj->get_parent()); // parent step should be less than the
00672 // daughter steps so that the parent
00673 // perturber list is computed before
00674 // the internal motion is advanced
00675
00676 bi->init_pred();
00677 bj->init_pred();
00678 bj->get_parent()->init_pred();
00679
00680 init_predictor_tree(bj->get_parent()); // for diagnostic output...
00681
00682 check_merge_esc_flags(bj, bi);
00683
00684 if (full_dump) {
00685
00686 // Dump out the "after" system (parent), for use in 4tree
00687 // applications. Must predict this portion of the tree again.
00688
00689 predict_loworder_all(bj->get_parent(), bj->get_system_time());
00690
00691 // cerr << "combine_top_level_nodes: time " << bi->get_system_time();
00692 // cerr << " put_node for " << bj->get_parent()->format_label()
00693 // << endl;
00694
00695 put_node(cout, *bj->get_parent(), false, 2);
00696 }
00697
00698 bi->get_kira_counters()->top_level_combine++;
00699
00700 if (bi->get_kira_diag()->tree && bi->get_kira_diag()->tree_level > 1)
00701 pp3(bi->get_parent(), cerr);
00702 }
00703
00704 void split_top_level_node(hdyn * bi,
00705 int full_dump) // default = 0
00706 {
00707 // Split a top-level node into two components. The original node is
00708 // deleted, so any references to it (in nn/coll pointers or perturber
00709 // lists) must be corrected.
00710
00711 if (!bi->is_top_level_node())
00712 err_exit("split_top_level_node: not at top level");
00713
00714 if (bi->get_oldest_daughter()->get_slow()) {
00715
00716 // Shouldn't happen -- flag and defer the split.
00717
00718 cerr << "split_top_level_node: warning: trying to split slow binary "
00719 << bi->format_label() << endl
00720 << " at time " << bi->get_system_time() << endl;
00721
00722 // bi->get_oldest_daughter()->delete_slow();
00723
00724 bi->get_oldest_daughter()->get_slow()->set_stop();
00725 return;
00726 }
00727
00728 if (bi->get_kira_diag()->tree) {
00729
00730 cerr << endl << "split_top_level_node: splitting ";
00731 bi->pretty_print_node(cerr);
00732 cerr << " at time " << bi->get_system_time();
00733
00734 if (bi->get_kira_diag()->tree_level >= 1) {
00735 cerr << endl;
00736 pp2(bi, cerr);
00737 print_binary_from_dyn_pair(bi->get_oldest_daughter(),
00738 bi->get_oldest_daughter()
00739 ->get_younger_sister());
00740
00741 #if 0
00742 cerr << endl;
00743 PRL(bi->get_oldest_daughter()->get_perturbation_squared());
00744 hdyn *pnode = bi->get_oldest_daughter()->find_perturber_node();
00745 if (pnode && pnode->is_valid()) {
00746 PRL(pnode->format_label());
00747 if (pnode->get_valid_perturbers())
00748 PRL(pnode->get_n_perturbers());
00749 else
00750 cerr << "perturbers unknown" << endl;
00751 } else
00752 cerr << "pnode invalid" << endl;
00753 #endif
00754
00755
00756 cerr << endl << flush;
00757
00758 if (bi->get_kira_diag()->tree_level > 1) {
00759 cerr << endl;
00760 pp3(bi, cerr);
00761
00762 // Excessive output?
00763
00764 if (bi->get_kira_diag()->tree_level > 2)
00765 put_node(cerr, *bi, bi->get_kira_options()->print_xreal);
00766 }
00767 } else {
00768 cerr << endl << " ";
00769 print_relative_energy_and_period(bi->get_oldest_daughter(),
00770 bi->get_oldest_daughter()
00771 ->get_younger_sister());
00772 cerr << endl;
00773 }
00774 }
00775
00776 hdyn *od = bi->get_oldest_daughter();
00777 hdyn *yd = od->get_younger_sister();
00778
00779 // Synchronize the nodes involved.
00780
00781 predict_loworder_all(bi->get_root(), bi->get_system_time());
00782
00783 // for debugging ...
00784 // synchronize_tree(bi->get_root());
00785 // synchronize_tree(bi);
00786
00787 bi->synchronize_node();
00788 od->synchronize_node();
00789 update_binary_sister(od);
00790
00791 if (full_dump) {
00792
00793 // Components are synchronized, but lower levels are not.
00794
00795 // Dump out the "before" system, for use in 4tree applications,
00796 // using predicted quantities.
00797
00798 // cerr << "split_top_level_node: time " << bi->get_system_time();
00799 // cerr << " put_node for " << bi->format_label() << endl;
00800
00801 put_node(cout, *bi, false, 3);
00802 }
00803
00804 // Express od and yd quantities relative to root.
00805
00806 od->set_pos(hdyn_something_relative_to_root(od, &hdyn::get_pos));
00807 od->set_vel(hdyn_something_relative_to_root(od, &hdyn::get_vel));
00808 od->set_acc(hdyn_something_relative_to_root(od, &hdyn::get_acc));
00809 od->set_jerk(hdyn_something_relative_to_root(od, &hdyn::get_jerk));
00810 od->store_old_force();
00811
00812 yd->set_pos(hdyn_something_relative_to_root(yd, &hdyn::get_pos));
00813 yd->set_vel(hdyn_something_relative_to_root(yd, &hdyn::get_vel));
00814 yd->set_acc(hdyn_something_relative_to_root(yd, &hdyn::get_acc));
00815 yd->set_jerk(hdyn_something_relative_to_root(yd, &hdyn::get_jerk));
00816 yd->store_old_force();
00817
00818 od->init_pred();
00819 yd->init_pred();
00820
00821 // May not be necessary to do this if low-level perturbers are
00822 // allowed, but cleaner to recompute the lists. Clear all
00823 // perturber lists below the new top-level nodes.
00824
00825 for_all_nodes(hdyn, od, bb) {
00826 bb->set_valid_perturbers(false);
00827 bb->set_perturbation_squared(-1);
00828 }
00829 for_all_nodes(hdyn, yd, bb) {
00830 bb->set_valid_perturbers(false);
00831 bb->set_perturbation_squared(-1);
00832 }
00833
00834 // Dissolve the parent node and attach od and yd at top level.
00835
00836 hdyn *root = bi->get_root();
00837
00838 detach_node_from_general_tree(*bi);
00839
00840 // Imperfect correction of neighbor pointers:
00841
00842 if (bi->get_nn()->get_nn() == bi)
00843 bi->get_nn()->set_nn(NULL);
00844
00845 // Should also check for the unlikely possibility that:
00846 //
00847 // (1) binary bi is unperturbed, and
00848 // (2) binary bi is on the perturber list of some other binary.
00849 //
00850 // If so, bi must be removed from the perturber list before being
00851 // deleted.
00852
00853 if (!RESOLVE_UNPERTURBED_PERTURBERS)
00854 expand_perturber_lists(bi->get_root(), bi,
00855 bi->get_kira_diag()->tree
00856 && bi->get_kira_diag()->tree_level > 0);
00857
00858 // Copy any slow_perturbed list to the components.
00859
00860 bi->copy_slow_perturbed(od, true); // "true" ==> overwrite
00861 bi->copy_slow_perturbed(yd, true);
00862
00863 delete bi;
00864
00865 add_node(*od, *root);
00866 add_node(*yd, *root);
00867
00868 // halve_timestep(od);
00869 // halve_timestep(yd);
00870
00871 if (full_dump) {
00872
00873 // Dump out the "after" system (od and yd), for use in 4tree
00874 // applications.
00875
00876 predict_loworder_all(od, od->get_system_time());
00877 predict_loworder_all(yd, yd->get_system_time());
00878
00879 // cerr << "split_top_level_node: time " << od->get_system_time();
00880 // cerr << " put_node for " << endl << " " << od->format_label();
00881 // cerr << " and " << yd->format_label() << endl;
00882
00883 put_node(cout, *od, false, 2);
00884 put_node(cout, *yd, false, 2);
00885 }
00886
00887 bi->get_kira_counters()->top_level_split++;
00888 }
00889
00890 local void combine_low_level_nodes(hdyn * bi, hdyn * bj,
00891 int full_dump = 0)
00892 {
00893 // Rearrange the tree structure within a multiple system to try
00894 // to make bi and bj sister nodes.
00895
00896 if (bi->get_slow()) {
00897
00898 // Not sure if this can happen, but flag it just in case...
00899 // Hmmm, looks like it can happen (Steve, 9/00).
00900
00901 // Old code:
00902 //
00903 // cerr << "combine_low_level_nodes: warning: splitting slow binary "
00904 // << bi->get_parent()->format_label() << " at time "
00905 // << bi->get_system_time()
00906 // << endl;
00907 // bi->delete_slow(); // will likely cause a crash later!
00908
00909 // New:
00910
00911 // As in split_top_level_node, defer the split
00912 // and schedule the slow motion for termination...
00913
00914 bi->get_slow()->set_stop();
00915 return;
00916 }
00917
00918 if (bi->get_kira_diag()->tree && bi->get_kira_diag()->tree_level > 0) {
00919 cerr << "\ncombine_low_level_nodes: combining ";
00920 bi->pretty_print_node(cerr);
00921 cerr << " and ";
00922 bj->pretty_print_node(cerr);
00923 cerr << " at time " << bi->get_system_time() << "\n";
00924 }
00925
00926 hdyn *ancestor;
00927 ancestor = common_ancestor(bi, bj);
00928
00929 bool pp3_at_end = false;
00930
00931 #if 0
00932 if (bi->get_time() > 2.6 && bi->get_time() < 2.7) {
00933 cerr << endl << "------------------------------" << endl;
00934 cerr << "combine_low_level_nodes:" << endl;
00935 cerr << "bi = " << bi->format_label() << endl;
00936 cerr << "bj = " << bj->format_label() << endl;
00937 cerr << "ancestor = " << ancestor->format_label() << endl;
00938 pp3(ancestor);
00939 pp3_at_end = true;
00940 }
00941 #endif
00942
00943 // Make sure bi and bj are up to date.
00944
00945 predict_loworder_all(bi->get_root(), bi->get_system_time());
00946
00947 bi->synchronize_node();
00948 bj->synchronize_node();
00949
00950 synchronize_branch(bi, ancestor);
00951 synchronize_branch(bj, ancestor);
00952
00953 hdyn* old_top_level_node = bi->get_top_level_node();
00954
00955 // if (full_dump == 1) {
00956 if (full_dump) {
00957
00958 // Dump out the "before" system (top-level), for use in 4tree
00959 // applications.
00960
00961 // cerr << "combine_low_level_nodes: time " << bi->get_system_time();
00962 // cerr << " put_node for " << old_top_level_node->format_label()
00963 // << endl;
00964
00965 put_node(cout, *old_top_level_node, false, 3);
00966 }
00967
00968 // Note from Steve, 3/99:
00969 //
00970 // Function move_node will remove the parent node of bi and
00971 // reattach node bi as a sister of bj. If the binary sister
00972 // of bi is also a binary and contains bj, then it will become
00973 // an ancestor node of the new system. If, as is likely, bi is
00974 // a perturber of its binary sister, the perturber list of the
00975 // new system will then be corrupted, as the ancestor node will
00976 // still contain bi as a perturber. Avoid this unpleasantness
00977 // by forcing the perturber lists of the entire subtree to be
00978 // recomputed. However, retain the top-level perturber list,
00979 // which should be unchanged, so we at least don't have to
00980 // compute perturbations using the entire system.
00981 // Messy, messy...
00982 //
00983 // Messier still, if bi's parent node happens to be the top-level
00984 // node, then the top-level node will be deleted and its perturber
00985 // information lost. Save the perturber info and restore it to
00986 // the eventual top-level node.
00987
00988 bool vp = old_top_level_node->get_valid_perturbers();
00989 int np = 0;
00990 real p_sq = -1;
00991 real p_fac = 0;
00992 hdyn** pert_list = NULL;
00993
00994 if (vp) {
00995 np = old_top_level_node->get_n_perturbers();
00996 p_sq = old_top_level_node->get_perturbation_squared();
00997 p_fac = old_top_level_node->get_perturbation_radius_factor();
00998 pert_list = new hdyn *[MAX_PERTURBERS];
00999 for (int i = 0; i < np; i++)
01000 pert_list[i] = old_top_level_node->get_perturber_list()[i];
01001 // cerr << "saved top-level perturber information" << endl;
01002 }
01003
01004 move_node(bi, bj);
01005
01006 hdyn* top_level_node = bi->get_top_level_node();
01007
01008 if (top_level_node != old_top_level_node) {
01009
01010 if (vp) {
01011
01012 // Restore original top-level perturbation information.
01013 // (Might have been easier simply to copy the node...)
01014
01015 top_level_node->remove_perturber_list();
01016 top_level_node->new_perturber_list();
01017
01018 top_level_node->set_valid_perturbers(vp);
01019 top_level_node->set_n_perturbers(np);
01020 top_level_node->set_perturbation_squared(p_sq);
01021 top_level_node->set_perturbation_radius_factor(p_fac);
01022
01023 for (int i = 0; i < np; i++)
01024 top_level_node->get_perturber_list()[i] = pert_list[i];
01025
01026 delete pert_list;
01027 cerr << "restored top-level perturber information, np = "
01028 << np << endl;
01029
01030 } else {
01031
01032 top_level_node->set_valid_perturbers(vp);
01033 top_level_node->set_perturbation_squared(-1);
01034
01035 }
01036 }
01037
01038 // halve_timestep(bi);
01039 // halve_timestep(bj->get_parent());
01040
01041 predict_loworder_all(bi->get_root(), bi->get_system_time());
01042
01043 // Force all perturber lists in the present subtree to be rebuilt.
01044
01045 for_all_nodes(hdyn, top_level_node, bb) {
01046 if (bb != top_level_node) {
01047
01048 bb->set_valid_perturbers(false);
01049 bb->set_perturbation_squared(-1);
01050
01051 // cerr << "cleared perturber lists for "
01052 // << bb->format_label() << endl;
01053 }
01054 }
01055
01056 bi->get_kira_counters()->low_level_combine++;
01057
01058 // Make sure that all CM node names are up to date.
01059
01060 hdyn *bn = bi->get_parent();
01061 while (bn != bi->get_root()) {
01062 label_binary_node(bn);
01063 bn = bn->get_parent();
01064 }
01065
01066 check_merge_esc_flags(bi, bi->get_binary_sister());
01067
01068 // if (full_dump == 1) {
01069 if (full_dump) {
01070
01071 // Dump out the "after" system (new top-level), for use in 4tree
01072 // applications.
01073
01074 predict_loworder_all(top_level_node, bi->get_system_time());
01075
01076 // cerr << "combine_low_level_nodes: time " << bi->get_system_time();
01077 // cerr << " put_node for " << top_level_node->format_label() << endl;
01078
01079 put_node(cout, *top_level_node, false, 2);
01080 }
01081
01082 if (pp3_at_end) {
01083 cerr << endl << "after combine_low_level_nodes:" << endl;
01084 pp3(bi->get_top_level_node());
01085 cerr << endl << "------------------------------" << endl;
01086 }
01087 }
01088
01089 local int adjust_low_level_node(hdyn * bi, int full_dump = 0)
01090 {
01091 int status = 1;
01092
01093 bool top_level_combine; // TRUE iff top-level nodes are to be combined.
01094 // Takes precedence over the returned value of
01095 // new_sister_node. If new_sister_node is
01096 // non-NULL, it is the node which should become
01097 // the new sister of node bi within the same
01098 // binary subtree.
01099
01100 hdyn *sister = bi->new_sister_node(top_level_combine);
01101
01102 #if 0
01103 if (sister != NULL) {
01104 cout << "adjust low_level, "; bi->pretty_print_node(cout);
01105 cout << "-- "; sister->pretty_print_node(cout);
01106 cout << "-- "; sister->get_nn()->pretty_print_node(cout); cout<<endl;
01107 }
01108 #endif
01109
01110 if (sister != NULL)
01111 predict_loworder_all(bi->get_root(), bi->get_system_time());
01112
01113 if (top_level_combine) {
01114
01115 if (number_of_daughter_nodes_exceeds(bi->get_root(), 2)) {
01116
01117 if (bi->get_kira_diag()->tree
01118 && bi->get_kira_diag()->tree_level > 1) {
01119 cerr << "\nadjust_low_level_node: "
01120 << "normal top level combine at time "
01121 << bi->get_time() << endl;
01122 // print_recalculated_energies(bi->get_root(), 1);
01123 }
01124
01125 // cerr<< "Call combine_top_level_nodes from adjust_low_level_node"
01126 // << endl;
01127
01128 combine_top_level_nodes(sister->get_top_level_node(),
01129 bi->get_top_level_node(), full_dump);
01130 status = 2;
01131
01132 } else {
01133
01134 if (bi->get_kira_diag()->tree
01135 && bi->get_kira_diag()->tree_level > 1) {
01136 cerr << "adjust_low_level_node:"
01137 << " top level combine with two top level nodes at time "
01138 << bi->get_time() << endl;
01139 // print_recalculated_energies(bi->get_root(), 1);
01140 }
01141
01142 hdyn* t = bi->get_top_level_node();
01143 hdyn* od = t->get_oldest_daughter();
01144
01145 if (!od)
01146 status = 0; // shouldn't happen
01147 else {
01148
01149 if (od->get_slow()) {
01150
01151 if (!od->get_slow()->get_stop()) {
01152 cerr << "adjust_low_level_node: scheduling end "
01153 << "of slow motion for " << bi->format_label()
01154 << " at time " << bi->get_system_time()
01155 << endl;
01156 od->get_slow()->set_stop();
01157 }
01158 status = 0;
01159
01160 } else {
01161
01162 // cerr << "call split_top_level_node 1" << endl;
01163
01164 split_top_level_node(t, full_dump);
01165 status = 3;
01166
01167 }
01168 }
01169 }
01170
01171 } else if (sister != NULL)
01172
01173 combine_low_level_nodes(bi, sister, full_dump);
01174
01175 else
01176
01177 status = 0;
01178
01179 return status;
01180 }
01181
01182
01183 local inline bool check_binary_params(hdyn *b)
01184 {
01185 if (b->is_low_level_node()) {
01186
01187 hdyn *od = b->get_oldest_daughter();
01188
01189 if (od // b is a low-level,
01190 && od->get_perturbation_squared() > 1) { // strongly perturbed,
01191 // binary node
01192
01193 bool sync = false;
01194 int reason = 0;
01195
01196 if (od->get_timestep() // very disparate
01197 > 128*b->get_timestep()) // component timesteps
01198 // (128 is arbitrary)
01199 sync = true;
01200
01201 else if (b->distance_to_sister_squared() // components are too
01202 < od->distance_to_sister_squared() // far apart, with some
01203 && od->get_timestep() // timestep disparity
01204 > 4*b->get_timestep()) { // (4 is arbitrary)
01205
01206 sync = true;
01207 reason = 1;
01208
01209 }
01210
01211 // Synchronize the binary components if they are not on the
01212 // current integration list, and reset the binary timestep
01213 // to match the parent node.
01214
01215 if (od->get_time() == b->get_time()) sync = false;
01216
01217 if (sync) {
01218
01219 od->synchronize_node();
01220 od->set_timestep(b->get_timestep());
01221
01222 if (b->get_kira_diag()->tree
01223 && b->get_kira_diag()->tree_level > reason)
01224 cerr << "check_binary_params: synchronizing ("
01225 << reason << ") "
01226 << b->format_label() << " components at time "
01227 << b->get_system_time() << endl;
01228
01229 return true;
01230 }
01231 }
01232 }
01233
01234 return false;
01235 }
01236
01237 local void print_tree_structure(hdyn *bb) // for debugging
01238 {
01239 hdyn *b = bb->get_top_level_node();
01240 hdyn *od = b->get_oldest_daughter();
01241
01242 if (od) {
01243 hdyn *yd = od->get_younger_sister();
01244
01245 cerr << endl << "tree structure for " << b->format_label()
01246 << " at time " << b->get_system_time() << endl;
01247 cerr << "output triggered by " << bb->format_label() << endl;
01248
01249 // Daughters:
01250
01251 cerr << "daughters are " << od->format_label() << " and ";
01252 cerr << yd->format_label();
01253 cerr << ", separation = " << abs(od->get_pos()-yd->get_pos()) << endl;
01254 cerr << "daughter neighbors are " << od->get_nn()->format_label()
01255 << " and ";
01256 cerr << yd->get_nn()->format_label() << endl;
01257
01258 // Granddaughters:
01259
01260 for_all_daughters(hdyn, b, d) { // d is od or yd
01261 hdyn *od1 = d->get_oldest_daughter();
01262 if (od1) {
01263 cerr << " daughters of " << d->format_label();
01264 hdyn *od2 = od1->get_younger_sister();
01265 cerr << " (separation = "
01266 << abs(od1->get_pos()-od2->get_pos()) << "):" << endl;
01267 hdyn *s = d->get_binary_sister();
01268 for_all_daughters(hdyn, d, dd) { // dd is od1 or od2
01269 if (s->is_parent()) {
01270 for_all_daughters(hdyn, s, ss) {
01271 cerr << " distance from "
01272 << dd->format_label();
01273 cerr << " to " << ss->format_label() << " is ";
01274 cerr << abs(d->get_pos()+dd->get_pos()
01275 -s->get_pos()-ss->get_pos())
01276 << endl;
01277 }
01278 } else {
01279 cerr << " distance from " << dd->format_label();
01280 cerr << " to " << s->format_label() << " is ";
01281 cerr << abs(d->get_pos()+dd->get_pos()-s->get_pos())
01282 << endl;
01283 }
01284 }
01285 }
01286 }
01287 }
01288 }
01289
01290 int hdyn::adjust_tree_structure(int full_dump) // default = 0
01291 {
01292 int status = 0;
01293
01294 // Value of status (return value) indicates adjustment that occurred:
01295 //
01296 // 0 no adjustment
01297 // 1 low-level combine
01298 // 2 top-level combine (direct)
01299 // 3 top-level split (direct)
01300 // 4 top-level combine (indirect)
01301 // 5 top-level split (indirect)
01302 // 6 low-level timestep change (no tree change)
01303 //
01304 // (Similar coding also applies to adjust_low_level_node.)
01305
01306 // cerr << "\n*** in adjust_tree_structure for " << format_label() << endl;
01307
01308 hdyn *br = get_root();
01309 if (is_top_level_node()) { // this is a top-level node
01310
01311 bool cm = false;
01312 if (oldest_daughter) cm = true;
01313
01314 if (nn == NULL) {
01315 pretty_print_node(cerr); cerr << " nn is NULL " << endl;
01316 return 0;
01317 }
01318
01319 hdyn *nn_top = nn->get_top_level_node();
01320
01321 if (too_close(this, nn_top, d_min_sq)) {
01322
01323 if (number_of_daughter_nodes_exceeds(parent, 2)) {
01324
01325 predict_loworder_all(get_root(), system_time);
01326
01327 // cerr << "\ntime = " << system_time << endl;
01328 // print_recalculated_energies(get_root(), 1);
01329 // pp3(get_root(), cerr);
01330
01331 // cerr << "Call combine_top_level_nodes from "
01332 // << "adjust_tree_structure"<<endl;
01333
01334 combine_top_level_nodes(nn_top, this, full_dump);
01335
01336 // cerr << "Time = " << system_time<< endl;
01337 // print_recalculated_energies(get_root(), 1);
01338 // pp3(get_root(), cerr);
01339
01340 status = 2;
01341
01342 } else {
01343
01344 status = 0;
01345 }
01346
01347 } else if (too_big(this, d_min_sq * lag_factor)) {
01348
01349 // print_recalculated_energies(get_root(), 1);
01350
01351 predict_loworder_all(get_root(), system_time);
01352
01353 // Don't check for slow binary, as too_big should return false
01354 // if this is slow.
01355
01356 // cerr << "call split_top_level_node 2" << endl;
01357
01358 split_top_level_node(this, full_dump);
01359
01360 // Better exit next -- 'this' has already been deleted...
01361
01362 status = 3;
01363
01364 } else {
01365
01366 status = 0;
01367 }
01368
01369 } else { // this is a low-level node
01370 // *** check both this and our sister ***
01371 if (kep == NULL) {
01372
01373 hdyn *s = get_binary_sister();
01374 hdyn *old_top_level_node = get_top_level_node();
01375
01376 status = adjust_low_level_node(this, full_dump);
01377 if (!status) status = adjust_low_level_node(s, full_dump);
01378
01379 if (status) {
01380
01381 if (status > 1) status += 2;
01382 if (old_top_level_node != get_top_level_node())
01383 get_top_level_node()->zero_perturber_list();
01384
01385 } else {
01386
01387 // Check sizes of low-level binaries. In some circumstances
01388 // it is possible for the center of mass timestep of a
01389 // binary to become very small as its components recede,
01390 // with the result that the binary is never split up.
01391 // Explicitly attempt to avoid that here (Steve, 6/00).
01392
01393 if (check_binary_params(this) || check_binary_params(s))
01394 status = 6;
01395 }
01396
01397 #if 0
01398 if (system_time > 2295.905
01399 && node_contains(get_top_level_node(), "9530"))
01400 print_tree_structure(this);
01401 #endif
01402
01403 } else {
01404
01405 status = 0;
01406 }
01407 }
01408
01409 return status;
01410 }
1.2.6 written by Dimitri van Heesch,
© 1997-2001