00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00055
00056
00057
00058
00059
00060
00061
00062
00063
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
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
00098
00099 r_virial = -0.5 * total_mass * total_mass / potential_energy;
00100
00101
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
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
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
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
00202
00203 int *N = new int[n_lagr+1];
00204
00205
00206
00207
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
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
00224
00225
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
00238
00239 for_all_daughters(dyn, b, bi)
00240
00241
00242
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
00251
00252
00253
00254
00255 int i = which_zone(bi, center_pos, n_lagr, r_lagr);
00256
00257
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
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
00331
00332
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
00342
00343
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
00357
00358 for_all_daughters(dyn, b, bi)
00359
00360
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
00370
00371 int i = which_zone(bi, center_pos, n_lagr, r_lagr);
00372
00373
00374
00375 N_total++;
00376
00377 real weight = bi->get_mass();
00378 weight = 1;
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
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463 local real top_level_kinetic_energy(dyn* b)
00464 {
00465
00466
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,
00487 real& kinetic_energy,
00488 real& kT,
00489 void (*compute_energies)(dyn*, real,
00490 real&, real&, real&,
00491 bool))
00492 {
00493
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;
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
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
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
00567
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
00587
00588
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];
00597
00598
00599 static int e_histogram[NP][NR];
00600
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
00616
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
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
00649
00650 if (P > 0) {
00651
00652
00653
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
00663
00664
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
00685
00686 while (elim < E) {
00687 ie++;
00688 elim *= 2;
00689 if (ie >= NE-1) break;
00690 }
00691
00692
00693
00694 p_histogram[ip][ir]++;
00695 e_histogram[NE-1-ie][ir]++;
00696
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);
00726 }
00727
00728 cerr << endl << " total ";
00729
00730
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);
00741 }
00742
00743
00744
00745 local void print_binary_histograms()
00746 {
00747
00748
00749 print_histogram(p_histogram, NP, "period");
00750
00751
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
00759
00760 print_histogram(e_histogram, NE, "energy");
00761
00762
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
00782
00783
00784
00785
00786
00787
00788
00789
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
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
00841
00842
00843
00844
00845
00846
00847
00848
00849
00850 bool reset = false;
00851 if (od->get_kepler() == NULL) {
00852 new_child_kepler(bi);
00853 reset = true;
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
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
00883
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();
00916
00917
00918
00919
00920
00921
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
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
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
00961
00962
00963
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
00990
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
01095
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");
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
01138
01139 local dyn* dominant_mass(dyn* b, real f)
01140 {
01141
01142
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
01169
01170
01171 local int compare_radii(const void * pi, const void * pj)
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
01184
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
01194
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
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
01222
01223 qsort((void *)rm_table, (size_t)i, sizeof(rm_pair), compare_radii);
01224
01225
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
01247
01248
01249
01250
01251
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
01267
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
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
01308
01309
01310
01311 which_lagr = 2;
01312
01313 binaries = true;
01314 B_flag = false;
01315 calc_e = true;
01316 n_sq = true;
01317 out = false;
01318 long_binary_output = true;
01319 verbose = true;
01320
01321 extern char *poptarg;
01322 int c;
01323 char* param_string = "b.Bnel.o";
01324
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,
01365 bool verbose,
01366 bool binaries,
01367 bool long_binary_output,
01368 int which_lagr,
01369 bool print_time,
01370 bool compute_energy,
01371 bool allow_n_sq_ops,
01372 void (*compute_energies)(dyn*, real,
01373 real&, real&,
01374 real&, bool),
01375 void (*dstar_params)(dyn*),
01376 bool (*print_dstar_stats)(dyn*, bool,
01377 vector, bool))
01378
01379
01380
01381
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
01411
01412 real kinetic_energy = 0, potential_energy = 0;
01413
01414 real r_virial = -1;
01415 if (compute_energy)
01416 r_virial = print_relaxation_time(b, potential_energy, kinetic_energy,
01417 compute_energies);
01418
01419
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
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
01442
01443
01444 real kT = 0;
01445
01446 if (compute_energy)
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
01461
01462 dyn* b_dom = dominant_mass(b, 0.5);
01463
01464 if (!b_dom) {
01465
01466
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
01474
01475
01476
01477
01478
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
01488
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
01499
01500
01501
01502
01503
01504
01505
01506
01507
01508
01509
01510
01511
01512
01513 rhalf = print_lagrangian_radii(b, which_lagr, verbose, 0);
01514
01515
01516
01517
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
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
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
01575 cerr << "\n Anisotropy by Lagrangian zone (light stars):\n";
01576 print_anisotropy_by_radial_zone(b, 2);
01577
01578
01579 cerr << "\n Anisotropy by Lagrangian zone (heavy stars):\n";
01580 print_anisotropy_by_radial_zone(b, 3);
01581 }
01582
01583 } else {
01584
01585
01586
01587 center = b_dom->get_pos();
01588 putvq(b->get_dyn_story(), "lagr_pos", center);
01589
01590
01591
01592
01593
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
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);
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
01649
01650 int which = 0;
01651 bool found = false;
01652 for_all_daughters(dyn, b, bb)
01653 found |= bb->nn_stats(energy_cutoff, kT,
01654 center, verbose,
01655 long_binary_output,
01656 which++);
01657 if (!found)
01658 cerr << " (none)\n";
01659 }
01660 }
01661
01662 cerr.precision(p);
01663
01664
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
01687
01688 if (!n_sq) calc_e = false;
01689
01690
01691
01692 dyn *b;
01693 int i = 0;
01694
01695 while (b = get_dyn(cin)) {
01696
01697 check_addstar(b);
01698 check_set_external(b, true);
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