Main Page   Class Hierarchy   Data Structures   File List   Data Fields   Globals  

sys_stats.C

Go to the documentation of this file.
00001 
00002        //=======================================================//    _\|/_
00003       //  __  _____           ___                    ___       //      /|\ ~
00004      //  /      |      ^     |   \  |         ^     |   \     //          _\|/_
00005     //   \__    |     / \    |___/  |        / \    |___/    //            /|\ ~
00006    //       \   |    /___\   |  \   |       /___\   |   \   // _\|/_
00007   //     ___/   |   /     \  |   \  |____  /     \  |___/  //   /|\ ~
00008  //                                                       //            _\|/_
00009 //=======================================================//              /|\ ~
00010 
00055 
00056 // ***  MUST make sure that the definitions of virial radius and virial  ***
00057 // ***  equilibrium are consistent between scale and sys_stats.          ***
00058 
00059 //   Note:  Because of the reference to libstar.a in sys_stats, the
00060 //          only global function in this file is sys_stats itself.
00061 //          Other "stats-related" functions are found in dyn_stats.C.
00062 //          Thus, any "dyn-only" tools referencing just the helper
00063 //          functions will not have to load the "star" libraries.
00064 
00065 #include "dyn.h"
00066 #include "star/sstar_to_dyn.h"
00067 
00068 #ifndef TOOLBOX
00069 
00070 local bool check_for_doubling(dyn* b)
00071 {
00072     if (getrq(b->get_log_story(), "fraction_of_masses_doubled") > 0)
00073         return true;
00074     else
00075         return false;
00076 }
00077 
00078 local real print_relaxation_time(dyn* b,
00079                                  real& potential_energy,
00080                                  real& kinetic_energy,
00081                                  void (*compute_energies)(dyn*, real,
00082                                                           real&, real&, real&,
00083                                                           bool))
00084 {
00085     // Print the relaxation time
00086 
00087     real r_virial, t_relax;
00088     real total_mass = 0;
00089     int N = b->n_leaves();
00090 
00091     for_all_leaves(dyn, b, bj)
00092         total_mass += bj->get_mass();
00093 
00094     real e_total;
00095     compute_energies(b, 0.0, potential_energy, kinetic_energy, e_total, true);
00096 
00097     // Potential energy here is internal potential energy.
00098 
00099     r_virial = -0.5 * total_mass * total_mass / potential_energy;
00100 
00101     // Note suspect choice of Lambda...
00102 
00103     t_relax = 9.62e-2 * sqrt(r_virial * r_virial * r_virial / total_mass)
00104               * N / log10(0.4 * N);
00105 
00106     PRI(4); PRL(r_virial);
00107     PRI(4); PRL(t_relax);
00108 
00109     return r_virial;
00110 }
00111 
00112 local bool print_numbers_and_masses(dyn* b)
00113 {
00114     // Numbers of stars and nodes:
00115 
00116     real total_cpu_time = getrq(b->get_log_story(), "total_cpu_time");
00117     if (total_cpu_time > -VERY_LARGE_NUMBER) {
00118         PRI(4); PRL(total_cpu_time);
00119     } else {
00120         PRI(4); cerr << "total_cpu_time = (undefined)" << endl;
00121     }
00122 
00123     int N = b->n_leaves();
00124     int N_top_level = b->n_daughters();
00125     cerr << "    N = " << N << "  N_top_level = " << N_top_level << endl;
00126 
00127     // Masses and averages:
00128 
00129     real total_mass_nodes = 0;
00130     for_all_daughters(dyn, b, bi)
00131         total_mass_nodes += bi->get_mass();
00132 
00133     real total_mass_leaves = 0;
00134     real m_min = VERY_LARGE_NUMBER, m_max = -m_min;
00135     for_all_leaves(dyn, b, bj) {
00136         total_mass_leaves += bj->get_mass();
00137         m_min = min(m_min, bj->get_mass());
00138         m_max = max(m_max, bj->get_mass());
00139     }
00140     real m_av = total_mass_leaves / max(1, N);
00141 
00142     cerr << "    total_mass = " << b->get_mass();
00143     cerr << "  nodes: " << total_mass_nodes;
00144     cerr << "  leaves: " << total_mass_leaves << endl;
00145 
00146     cerr << "    m_min = " << m_min << "  m_max = " << m_max
00147          << "  m_av = " << m_av << endl;
00148 
00149     return (m_min < m_max);
00150 }
00151 
00152 local void print_parameters_for_massive_black_holes(dyn *b,
00153                                                     real kT,
00154                                                     vector center,
00155                                                     bool verbose) {
00156 
00157   int n_bh = 0;
00158   for_all_daughters(dyn, b, bi) {
00159     if(find_qmatch(bi->get_log_story(), "black_hole")) {
00160 
00161       n_bh ++;
00162       bool long_binary_output = true;   
00163       print_binary_from_dyn_pair(b, bi,
00164                                  kT, center, verbose,
00165                                  long_binary_output);
00166     }
00167   }
00168 
00169   if(n_bh==0) {
00170     cerr << "           "
00171          << "   ---   "
00172          << "No massive black holes"
00173          << "   ---   ";
00174   }
00175 }
00176 
00177 
00178 
00179 local int which_zone(dyn* bi, vector& center_pos, int n_lagr, real* r_lagr)
00180 {
00181     vector dr = bi->get_pos() - center_pos;
00182     real dr2 = dr*dr;
00183 
00184     for (int j = 0; j < n_lagr; j++)
00185       if (r_lagr[j] > dr2) return j;
00186 
00187     return n_lagr;
00188 }
00189 
00190 local void print_numbers_and_masses_by_radial_zone(dyn* b, int which)
00191 {
00192     if (find_qmatch(b->get_dyn_story(), "n_lagr")) {
00193 
00194         // Make a list of previously computed lagrangian radii.
00195 
00196         int n_lagr = getiq(b->get_dyn_story(), "n_lagr");
00197         real *r_lagr = new real[n_lagr];
00198 
00199         getra(b->get_dyn_story(), "r_lagr", r_lagr, n_lagr);
00200 
00201         // Numbers of top-level nodes (leaves in multiple case):
00202 
00203         int *N = new int[n_lagr+1];
00204 
00205         // Note that r_lagr omits the 0% and 100% radii.
00206 
00207         // Masses and averages:
00208 
00209         real *total_mass_nodes = new real[n_lagr+1];
00210         real *m_min = new real[n_lagr+1];
00211         real *m_max = new real[n_lagr+1];
00212 
00213         // Initialization:
00214 
00215         for (int i = 0; i <= n_lagr; i++) {
00216             N[i] = 0;
00217             total_mass_nodes[i] = 0;
00218             m_min[i] = VERY_LARGE_NUMBER;
00219             m_max[i] = -VERY_LARGE_NUMBER;
00220             if (i < n_lagr) r_lagr[i] *= r_lagr[i];
00221         }
00222 
00223         // Use the same center as lagrad, or the geometric center
00224         // in case of error (shouldn't happen, as lagr_pos is written
00225         // whenever r_lagr is).
00226 
00227         vector center_pos = 0;
00228 
00229         if (find_qmatch(b->get_dyn_story(), "lagr_pos"))
00230             center_pos = getvq(b->get_dyn_story(), "lagr_pos");
00231         else
00232             warning(
00233             "print_numbers_and_masses_by_radial_zone: lagr_pos not found");
00234 
00235         int N_total = 0;
00236 
00237         // PRL(which);
00238 
00239         for_all_daughters(dyn, b, bi)
00240 
00241             // Count single stars and binaries separately.
00242             // Count single and doubled-mass stars separately also.
00243 
00244             if ( (which == 0 && bi->get_oldest_daughter() == NULL)
00245                 || (which == 1 && bi->get_oldest_daughter() != NULL)
00246                 || (which == 2 && getiq(bi->get_log_story(),
00247                                         "mass_doubled") == 0 )
00248                 || (which == 3 && getiq(bi->get_log_story(),
00249                                         "mass_doubled") == 1) ) {
00250                  //              || (which == 2)
00251                  //              || (which == 3) ) {
00252 
00253                 // Find which zone we are in.
00254 
00255                 int i = which_zone(bi, center_pos, n_lagr, r_lagr);
00256 
00257                 // Update statistics.
00258 
00259                 if (which != 1) {
00260                     N[i]++;
00261                     N_total++;
00262                 } else {
00263                     N[i] += bi->n_leaves();
00264                     N_total += bi->n_leaves();
00265                 }
00266 
00267                 total_mass_nodes[i] += bi->get_mass();
00268                 m_min[i] = min(m_min[i], bi->get_mass());
00269                 m_max[i] = max(m_max[i], bi->get_mass());
00270             }
00271 
00272         if (N_total > 0) {
00273 
00274             int i;
00275             for (i = 0; i <= n_lagr; i++) {
00276                 cerr << "    zone " << i << "  N = " << N[i];
00277                 if (N[i] > 0)
00278                     cerr << "  m_av = " << total_mass_nodes[i] / max(N[i], 1)
00279                          << "  m_min = " << m_min[i]
00280                          << "  m_max = " << m_max[i];
00281                 cerr << endl;
00282             }
00283 
00284             cerr << "\n  Cumulative:\n";
00285 
00286             int  Nc = 0;
00287             real m_totc = 0;
00288             real m_minc = VERY_LARGE_NUMBER;
00289             real m_maxc = -VERY_LARGE_NUMBER;
00290 
00291             for (i = 0; i <= n_lagr; i++) {
00292                 Nc += N[i];
00293                 m_totc += total_mass_nodes[i];
00294                 m_minc = min(m_minc, m_min[i]);
00295                 m_maxc = max(m_maxc, m_max[i]);
00296                 cerr << "    zone " << i << "  N = " << Nc;
00297                 if (Nc > 0)
00298                     cerr << "  m_av = " << m_totc / max(Nc, 1)
00299                          << "  m_min = " << m_minc
00300                          << "  m_max = " << m_maxc;
00301                 cerr << endl;
00302             }
00303 
00304         } else
00305 
00306             cerr << "    (none)\n";
00307 
00308         delete [] r_lagr;
00309         delete [] N;
00310         delete [] total_mass_nodes;
00311         delete [] m_min;
00312         delete [] m_max;
00313     }
00314 }
00315 
00316 local void print_anisotropy_by_radial_zone(dyn* b, int which)
00317 {
00318     if (find_qmatch(b->get_dyn_story(), "n_lagr")) {
00319 
00320         // Make a list of previously computed lagrangian radii.
00321 
00322         int n_lagr = getiq(b->get_dyn_story(), "n_lagr");
00323         real *r_lagr = new real[n_lagr];
00324         getra(b->get_dyn_story(), "r_lagr", r_lagr, n_lagr);
00325 
00326         real *total_weight = new real[n_lagr+1];
00327         real *vr2_sum = new real[n_lagr+1];
00328         real *vt2_sum = new real[n_lagr+1];
00329 
00330         // Note that r_lagr omits the 0% and 100% radii.
00331 
00332         // Initialization:
00333 
00334         for (int i = 0; i <= n_lagr; i++) {
00335             total_weight[i] = 0;
00336             vr2_sum[i] = 0;
00337             vt2_sum[i] = 0;
00338             if (i < n_lagr) r_lagr[i] *= r_lagr[i];
00339         }
00340 
00341         // Use the same center as lagrad, or the geometric center
00342         // in case of error (shouldn't happen, as lagr_pos is written
00343         // whenever r_lagr is).
00344 
00345         vector center_pos = 0, center_vel = 0;
00346         if (find_qmatch(b->get_dyn_story(), "lagr_pos"))
00347             center_pos = getvq(b->get_dyn_story(), "lagr_pos");
00348         else
00349             warning("print_anisotropy_by_radial_zone: lagr_pos not found");
00350 
00351         if (find_qmatch(b->get_dyn_story(), "lagr_vel"))
00352             center_vel = getvq(b->get_dyn_story(), "lagr_vel");
00353 
00354         int N_total = 0;
00355 
00356         // PRL(which);
00357 
00358         for_all_daughters(dyn, b, bi)
00359 
00360             // Count single stars and binaries separately.
00361 
00362             if ( (which == 0 && bi->get_oldest_daughter() == NULL)
00363                 || (which == 1 && bi->get_oldest_daughter() != NULL)
00364                 || (which == 2 && getiq(bi->get_log_story(),
00365                                         "mass_doubled") == 0)
00366                 || (which == 3 && getiq(bi->get_log_story(),
00367                                         "mass_doubled") == 1) ) {
00368 
00369                 // Find which zone we are in.
00370 
00371                 int i = which_zone(bi, center_pos, n_lagr, r_lagr);
00372 
00373                 // Update statistics.
00374 
00375                 N_total++;
00376 
00377                 real weight = bi->get_mass();
00378                 weight = 1;                     // Heggie/Binney & Tremaine
00379 
00380                 vector dr = bi->get_pos() - center_pos;
00381                 vector dv = bi->get_vel() - center_vel;
00382 
00383                 real r2 = square(dr);
00384                 real v2 = square(dv);
00385                 real vr = dr*dv;
00386 
00387                 real vr2 = 0;
00388                 if (r2 > 0) vr2 = vr * vr / r2;
00389 
00390                 total_weight[i] += weight;
00391                 vr2_sum[i] += weight * vr2;
00392                 vt2_sum[i] += weight * (v2 - vr2);              
00393             }
00394 
00395         if (N_total > 0) {
00396 
00397             int k;
00398             for (k = 0; k <= n_lagr; k += 5) {
00399                 if (k > 0) cerr << endl;
00400                 cerr << "           ";
00401                 for (int i = k; i < k+5 && i <= n_lagr; i++) {
00402                     if (vr2_sum[i] > 0)
00403                         cerr << " " << 1 - 0.5 * vt2_sum[i] / vr2_sum[i];
00404                     else
00405                         cerr << "   ---   ";
00406                 }
00407             }
00408             cerr << endl;
00409 
00410             cerr << "\n  Cumulative anisotropy:\n";
00411 
00412             real vr2c = 0;
00413             real vt2c = 0;
00414 
00415             for (k = 0; k <= n_lagr; k += 5) {
00416                 if (k > 0) cerr << endl;
00417                 cerr << "           ";
00418                 for (int i = k; i < k+5 && i <= n_lagr; i++) {
00419                     vr2c += vr2_sum[i];
00420                     vt2c += vt2_sum[i];
00421                     if (vr2c > 0)
00422                         cerr << " " << 1 - 0.5 * vt2c / vr2c;
00423                     else
00424                         cerr << "   ---   ";
00425                 }
00426             }
00427             cerr << endl;
00428 
00429         } else
00430 
00431             cerr << "    (none)\n";
00432 
00433         delete [] r_lagr;
00434         delete [] total_weight;
00435         delete [] vr2_sum;
00436         delete [] vt2_sum;
00437     }
00438 }
00439 
00440 // local real system_energy(dyn* b)
00441 // {
00442 //     real kin = 0;
00443 //     for_all_leaves(dyn, b, bj)
00444 //      kin += bj->get_mass()
00445 //              * square(something_relative_to_root(bj, &dyn::get_vel));
00446 //     kin *= 0.5;
00447 //
00448 //     real pot = 0.0;
00449 //     for_all_leaves(dyn, b, bi) {
00450 //      real dpot = 0.0;
00451 //      for_all_leaves(dyn, b, bj) {
00452 //          if (bj == bi) break;
00453 //          vector dx = something_relative_to_root(bi, &dyn::get_pos)
00454 //                        - something_relative_to_root(bj, &dyn::get_pos);
00455 //          dpot += bj->get_mass() / abs(dx);
00456 //      }
00457 //      pot -= bi->get_mass() * dpot;
00458 //     }
00459 //
00460 //     return kin + pot;
00461 // }
00462 
00463 local real top_level_kinetic_energy(dyn* b)
00464 {
00465     // (Probably should compute energy relative to density center,
00466     //  or at least relative to the system center of mass...)
00467 
00468     vector cmv = vector(0);
00469     real mass = 0;
00470 
00471     for_all_daughters(dyn, b, bb) {
00472         mass += bb->get_mass();
00473         cmv += bb->get_mass()*bb->get_vel();
00474     }
00475     cmv /= mass;
00476 
00477     real kin = 0;
00478     { for_all_daughters(dyn, b, bb)
00479         kin += bb->get_mass()*square(bb->get_vel()-cmv);
00480     }
00481 
00482     return 0.5*kin;
00483 }
00484 
00485 local void print_energies(dyn* b,
00486                           real& potential_energy,       // top-level
00487                           real& kinetic_energy,         // top-level
00488                           real& kT,
00489                           void (*compute_energies)(dyn*, real,
00490                                                    real&, real&, real&,
00491                                                    bool))
00492 {
00493     // Energies (top-level nodes):
00494 
00495     real e_total;
00496 
00497     if (kinetic_energy == 0)
00498         compute_energies(b, 0.0, potential_energy, kinetic_energy, e_total,
00499                          true);
00500 
00501     real total_int_energy = kinetic_energy + potential_energy;  // internal pot
00502     real external_pot = get_external_pot(b);
00503     e_total = total_int_energy + external_pot;
00504 
00505     vector com_pos, com_vel;
00506     compute_com(b, com_pos, com_vel);
00507     real kin_com = 0.5*b->get_mass()*square(com_vel);
00508 
00509     real kin_int = kinetic_energy - kin_com;
00510     real virial_ratio = -kin_int / (potential_energy
00511                                         + get_external_virial(b));
00512 
00513     kT = kin_int / (1.5*b->n_daughters());
00514 
00515     cerr << "    top-level nodes:\n";
00516     cerr << "        kinetic_energy = " << kin_int
00517          << "  potential_energy = " << potential_energy;
00518 
00519     if (external_pot == 0) {
00520         cerr << endl;
00521     } else {
00522         cerr << " (internal)" << endl;
00523 
00524         cerr << "        external_pot = " << external_pot << " (";
00525         print_external(b->get_external_field());
00526         cerr << ")" << endl;
00527         cerr << "        CM kinetic energy = " << kin_com << endl;
00528     }
00529 
00530     cerr << "        total energy = " << e_total
00531          << "  kT = " << kT << "  virial_ratio = " << virial_ratio
00532          << endl;
00533 
00534     real ke = kinetic_energy, pe = potential_energy;
00535 
00536     // Recompute energies, resolving any top-level nodes.
00537 
00538     e_total = total_int_energy;
00539 
00540     for_all_daughters(dyn, b, bb) {
00541         if (bb->is_parent()) {
00542             compute_energies(b, 0.0, pe, ke, e_total, false);
00543             break;
00544         }
00545     }
00546 
00547     e_total += external_pot;
00548     cerr << "    total energy (full system) = " << e_total
00549          << endl;
00550 }
00551 
00552 local void search_for_binaries(dyn* b, real energy_cutoff, real kT,
00553                                vector center, bool verbose,
00554                                bool long_binary_output)
00555 {
00556     // Search for bound binary pairs among top-level nodes.
00557 
00558     bool found = false;
00559 
00560     for_all_daughters(dyn, b, bi)
00561         for_all_daughters(dyn, b, bj) {
00562             if (bj == bi) break;
00563 
00564             real E = get_total_energy(bi, bj);
00565 
00566             // Convention: energy_cutoff is in terms of kT if set,
00567             //             in terms of E/mu if kT = 0.
00568 
00569             if ((kT > 0 && E < -energy_cutoff*kT)
00570                 || (kT <= 0 && E * (bi->get_mass() + bj->get_mass())
00571                         < -energy_cutoff * bi->get_mass() * bj->get_mass())) {
00572 
00573                 print_binary_from_dyn_pair(bi, bj,
00574                                            kT, center, verbose,
00575                                            long_binary_output);
00576                 cerr << endl;
00577 
00578                 found = true;
00579             }
00580         }
00581 
00582     if (!found) cerr << "    (none)\n";
00583 }
00584 
00585 
00586 // Histogram routines -- accumulate and print out key binary statistics.
00587 
00588 // Convenient to keep these global:
00589 
00590 #define P_MAX   0.1
00591 #define E_MIN   0.5
00592 #define NP      12
00593 #define NR      10
00594 #define NE      12
00595 
00596 static int p_histogram[NP][NR]; // first index:  log period
00597                                 // second index: radius
00598 
00599 static int e_histogram[NP][NR]; // first index:  log E/kT
00600                                 // second index: radius
00601 
00602 bool have_kT = false;
00603 
00604 local void initialize_histograms()
00605 {
00606     for (int ip = 0; ip < NP; ip++)
00607         for (int jr = 0; jr < NR; jr++)
00608             p_histogram[ip][jr] = e_histogram[ip][jr] = 0;
00609 }
00610 
00611 local void bin_recursive(dyn* bi,
00612                          vector center, real rcore, real rhalf,
00613                          real kT)
00614 {
00615     // Note: inner and outer multiple components are counted
00616     //        as separate binaries.
00617 
00618     have_kT = false;
00619     if (kT > 0) have_kT = true;
00620 
00621     for_all_nodes(dyn, bi, bb) {
00622         dyn* od = bb->get_oldest_daughter();
00623 
00624         if (od) {
00625 
00626             // Get period of binary with CM bb.
00627 
00628             bool del_kep = false;
00629 
00630             if (!od->get_kepler()) {
00631                 new_child_kepler(bb);
00632                 del_kep = true;
00633             }
00634 
00635             real P = od->get_kepler()->get_period();
00636             real R = abs(something_relative_to_root(bb, &dyn::get_pos)
00637                            - center);
00638             real mu = od->get_mass() * od->get_younger_sister()->get_mass()
00639                         / bb->get_mass();
00640             real E = -mu*od->get_kepler()->get_energy();
00641             if (kT > 0) E /= kT;
00642 
00643             if (del_kep) {
00644                 delete od->get_kepler();
00645                 od->set_kepler(NULL);
00646             }
00647 
00648             // Bin by P and R and by E and R.
00649 
00650             if (P > 0) {
00651 
00652                 // P bins are half dex, decreasing.
00653                 // P > P_MAX in bin 0, P_MAX >= P > 0.316 P_MAX in bin 1, etc.
00654 
00655                 int ip = (int) (1 - 2*log10(P/P_MAX));
00656                 if (ip < 0) ip = 0;
00657                 if (ip >= NP) ip = NP - 1;
00658 
00659                 int ir = 0;
00660                 if (R > rcore) {
00661 
00662                     // R bin 0 is the core.
00663                     // Linear binning in rcore < r < rhalf, logarithmic
00664                     // outside rhalf (x2); bin NR/2 has rhalf <= R < 2*rhalf.
00665 
00666                     if (R < rhalf) {
00667                         real x = R/rhalf;
00668                         ir = (int) (NR*x/2);
00669                         if (ir < 1) ir = 1;
00670                     } else {
00671                         real rlim = 2*rhalf;
00672                         ir = NR/2;
00673                         while (R > rlim) {
00674                             if (ir >= NR-1) break;
00675                             rlim *= 2;
00676                             ir++;
00677                         }
00678                     }
00679                 }
00680 
00681                 int ie = 0;
00682                 real elim = E_MIN;
00683 
00684                 // E bin 0 is 0 < E < 0.5 (kT), increase by factors of 2.
00685 
00686                 while (elim < E) {
00687                     ie++;
00688                     elim *= 2;
00689                     if (ie >= NE-1) break;
00690                 }
00691 
00692                 // Simply count binaries, for now.
00693 
00694                 p_histogram[ip][ir]++;
00695                 e_histogram[NE-1-ie][ir]++;     // histogram will be
00696                                                 // printed backwards
00697             }
00698         }
00699     }   
00700 }
00701 
00702 local void print_histogram(int histogram[][NR], int n, char *label)
00703 {
00704     cerr << endl
00705          << "  Binary distribution by " << label << " and radius:"
00706          << endl;
00707 
00708     PRI(13+5*n);
00709     cerr << "total" << endl;
00710 
00711     for (int jr = NR-1; jr >= 0; jr--) {
00712 
00713         if (jr == NR/2)
00714             cerr << "   Rhalf->";
00715         else if (jr == 0)
00716             cerr << "   core-> ";
00717         else
00718             PRI(10);
00719 
00720         int sum = 0;
00721         for (int i = n-1; i >= 0; i--) {
00722             fprintf(stderr, "%5d", histogram[i][jr]);
00723             sum += histogram[i][jr];
00724         }
00725         fprintf(stderr, "  %5d\n", sum);                // total by radius
00726     }
00727 
00728     cerr << endl << "   total  ";
00729 
00730     // Totals by column.
00731 
00732     int total = 0;
00733     for (int i = n-1; i >= 0; i--) {
00734         int sum = 0;
00735         for (int jr = NR-1; jr >= 0; jr--) sum += histogram[i][jr];
00736         fprintf(stderr, "%5d", sum);
00737         total += sum;
00738     }
00739 
00740     fprintf(stderr, "  %5d\n", total);                  // grand total
00741 }
00742 
00743 // Print out whatever histograms we have just accumulated.
00744 
00745 local void print_binary_histograms()
00746 {
00747     // Print period histogram...
00748 
00749     print_histogram(p_histogram, NP, "period");
00750 
00751     // ...and add caption.
00752 
00753     cerr << endl;
00754     PRI(14); cerr << "<";
00755     PRI((NP/2-1)*5-6); cerr << "period (0.5 dex)";
00756     PRI((NP/2)*5-13); cerr << "> " << P_MAX << endl;
00757 
00758     // Print energy histogram...
00759 
00760     print_histogram(e_histogram, NE, "energy");
00761 
00762     // ...and add caption.
00763 
00764     cerr << endl;
00765     PRI(11); cerr << "< "; fprintf(stderr, "%3.1f", E_MIN);
00766     PRI((NE/2-1)*5-4);
00767     if (have_kT)
00768         cerr << "E/kT (x 2)";
00769     else
00770         cerr << "E/mu (x 2)";
00771     PRI((NE/2)*5-8); cerr << ">" << endl;
00772 }
00773 
00774 
00775 local void print_binaries(dyn* b, real kT,
00776                           vector center, real rcore, real rhalf,
00777                           bool verbose,
00778                           bool long_binary_output = true,
00779                           void (*dstar_params)(dyn*) = NULL)
00780 {
00781     // Print out the properties of "known" binaries (i.e. binary subtrees),
00782     // and get some statistics on binaries in the core.  Note that *all*
00783     // binary subtrees are printed, regardless of energy.
00784     // Node b is the root node.
00785 
00786     // Printout occurs in four passes:  (0) perturbed multiples
00787     //                                  (1) unperturbed multiples
00788     //                                  (2) perturbed binaries
00789     //                                  (3) unperturbed binaries
00790 
00791     real eb = 0;
00792     real nb = 0;
00793     int n_unp = 0;
00794     real e_unp = 0;
00795 
00796     real mbcore = 0;
00797     int nbcore = 0;
00798 
00799     initialize_histograms();
00800 
00801     bool found = false;
00802 
00803     for (int pass = 0; pass < 4; pass++)
00804     for_all_daughters(dyn, b, bi) {
00805 
00806         dyn* od = bi->get_oldest_daughter();
00807 
00808         if (od &&
00809             (pass == 0 && bi->n_leaves()  > 2 && od->get_kepler() == NULL) ||
00810             (pass == 1 && bi->n_leaves()  > 2 && od->get_kepler() != NULL) ||
00811             (pass == 2 && bi->n_leaves() == 2 && od->get_kepler() == NULL) ||
00812             (pass == 3 && bi->n_leaves() == 2 && od->get_kepler() != NULL)) {
00813 
00814             if (verbose) {
00815                 if (od->get_kepler() == NULL)
00816                     cerr << "    ";
00817                 else
00818                     cerr << "  U ";
00819                 bi->pretty_print_node(cerr);
00820             }
00821 
00822             if (bi->n_leaves() > 2) {
00823 
00824                 if (verbose) cerr << "   is a multiple system:\n";
00825 
00826                 // Recursively print out the structure :
00827 
00828                 kepler k;
00829                 eb += print_structure_recursive(bi,
00830                                                 dstar_params,
00831                                                 n_unp, e_unp,
00832                                                 kT, center, &k, verbose);
00833 
00834                 bin_recursive(bi, center, rcore, rhalf, kT);
00835 
00836             } else {
00837 
00838                 int init_indent = BIN_INDENT - 4 - strlen(bi->format_label());
00839 
00840                 // if (verbose) {
00841                 //    if (od->get_kepler()) {
00842                 //      PRI(init_indent);
00843                 //      cerr << "is unperturbed (has a kepler pointer)"
00844                 //           << endl;
00845                 //
00846                 //      init_indent = BIN_INDENT;
00847                 //    }
00848                 // }
00849 
00850                 bool reset = false;
00851                 if (od->get_kepler() == NULL) {
00852                     new_child_kepler(bi);       // attach temporary kepler
00853                     reset = true;               // to oldest daughter
00854                 }
00855 
00856                 real dist_from_center = abs(bi->get_pos() - center);
00857 
00858                 eb += print_binary_params(od->get_kepler(), od->get_mass(),
00859                                           kT, dist_from_center, verbose,
00860                                           long_binary_output, init_indent);
00861                 nb++;
00862 
00863                 // Indirect reference to dstar output:
00864 
00865                 if (dstar_params != NULL)
00866                     dstar_params(bi);
00867 
00868                 if (rcore > 0) {
00869                     if (dist_from_center <= rcore) {
00870                         nbcore++;
00871                         mbcore += bi->get_mass();
00872                     }
00873                 }
00874 
00875                 bin_recursive(bi, center, rcore, rhalf, kT);
00876 
00877                 if (reset) {
00878                     delete od->get_kepler();
00879                     od->set_kepler(NULL);
00880                 }
00881 
00882                 // Virtual reference to additional binary output.
00883                 // Must do this *after* temporary keplers have been removed.
00884 
00885                 real e = od->print_pert(long_binary_output);
00886                 if (e != 0) {
00887                     n_unp++;
00888                     e_unp += e;
00889                 }
00890             }
00891 
00892             found = true;
00893         }
00894     }
00895 
00896     if (!found)
00897 
00898         cerr << "    (none)\n";
00899 
00900     else {
00901 
00902         if (verbose) cerr << endl;
00903         cerr << "  Total binary energy ("
00904              << nb << " binaries) = " << eb << endl;
00905 
00906         if (n_unp != 0) {
00907             cerr << "  Total unperturbed binary energy ("
00908                  << n_unp << " binaries) = " << e_unp << endl;
00909         }
00910 
00911         if (rcore > 0)
00912             cerr << "  nbcore = " << nbcore
00913                  << "  mbcore = " << mbcore << endl;
00914 
00915         print_binary_histograms();      // should this always be done, or
00916                                         // only when binary output is turned
00917                                         // on (as at present)?
00918                                         //
00919                                         // -- histograms are presently only
00920                                         //    computed if binary output is
00921                                         //    enabled
00922     }
00923 }
00924 
00925 local void print_core_parameters(dyn* b, bool allow_n_sq_ops,
00926                                  vector& density_center, real& rcore)
00927 {
00928     real mcore;
00929     int ncore;
00930 
00931     compute_core_parameters(b, 12, allow_n_sq_ops,
00932                             density_center, rcore, ncore, mcore);
00933 
00934     cerr << "    density_center = " << density_center << endl;
00935     cerr << "    rcore = " << rcore << "  ncore = " << ncore
00936          << "  mcore = " << mcore << endl;
00937 
00938     // Place the data in the root dyn story.
00939 
00940     putrq(b->get_dyn_story(), "core_radius_time", b->get_system_time());
00941     putrq(b->get_dyn_story(), "core_radius", rcore);
00942     putiq(b->get_dyn_story(), "n_core", ncore);
00943     putrq(b->get_dyn_story(), "m_core", mcore);
00944 }
00945 
00946 // Linear interpolation routine.
00947 
00948 local real linear_interpolation(const real x,
00949                                 const real x1, const real x2,
00950                                 const real y1, const real y2) {
00951 
00952         real a = (y2-y1)/(x2-x1);
00953         real b = y1 - a*x1;
00954 
00955         real y = a*x + b;
00956         return y;
00957 }
00958 
00959 #if 0
00960 // Currently in /star/util/kingfit.C
00961 
00962 // Fitting function for N-body Rc/Rvir to King's concentration parameter c.
00963 // Argument is core radius / virial radius.
00964 
00965 local real kingCfit(const real rc_rvir) {
00966 
00967   int nfit = 12;
00968   real WoKing[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
00969   real Cking[] = {0., 0.295643, 0.505349, 0.673898, 0.840487,
00970                   1.03059, 1.25598, 1.5284, 1.83414, 2.12028,
00971                   2.35155, 2.5495, 2.7396};
00972   real Rc_Rvir[] = {1., 0.497, 0.492, 0.428, 0.376, 0.314,
00973                     0.241, 0.179, 0.110, 0.0568, 0.0369,
00974                     0.0185, 0.0129};
00975 
00976   if (rc_rvir>=Rc_Rvir[1])
00977     return 0;
00978   else if(rc_rvir<=Rc_Rvir[nfit])
00979     return 3;
00980   else
00981     for (int i=1; i<=nfit; i++)
00982       if (rc_rvir>=Rc_Rvir[i])
00983         return linear_interpolation(rc_rvir,
00984                                     Rc_Rvir[i-1], Rc_Rvir[i],
00985                                     Cking[i-1], Cking[i]);
00986   return 0;
00987 }
00988 
00989 // Fitting function for N-body Rc/Rvir to King's dimentionless Wo.
00990 // Argument is core radius / virial radius.
00991 
00992 local real kingWfit(const real rc_rvir) {
00993 
00994   int nfit = 12;
00995   real WoKing[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
00996   real Rc_Rvir[] = {1., 0.497, 0.492, 0.428, 0.376, 0.314,
00997                     0.241, 0.179, 0.110, 0.0568, 0.0369,
00998                     0.0185, 0.0129};
00999 
01000   if (rc_rvir>=Rc_Rvir[1])
01001     return 1;
01002   else if (rc_rvir <= Rc_Rvir[nfit])
01003     return 12;
01004   else
01005     for (int i=1; i<=nfit; i++)
01006       if (rc_rvir >= Rc_Rvir[i])
01007         return  linear_interpolation(rc_rvir,
01008                                      Rc_Rvir[i-1], Rc_Rvir[i],
01009                                      WoKing[i-1], WoKing[i]);
01010   return 1;
01011 }
01012 
01013 local void print_king_parameters(const real rc_rvir) {
01014 
01015   real Wo = kingWfit(rc_rvir);
01016   real C  = kingCfit(rc_rvir);
01017 
01018     PRI(4); cerr << "Wo = " << Wo
01019                  << "  c = " << C
01020                  << endl;
01021 
01022 }
01023 
01024 #endif
01025 
01026 local bool testnode(dyn * b)
01027 {
01028     if (b->is_top_level_node())
01029         return true;
01030     else
01031         return false;
01032 }
01033 
01034 local bool binary_fn(dyn * b)
01035 {
01036     if (b->get_oldest_daughter())
01037         return true;
01038     else
01039         return false;
01040 }
01041 
01042 local bool single_fn(dyn * b)
01043 {
01044     if (getiq(b->get_log_story(), "mass_doubled") == 0)
01045         return true;
01046     else
01047         return false;
01048 }
01049 
01050 local bool double_fn(dyn * b)
01051 {
01052     if (getiq(b->get_log_story(), "mass_doubled") == 1)
01053         return true;
01054     else
01055         return false;
01056 }
01057 
01058 local real print_lagrangian_radii(dyn* b, int which_lagr,
01059                                   bool verbose = true, int which_star = 0)
01060 {
01061     bool nonlin = false;
01062 
01063     real rhalf = 1;
01064     int ihalf;
01065 
01066     int nl, indent;
01067     if (which_lagr == 0) {
01068         nl = 4;
01069         indent = 15;
01070         ihalf = 1;
01071     } else if (which_lagr == 1) {
01072         nl = 10;
01073         indent = 20;
01074         ihalf = 4;
01075     } else {
01076         nl = 10;
01077         indent = 26;
01078         nonlin = true;
01079         ihalf = 6;
01080     }
01081 
01082     if (which_star == 0)
01083         compute_general_mass_radii(b, nl, nonlin);
01084     else if (which_star == 1)
01085         compute_general_mass_radii(b, nl, nonlin, binary_fn);
01086     else if (which_star == 2)
01087         compute_general_mass_radii(b, nl, nonlin, single_fn);
01088     else if (which_star == 3)
01089         compute_general_mass_radii(b, nl, nonlin, double_fn);
01090 
01091     if (find_qmatch(b->get_dyn_story(), "n_lagr")
01092         && getrq(b->get_dyn_story(), "lagr_time") == b->get_system_time()) {
01093 
01094         // Assume that lagr_pos has been properly set if n_lagr is set
01095         // and lagr_time is current.
01096 
01097         vector lagr_pos = getvq(b->get_dyn_story(), "lagr_pos");
01098 
01099         if (verbose) {
01100             cerr << endl << "  Lagrangian radii relative to ("
01101                  << lagr_pos << "):" << endl;
01102             if (find_qmatch(b->get_dyn_story(), "pos_type"))
01103                 cerr << "                               ( = "
01104                      << getsq(b->get_dyn_story(), "pos_type")
01105                      << ")" << endl;
01106             if (which_lagr == 0)
01107                 cerr << "    quartiles: ";
01108             else if (which_lagr == 1)
01109                 cerr << "    10-percentiles: ";
01110             else
01111                 cerr << "    selected percentiles: ";
01112         }
01113 
01114         int n_lagr = getiq(b->get_dyn_story(), "n_lagr");  // should be nl - 1
01115         real *r_lagr = new real[n_lagr];
01116 
01117         getra(b->get_dyn_story(), "r_lagr", r_lagr, n_lagr);
01118 
01119         for (int k = 0; k < n_lagr; k += 5) {
01120             if (k > 0) {
01121                 cerr << endl;
01122                 for (int kk = 0; kk < indent; kk++) cerr << " ";
01123             }
01124             for (int i = k; i < k+5 && i < n_lagr; i++)
01125                 cerr << " " << r_lagr[i];
01126         }
01127         cerr << endl << flush;
01128 
01129         rhalf = r_lagr[ihalf];
01130         delete [] r_lagr;
01131     }
01132     return rhalf;
01133 }
01134 
01135 //-----------------------------------------------------------------------------
01136 //
01137 // Local functions for dominated ("disk") motion:
01138 
01139 local dyn* dominant_mass(dyn* b, real f)
01140 {
01141     // Return a pointer to the most massive top-level node contributing
01142     // more than fraction f of the total mass.
01143 
01144     real total_mass = 0, max_mass = 0;
01145     dyn* b_dom;
01146 
01147     for_all_daughters(dyn, b, bi) {
01148         total_mass += bi->get_mass();
01149         if (bi->get_mass() > max_mass) {
01150             max_mass = bi->get_mass();
01151             b_dom = bi;
01152         }
01153     }
01154 
01155     if (max_mass < f*total_mass)
01156         return NULL;
01157     else
01158         return b_dom;
01159 }
01160 
01161 typedef  struct
01162 {
01163     real  radius;
01164     real  mass;
01165 } rm_pair, *rm_pair_ptr;
01166 
01167 //-----------------------------------------------------------------------------
01168 //  compare_radii  --  compare the radii of two particles
01169 //-----------------------------------------------------------------------------
01170 
01171 local int compare_radii(const void * pi, const void * pj)  // increasing radius
01172 {
01173     if (((rm_pair_ptr) pi)->radius > ((rm_pair_ptr) pj)->radius)
01174         return +1;
01175     else if (((rm_pair_ptr)pi)->radius < ((rm_pair_ptr)pj)->radius)
01176         return -1;
01177     else
01178         return 0;
01179 }
01180 
01181 local void print_dominated_lagrangian_radii(dyn* b, dyn* b_dom)
01182 {
01183     // Compute and print 10, 20, 30, ..., 90% radii of current system,
01184     // taking particle b_dom as the center.
01185 
01186     if (!b_dom) return;
01187 
01188     int n = 0;
01189     { for_all_daughters(dyn, b, bi)
01190         if (bi != b_dom) n++;
01191     }
01192 
01193     // Set up an array of (radius, mass) pairs.  Also find the total
01194     // mass of all nodes under consideration.
01195 
01196     rm_pair_ptr rm_table = new rm_pair[n];
01197 
01198     if (rm_table == NULL) {
01199         cerr << "print_dominated_lagrangian_radii: "
01200              << "not enough memory left for rm_table\n";
01201         return;
01202     }
01203 
01204     real total_mass = 0;
01205     int i = 0;
01206 
01207     for_all_daughters(dyn, b, bi)
01208         if (bi != b_dom) {
01209             vector dr = bi->get_pos() - b_dom->get_pos();
01210 
01211             // "Radius" is 2-D (x-y) only.
01212 
01213             dr[2] = 0;
01214 
01215             total_mass += bi->get_mass();
01216             rm_table[i].radius = abs(dr);
01217             rm_table[i].mass = bi->get_mass();
01218             i++;
01219         }
01220 
01221     // Sort the array by radius.
01222 
01223     qsort((void *)rm_table, (size_t)i, sizeof(rm_pair), compare_radii);
01224 
01225     // Print out the percentile radii:
01226 
01227     cerr << endl << "  Lagrangian radii: ";
01228 
01229     real cumulative_mass = 0.0;
01230     i = 0;
01231 
01232     for (int k = 1; k <= 9; k++) {
01233 
01234         while (cumulative_mass < 0.1*k*total_mass)
01235             cumulative_mass += rm_table[i++].mass;
01236 
01237         cerr << " " << rm_table[i-1].radius;
01238         if (k == 5) cerr << endl << "                    ";
01239     }
01240     cerr << endl;
01241 }
01242 
01243 local void print_dominated_velocity_dispersions(dyn* b, dyn* b_dom)
01244 {
01245 
01246     // Compute and print system velocity dispersions in the radial,
01247     // transverse, and vertical (z) directions.
01248 
01249     // Assume that dominated motion is primarily in the x-y plane,
01250     // and compute the transverse dispersion relative to keplerian
01251     // motion.
01252 
01253     if (!b_dom) return;
01254 
01255     real total_mass = 0;
01256     real v2r = 0, v2t = 0, v2z = 0;
01257 
01258     for_all_daughters(dyn, b, bi)
01259         if (bi != b_dom) {
01260             vector dr = bi->get_pos() - b_dom->get_pos();
01261             vector dv = bi->get_vel() - b_dom->get_vel();
01262 
01263             total_mass += bi->get_mass();
01264             v2z += bi->get_mass() * dv[2]*dv[2];
01265 
01266             // Restrict motion to x-y plane and subtract off
01267             // keplerian motion in the positive sense.
01268 
01269             dr[2] = 0;
01270             dv[2] = 0;
01271             real r = abs(dr);
01272 
01273             if (r > 0) {
01274                 real vr = dr*dv/r;
01275 
01276                 // Subtract off keplerian motion.
01277 
01278                 real vkep = sqrt(b_dom->get_mass()/r);
01279                 dv[0] -= -dr[1]*vkep/r;
01280                 dv[1] -=  dr[0]*vkep/r;
01281 
01282                 v2r += bi->get_mass() * vr*vr;
01283                 v2t += bi->get_mass() * (dv*dv - vr*vr);
01284             }
01285         }
01286 
01287     if (total_mass > 0)
01288         cerr << endl << "  Velocity dispersions:  "
01289              << sqrt(v2r/total_mass) << "  "
01290              << sqrt(v2t/total_mass) << "  "
01291              << sqrt(v2z/total_mass)
01292              << endl;
01293 }
01294 
01295 //-----------------------------------------------------------------------------
01296 
01297 bool parse_sys_stats_main(int argc, char *argv[],
01298                           int &which_lagr,
01299                           bool &binaries,
01300                           bool &long_binary_output,
01301                           bool &B_flag,
01302                           bool &calc_e,
01303                           bool &n_sq,
01304                           bool &out,
01305                           bool &verbose)
01306 {
01307     // Parse the sys_stats command-line (used by both dyn and hdyn versions).
01308 
01309     // Set standard defaults for standalone tools:
01310 
01311     which_lagr = 2;                     // print nonlinear Lagrangian zones
01312 
01313     binaries = true;                    // print binary output
01314     B_flag = false;                     // force binary evolution (hdyn version)
01315     calc_e = true;                      // compute energy
01316     n_sq = true;                        // allow n^2 operations
01317     out = false;                        // write cin to cout
01318     long_binary_output = true;          // long binary output
01319     verbose = true;                     // extended output
01320 
01321     extern char *poptarg;
01322     int c;
01323     char* param_string = "b.Bnel.o";    // note: "v" removed because only the
01324                                         // "verbose = true" option works!
01325 
01326     while ((c = pgetopt(argc, argv, param_string)) != -1)
01327         switch(c) {
01328 
01329             case 'b': {int b = 1;
01330                       if (poptarg) b = atoi(poptarg);
01331                       if (b == 0) {
01332                           binaries = false;
01333                           long_binary_output = false;
01334                       } else if (b == 1) {
01335                           binaries = true;
01336                           long_binary_output = false;
01337                       } else {
01338                           binaries = true;
01339                           long_binary_output = true;
01340                       }}
01341             case 'B': B_flag = true;
01342                       break;
01343             case 'e': calc_e = false;
01344                       break;
01345             case 'l': if (poptarg)
01346                           which_lagr = atoi(poptarg);
01347                       else
01348                           which_lagr = 2;
01349                       break;
01350             case 'n': n_sq = false;
01351                       break;
01352             case 'o': out = true;
01353                       break;
01354             case 'v': verbose = false;
01355                       break;
01356             case '?': params_to_usage(cerr, argv[0], param_string);
01357                       return false;
01358         }
01359 
01360     return true;
01361 }
01362 
01363 void sys_stats(dyn* b,
01364                real energy_cutoff,                      // default = 1
01365                bool verbose,                            // default = true
01366                bool binaries,                           // default = true
01367                bool long_binary_output,                 // default = false
01368                int which_lagr,                          // default = 0
01369                bool print_time,                         // default = false
01370                bool compute_energy,                     // default = false
01371                bool allow_n_sq_ops,                     // default = false
01372                void (*compute_energies)(dyn*, real,     // default = calculate_
01373                                         real&, real&,   //              energies
01374                                         real&, bool),
01375                void (*dstar_params)(dyn*),              // default = NULL
01376                bool (*print_dstar_stats)(dyn*, bool,    // default = NULL
01377                                          vector, bool))
01378 
01379 // The last three arguments are a nasty C way of allowing this dyn function
01380 // to output additional dyn/dstar information when called from kira and
01381 // other hdyn programs.
01382 
01383 {
01384     int p = cerr.precision(STD_PRECISION);
01385 
01386     if (print_time) {
01387 
01388         real time = getrq(b->get_dyn_story(), "t");
01389         if (time <= -VERY_LARGE_NUMBER)
01390             time = b->get_system_time();
01391 
01392         if (time > -VERY_LARGE_NUMBER)
01393             cerr << "Time = " << time << endl;
01394         else
01395             cerr << "Time = (undefined)" << endl;
01396 
01397         if (b->get_use_sstar())
01398             print_sstar_time_scales(b);
01399     }
01400 
01401     if (verbose) cerr << "\n  Overall parameters:\n";
01402     bool mass_spectrum = print_numbers_and_masses(b);
01403 
01404     vector com_pos, com_vel;
01405     compute_com(b, com_pos, com_vel);
01406     cerr << "    center of mass position = " << com_pos << endl
01407          << "                   velocity = " << com_vel << endl;
01408 
01409     bool heavy_stars = check_for_doubling(b);
01410     // PRI(4); PRL(heavy_stars);
01411 
01412     real kinetic_energy = 0, potential_energy = 0;
01413 
01414     real r_virial = -1;
01415     if (compute_energy)                         // Need virial radius for tR
01416         r_virial  = print_relaxation_time(b, potential_energy, kinetic_energy,
01417                                           compute_energies);
01418 
01419     // NB:  If set, potential energy here is internal potential energy.
01420 
01421     if (r_virial == -1) {
01422         if (find_qmatch(b->get_dyn_story(), "energy_time")
01423             && getrq(b->get_dyn_story(), "energy_time")
01424                                  == b->get_system_time()) {
01425 
01426             // Take energies from the dyn story.
01427 
01428             if (find_qmatch(b->get_dyn_story(), "kinetic_energy")
01429                 && find_qmatch(b->get_dyn_story(), "kinetic_energy")) {
01430 
01431                 kinetic_energy = getrq(b->get_dyn_story(), "kinetic_energy");
01432                 potential_energy = getrq(b->get_dyn_story(),
01433                                          "potential_energy");
01434                 if (potential_energy < 0)
01435                     r_virial = -0.5*b->get_mass()*b->get_mass()
01436                                         / potential_energy;
01437             }
01438         }
01439     }
01440 
01441     // Note: even if allow_n_sq_ops is false, we can still compute kT
01442     // from the kinetic energy.
01443 
01444     real kT = 0;
01445 
01446     if (compute_energy)                                 // recompute energies
01447 
01448         print_energies(b, potential_energy, kinetic_energy, kT,
01449                        compute_energies);
01450 
01451     else if (b->get_oldest_daughter())
01452 
01453         kT = top_level_kinetic_energy(b) / (1.5*b->n_daughters());
01454 
01455     PRI(4); PRL(kT);
01456 
01457     vector center = com_pos;
01458     real rcore = 0, rhalf = 0;
01459 
01460     // "Dominant" mass means > 50% of the total mass of the system.
01461 
01462     dyn* b_dom = dominant_mass(b, 0.5);
01463 
01464     if (!b_dom) {
01465 
01466         // No dominant mass.
01467 
01468         bool has_densities = (getrq(b->get_dyn_story(), "density_time")
01469                                == b->get_system_time());
01470 
01471         if (has_densities || allow_n_sq_ops) {
01472 
01473             // cerr << "Compute densities" << endl;     // ???
01474 
01475             // Function compute_core_parameters will look in the dyn story
01476             // for densities and use them if they are current.  It will
01477             // only do O(N^2) operations if no current densities are found
01478             // and allow_n_sq_ops is true.
01479 
01480             if (verbose) {
01481                 cerr << "\n  Core parameters";
01482                 if (has_densities)
01483                     cerr << " (densities from input snapshot)";
01484                 cerr << ":\n";
01485             }
01486 
01487             // Core parameters are always expressed relative to the
01488             // (mean) density center.
01489 
01490             print_core_parameters(b, allow_n_sq_ops, center, rcore);
01491 
01492             if (rcore > 0 && r_virial > 0) {
01493                 if (verbose) cerr << "\n  Dynamical King parameters:\n";
01494                 print_fitted_king_model(rcore/r_virial, rcore_rvirial);
01495             }
01496         }
01497 
01498         // If core parameters were computed, then center now is the mean
01499         // density center.  If not, then center is the center of mass.
01500         // However, this value of center is presently not used, as the
01501         // vector will be set equal to lagr_pos below.
01502         //
01503         // The vector lagr_pos is set when the Lagrangian radii are
01504         // computed; lagr_pos and the associated Lagrangian radii are
01505         // used internally by *all* functions which print quantities
01506         // by radial zone.
01507 
01508         // final variable which = 0 : single stars/CMs
01509         //                      = 1 : binaries
01510         //                      = 2 : light stars (heavy_stars = true)
01511         //                      = 3 : heavy stars (heavy_stars = true)
01512 
01513         rhalf = print_lagrangian_radii(b, which_lagr, verbose, 0);
01514 
01515         // cerr << "first Lagrangian radii calc, all stars" << endl;
01516 
01517         // PRL(heavy_stars);
01518 
01519         if (verbose) {
01520             if (heavy_stars) {
01521                 cerr << "\n  Lagrangian radii (light stars):\n";
01522                 print_lagrangian_radii(b, which_lagr, verbose, 2);
01523                 cerr << "\n  Lagrangian radii (heavy stars):\n";
01524                 print_lagrangian_radii(b, which_lagr, verbose, 3);
01525             }
01526         }
01527 
01528         if (mass_spectrum) {
01529 
01530             if (verbose)
01531                 cerr << endl
01532                      << "  Mass distribution by Lagrangian zone (singles):"
01533                      << endl;
01534             print_numbers_and_masses_by_radial_zone(b, 0);
01535 
01536             if (verbose)
01537                 cerr << endl
01538                      << "  Mass distribution by Lagrangian zone (multiples):"
01539                      << endl;
01540             print_numbers_and_masses_by_radial_zone(b, 1);
01541 
01542         }
01543 
01544         bool black_hole = true;
01545         if(black_hole) {
01546           if (verbose)
01547             cerr << endl
01548                  << "  Orbital parameters for massive black holes:"
01549                  << endl;
01550             print_parameters_for_massive_black_holes(b, kT, center, verbose);
01551         }       
01552 
01553         if (verbose)
01554             cerr << "\n  Anisotropy by Lagrangian zone (singles):\n";
01555         print_anisotropy_by_radial_zone(b, 0);
01556 
01557         if (verbose)
01558             cerr << "\n  Anisotropy by Lagrangian zone (multiple CMs):\n";
01559         print_anisotropy_by_radial_zone(b, 1);
01560 
01561         if (heavy_stars && verbose) {
01562             // if (verbose)
01563             cerr << endl
01564                  << "  Mass distribution by Lagrangian zone (light stars):"
01565                  << endl;
01566             print_numbers_and_masses_by_radial_zone(b, 2);
01567 
01568             // if (verbose)
01569             cerr << endl
01570                  << "  Mass distribution by Lagrangian zone (heavy stars):"
01571                  << endl;
01572             print_numbers_and_masses_by_radial_zone(b, 3);
01573 
01574             // if (verbose)
01575             cerr << "\n  Anisotropy by Lagrangian zone (light stars):\n";
01576             print_anisotropy_by_radial_zone(b, 2);
01577 
01578             // if (verbose)
01579             cerr << "\n  Anisotropy by Lagrangian zone (heavy stars):\n";
01580             print_anisotropy_by_radial_zone(b, 3);
01581         }
01582 
01583     } else {
01584 
01585         // Node b_dom dominates the motion ("central black hole").
01586 
01587         center = b_dom->get_pos();
01588         putvq(b->get_dyn_story(), "lagr_pos", center);
01589 
01590         // Assume we have a disk system of some sort, and that the
01591         // primary plane is x-y.  All functions relating to this
01592         // option are currently local, but may be made global later,
01593         // if appropriate.
01594 
01595         cerr << endl << "  Motion dominated by node "
01596              << b_dom->format_label() << endl
01597              << "      (mass = " << b_dom->get_mass()
01598              << ",  pos = " << center << ")" << endl;
01599         cerr << "  Taking x-y plane as plane of symmetry." << endl;
01600 
01601         print_dominated_lagrangian_radii(b, b_dom);
01602         print_dominated_velocity_dispersions(b, b_dom);
01603     }
01604 
01605     bool sstar = b->get_use_sstar();
01606 
01607     if (print_dstar_stats != NULL)
01608         sstar = !print_dstar_stats(b, mass_spectrum, center, verbose);
01609 
01610     if (sstar)
01611           sstar_stats(b, mass_spectrum, center, verbose);
01612 
01613     if (binaries) {
01614 
01615         // Use the same center as used by the Lagrangian radii functions.
01616 
01617         if (find_qmatch(b->get_dyn_story(), "lagr_pos"))
01618             center = getvq(b->get_dyn_story(), "lagr_pos");
01619         else
01620             warning("sys_stats: lagr_pos not found");
01621 
01622         set_kepler_tolerance(2);        // avold termination on error
01623 
01624         if (verbose) {
01625             cerr << endl;
01626             cerr << "  Binaries/multiples";
01627             if (!long_binary_output) cerr << " (short output)";
01628             cerr << ":" << endl;
01629         }
01630 
01631         print_binaries(b, kT, center, rcore, rhalf,
01632                        verbose, long_binary_output, dstar_params);
01633 
01634         if (allow_n_sq_ops) {
01635 
01636             if (verbose) {
01637                 cerr << "\n  Other bound pairs with ";
01638                 if (kT > 0)
01639                     cerr << "|E| > " << energy_cutoff << " kT:\n";
01640                 else
01641                     cerr << "|E/mu| > " << energy_cutoff << ":\n";
01642             }
01643             search_for_binaries(b, energy_cutoff, kT,
01644                                 center, verbose, long_binary_output);
01645 
01646         } else {
01647 
01648             // Do an NN search for binaries (hdyn only).
01649 
01650             int which = 0;
01651             bool found = false;
01652             for_all_daughters(dyn, b, bb)
01653                 found |= bb->nn_stats(energy_cutoff, kT,   // Dummy function for
01654                                       center, verbose,     // dyn; get NN binary
01655                                       long_binary_output,  // info for hdyn
01656                                       which++);
01657             if (!found)
01658                 cerr << "    (none)\n";
01659         }
01660     }
01661 
01662     cerr.precision(p);
01663 
01664     // Finally, refine estimates of the cluster mass (moved here from hdyn...)
01665 
01666     refine_cluster_mass(b, 1);
01667 }
01668 
01669 #else
01670 
01671 main(int argc, char **argv)
01672 {
01673     check_help();
01674 
01675     bool binaries, long_binary_output, B_flag, verbose, out, n_sq, calc_e;
01676     int which_lagr;
01677 
01678     if (!parse_sys_stats_main(argc, argv,
01679                               which_lagr,
01680                               binaries, long_binary_output, B_flag,
01681                               calc_e, n_sq, out, verbose)) {
01682         get_help();
01683         exit(1);
01684     }
01685 
01686     // For dyn version, calc_e requires n_sq.
01687 
01688     if (!n_sq) calc_e = false;
01689 
01690     // Loop over input until no more data remain.
01691 
01692     dyn *b;
01693     int i = 0;
01694 
01695     while (b = get_dyn(cin)) { // NB:  get_xxx() reads NaN as legal garbage...
01696 
01697         check_addstar(b);
01698         check_set_external(b, true);    // true ==> verbose output
01699         cerr << endl;
01700 
01701         if (i++ > 0) cerr << endl;
01702         sys_stats(b, 0.5, verbose, binaries, long_binary_output,
01703                   which_lagr, true, calc_e, n_sq);
01704 
01705         if (out) put_node(cout, *b);
01706         rmtree(b);
01707     }
01708 }
01709 
01710 #endif
01711 

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