00001
00012
00013 #include "sdyn.h"
00014
00015
00016
00017 local void pp(sdyn* b, ostream & s, int level = 0) {
00018
00019 s.precision(4);
00020
00021 for (int i = 0; i < 2*level; i++) s << " ";
00022
00023 b->pretty_print_node(s);
00024 s << " \t"<< b->get_mass() << " \t"
00025 << b->get_pos() << " "
00026 << b->get_vel() <<endl;
00027
00028 for_all_daughters(sdyn, b, daughter) pp(daughter, s, level + 1);
00029 }
00030
00031 #ifndef TOOLBOX
00032
00033 static char id_string[50];
00034
00035
00036
00037 char* id(sdyn* bb)
00038 {
00039 if (bb->get_name() != NULL)
00040 return bb->get_name();
00041 else {
00042 sprintf(id_string, "%d", bb->get_index());
00043 return id_string;
00044 }
00045 return NULL;
00046 }
00047
00048
00049
00050
00051 local int count_daughters(sdyn* b)
00052 {
00053 int n = 0;
00054 for_all_daughters(sdyn, b, bb) n++;
00055
00056 return n;
00057 }
00058
00059
00060
00061
00062
00063 local void find_neighbors(sdyn* b)
00064 {
00065 for_all_daughters(sdyn, b, bb) {
00066 bb->set_nn_dr2(VERY_LARGE_NUMBER);
00067 bb->set_nn_ptr(NULL);
00068 bb->set_nnn_dr2(VERY_LARGE_NUMBER);
00069 bb->set_nnn_ptr(NULL);
00070 }
00071
00072 for_all_daughters(sdyn, b, bi)
00073 for (sdyn* bj = bi->get_younger_sister();
00074 bj != NULL; bj = bj->get_younger_sister()) {
00075
00076 real rij2 = square(bi->get_pos() - bj->get_pos());
00077
00078 if (rij2 < bi->get_nn_dr2()) {
00079 bi->set_nn_dr2(rij2);
00080 bi->set_nn_ptr(bj);
00081 } else if (rij2 < bi->get_nnn_dr2()) {
00082 bi->set_nnn_dr2(rij2);
00083 bi->set_nnn_ptr(bj);
00084 }
00085
00086 if (rij2 < bj->get_nn_dr2()) {
00087 bj->set_nn_dr2(rij2);
00088 bj->set_nn_ptr(bi);
00089 } else if (rij2 < bj->get_nnn_dr2()) {
00090 bj->set_nnn_dr2(rij2);
00091 bj->set_nnn_ptr(bi);
00092 }
00093 }
00094 }
00095
00096
00097
00098
00099
00100 local void detach_from_tree(sdyn* bi)
00101 {
00102 sdyn* parent = bi->get_parent();
00103 sdyn* elder = bi->get_elder_sister();
00104 sdyn* younger = bi->get_younger_sister();
00105
00106 if (younger != NULL) younger->set_elder_sister(elder);
00107
00108 if (elder == NULL)
00109 parent->set_oldest_daughter(younger);
00110 else
00111 elder->set_younger_sister(younger);
00112 }
00113
00114
00115
00116
00117 local void add_node(sdyn* root, sdyn* new_node)
00118 {
00119 new_node->set_parent(root);
00120 new_node->set_elder_sister(NULL);
00121
00122 sdyn* od = root->get_oldest_daughter();
00123 new_node->set_younger_sister(od);
00124
00125 if (od) od->set_elder_sister(new_node);
00126 root->set_oldest_daughter(new_node);
00127 }
00128
00129
00130
00131
00132 local real m_sum(sdyn* list[], int k_tuple)
00133 {
00134 real sum = 0;
00135 for (int i = 0; i < k_tuple; i++) sum += list[i]->get_mass();
00136
00137 return sum;
00138 }
00139
00140
00141
00142
00143 local vector pos_sum(sdyn* list[], int k_tuple)
00144 {
00145 vector sum = vector(0,0,0);
00146
00147 for (int i = 0; i < k_tuple; i++)
00148 sum += list[i]->get_mass() * list[i]->get_pos();
00149
00150 return sum;
00151 }
00152
00153
00154
00155
00156 local vector vel_sum(sdyn* list[], int k_tuple)
00157 {
00158 vector sum = vector(0,0,0);
00159
00160 for (int i = 0; i < k_tuple; i++)
00161 sum += list[i]->get_mass() * list[i]->get_vel();
00162
00163 return sum;
00164 }
00165
00166
00167
00168
00169
00170 local real tuple_size(sdyn* list[], int k_tuple)
00171 {
00172 real max_dist = 0;
00173 vector cmpos = pos_sum(list, k_tuple) / m_sum(list, k_tuple);
00174
00175 for (int i = 0; i < k_tuple; i++)
00176 max_dist = max(max_dist, abs(list[i]->get_pos() - cmpos));
00177
00178 return max_dist;
00179 }
00180
00181
00182
00183
00184 local real tuple_virial_radius(sdyn* list[], int k_tuple)
00185 {
00186 real total_mass = m_sum(list, k_tuple);
00187 real potential = 0;
00188
00189 for (int i = 0; i < k_tuple; i++)
00190 for (int j = i+1; j < k_tuple; j++)
00191 potential -= list[i]->get_mass() * list[j]->get_mass()
00192 / abs(list[i]->get_pos() - list[j]->get_pos());
00193
00194 return -0.5 * total_mass * total_mass / potential;
00195 }
00196
00197
00198
00199
00200
00201 local real distance_sq(sdyn* list[], int k_tuple, sdyn* rest[], int n_rest)
00202 {
00203 real min_dist_sq = VERY_LARGE_NUMBER;
00204
00205 for (int i = 0; i < k_tuple; i++)
00206 for (int j = 0; j < n_rest; j++)
00207 min_dist_sq = min(min_dist_sq,
00208 square(list[i]->get_pos() - rest[j]->get_pos()));
00209
00210 return min_dist_sq;
00211 }
00212
00213
00214
00215
00216 local bool is_bound(sdyn* list[], int k_tuple)
00217 {
00218 vector cmvel = vel_sum(list, k_tuple) / m_sum(list, k_tuple);
00219
00220 real kinetic = 0;
00221 for (int i = 0; i < k_tuple; i++)
00222 kinetic += list[i]->get_mass() * square(list[i]->get_vel());
00223 kinetic /= 2;
00224
00225 real potential = 0;
00226 for (int i = 0; i < k_tuple; i++)
00227 for (int j = i+1; j < k_tuple; j++)
00228 potential -= list[i]->get_mass() * list[j]->get_mass()
00229 / abs(list[i]->get_pos() - list[j]->get_pos());
00230
00231 if (kinetic + potential >= 0) return FALSE;
00232 return TRUE;
00233 }
00234
00235
00236
00237
00238
00239 local sdyn* make_tuple_cm(sdyn* list[], int k_tuple, real radius,
00240 bool meta = FALSE)
00241 {
00242 if (k_tuple < 2) return NULL;
00243
00244 sdyn* root = list[0]->get_parent();
00245
00246
00247
00248 for (int i = 0; i < k_tuple; i++)
00249 detach_from_tree(list[i]);
00250
00251
00252
00253
00254 sdyn* cm = new sdyn;
00255 add_node(root, cm);
00256
00257
00258
00259 cm->set_oldest_daughter(list[0]);
00260 list[0]->set_elder_sister(NULL);
00261 for (int i = 0; i < k_tuple; i++) {
00262 list[i]->set_parent(cm);
00263 if (i > 0) list[i]->set_elder_sister(list[i-1]);
00264 if (i < k_tuple-1) list[i]->set_younger_sister(list[i+1]);
00265 }
00266 list[k_tuple-1]->set_younger_sister(NULL);
00267
00268
00269
00270 real m_total = m_sum(list, k_tuple);
00271 vector cmpos = pos_sum(list, k_tuple) / m_total;
00272 vector cmvel = vel_sum(list, k_tuple)/ m_total;
00273
00274 cm->set_mass(m_total);
00275 cm->set_pos(cmpos);
00276 cm->set_vel(cmvel);
00277 cm->set_time(root->get_time());
00278
00279 cm->set_radius(radius);
00280
00281
00282
00283
00284 cm->set_nn_ptr(NULL);
00285 cm->set_nnn_ptr(NULL);
00286
00287
00288
00289 for (int i = 0; i < k_tuple; i++) {
00290 list[i]->inc_pos(-cmpos);
00291 list[i]->inc_vel(-cmvel);
00292 }
00293
00294
00295
00296 bool index = TRUE;
00297 for (int i = 0; i < k_tuple; i++)
00298 if (list[i]->get_index() <= 0) index = FALSE;
00299
00300 if (index) {
00301 int sum = 100 * list[0]->get_index();
00302 for (int i = 1; i < k_tuple; i++) sum += list[i]->get_index();
00303 cm->set_index(sum);
00304 }
00305
00306 bool name = TRUE;
00307 for (int i = 0; i < k_tuple; i++)
00308 if (list[i]->get_name() == NULL) name = FALSE;
00309
00310 if (name) {
00311 char temp[100];
00312 temp[0] = '\0';
00313 strcat(temp, (meta ? "{" : "("));
00314 for (int i = 0; i < k_tuple; i++) {
00315 strcat(temp, list[i]->get_name());
00316 if (i < k_tuple-1) strcat(temp, ",");
00317 }
00318 strcat(temp, (meta ? "}" : ")"));
00319 cm->set_name(temp);
00320 }
00321
00322 return cm;
00323 }
00324
00325
00326
00327
00328 local void identify_node(char* string, sdyn* bb)
00329 {
00330 cerr << string << " = " << bb;
00331 if (bb != NULL) cerr << " = " << id(bb);
00332 cerr << endl;
00333 }
00334
00335
00336
00337
00338 #define MIN_PERI_FACTOR 2 // Unconditionally unstable within this peri
00339 #define MAX_PERI_FACTOR 6 // Unconditionally stable outside this peri
00340 #define ISOL_FACTOR 4 // For multiples only
00341 #define ISOL_FACTOR_SQ (ISOL_FACTOR * ISOL_FACTOR)
00342
00343 #define QUARANTINE_TIME_LIMIT 100 // Unit = outer orbit period
00344 #define QSMA_TOL 0.01 // Acceptable variation in outer sma
00345 #define QECC_TOL 0.1 // Acceptable variation in outer ecc
00346
00347
00348
00349
00350
00351 local void set_tqflag(sdyn* b, int flag) {
00352
00353 b->set_temp_quarantine_flag(flag);
00354 for_all_daughters(sdyn, b, daughter) set_tqflag(daughter, flag);
00355 }
00356
00357
00358
00359
00360 local void check_tqflag(sdyn* b) {
00361
00362 if (b->get_temp_quarantine_flag() == 0) b->set_quarantine_flag(0);
00363 for_all_daughters(sdyn, b, daughter) check_tqflag(daughter);
00364 }
00365
00366
00367
00368
00369
00370 local void set_quar(sdyn* b, int flag, real time, real sma, real ecc) {
00371
00372 if (b->get_oldest_daughter() == NULL) {
00373 b->set_quarantine_flag(flag);
00374 b->set_quarantine_time(time);
00375 b->set_quarantine_sma(sma);
00376 b->set_quarantine_ecc(ecc);
00377 }else
00378 for_all_daughters(sdyn, b, daughter)
00379 set_quar(daughter, flag, time, sma, ecc);
00380 }
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390 local bool check_quar(sdyn* b, int flag, real time, real sma, real ecc) {
00391
00392
00393
00394
00395 if (b->get_oldest_daughter() == NULL) {
00396 if (b->get_quarantine_flag() < 0
00397 || b->get_quarantine_flag() != flag
00398 || b->get_quarantine_time() != time
00399 || b->get_quarantine_sma() != sma
00400 || b->get_quarantine_ecc() != ecc) return FALSE;
00401 } else
00402 for_all_daughters(sdyn, b, daughter)
00403 if (!check_quar(daughter, flag, time, sma,ecc)) return FALSE;
00404
00405 return TRUE;
00406 }
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416 local bool check_quarantine(sdyn* b, sdyn* n, real sma, real ecc, int debug)
00417 {
00418 set_tqflag(b, 1);
00419 set_tqflag(n, 1);
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430 sdyn* first = first_leaf(b);
00431
00432 int qflag = first->get_quarantine_flag();
00433 real qtime = first->get_quarantine_time();
00434 real qsma = first->get_quarantine_sma();
00435 real qecc = first->get_quarantine_ecc();
00436
00437 if (check_quar(b, qflag, qtime, qsma, qecc)
00438 && check_quar(n, qflag, qtime, qsma, qecc)) {
00439
00440
00441
00442 if (abs(sma - qsma) < QSMA_TOL * qsma
00443 && abs(ecc - qecc) < QECC_TOL * qecc) {
00444
00445
00446
00447
00448 if (b->get_time() - qtime > QUARANTINE_TIME_LIMIT *
00449 TWO_PI * sqrt( (b->get_mass() + n->get_mass()) / pow(sma, 3)))
00450 return TRUE;
00451 else
00452 return FALSE;
00453 }
00454 }
00455
00456
00457
00458
00459 qflag = (int)b / 4 + (int)n / 4;
00460 qtime = b->get_time();
00461
00462 set_quar(b, qflag, qtime, sma, ecc);
00463 set_quar(n, qflag, qtime, sma, ecc);
00464
00465 if (debug) cerr << ": new quarantine";
00466 return FALSE;
00467 }
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481 local int find_and_make_binaries(sdyn* b, bool dynamics, bool stability,
00482 int debug)
00483 {
00484 int n_bin = 0;
00485
00486 sdyn* bb = b->get_oldest_daughter();
00487 sdyn* last_bb = NULL;
00488
00489 while (bb) {
00490 sdyn* nn = bb->get_nn_ptr();
00491
00492 if (debug > 1) {
00493 identify_node("bb", bb);
00494 identify_node("nn", nn);
00495 }
00496
00497 if (nn != NULL && nn->get_nn_ptr() == bb) {
00498
00499 real radius = abs(bb->get_pos() - nn->get_pos());
00500 bool is_binary = TRUE;
00501 bool meta = FALSE;
00502
00503 if (debug) cerr << "mutual pair " << id(bb)
00504 << " " << id(nn) << flush;
00505
00506 if (dynamics) {
00507
00508 real m_total = bb->get_mass() + nn->get_mass();
00509 real eij = 0.5 * square(bb->get_vel() - nn->get_vel())
00510 - m_total / radius;
00511
00512 if (eij < 0) {
00513
00514 real sma = -0.5 * m_total / eij;
00515 if (debug) cerr << ": bound, a = " << sma << flush;
00516
00517 if (stability) {
00518
00519
00520
00521 vector rel_pos = bb->get_pos() - nn->get_pos();
00522 vector rel_vel = bb->get_vel() - nn->get_vel();
00523
00524 real rdotv = rel_pos * rel_vel;
00525 real temp = 1 - radius / sma;
00526
00527 real ecc = sqrt(max(0.0, rdotv * rdotv
00528 / (m_total * sma)
00529 + temp * temp));
00530 real periastron = sma * (1 - ecc);
00531 real size = max(bb->get_radius(), nn->get_radius());
00532
00533
00534
00535
00536 if (periastron < MIN_PERI_FACTOR * size) {
00537
00538
00539
00540 is_binary = FALSE;
00541 nn->set_nn_ptr(NULL);
00542
00543 if (debug) cerr << ": unstable, e = " << ecc
00544 << flush;
00545
00546 } else if (periastron < MAX_PERI_FACTOR * size) {
00547
00548
00549
00550
00551 if ( (is_binary = check_quarantine(bb, nn,
00552 sma, ecc,
00553 debug))
00554 == FALSE) {
00555 nn->set_nn_ptr(NULL);
00556 if (debug) cerr << ": quarantined, e = " << ecc
00557 << flush;
00558 } else {
00559 if (debug) cerr << ": metastable, e = " << ecc
00560 << flush;
00561 meta = TRUE;
00562 }
00563 } else
00564
00565
00566
00567 if (debug) cerr << ": stable, e = " << ecc
00568 << flush;
00569 }
00570
00571 radius = sma;
00572
00573 } else {
00574
00575 is_binary = FALSE;
00576 nn->set_nn_ptr(NULL);
00577 if (debug) cerr << ": not bound, separation = " << radius
00578 << flush;
00579 }
00580 }
00581
00582 if (is_binary) {
00583
00584 radius += bb->get_radius() + nn->get_radius();
00585 real r_crit_sq = ISOL_FACTOR_SQ * radius * radius;
00586
00587 if (bb->get_nnn_dr2() > r_crit_sq
00588 && nn->get_nnn_dr2() > r_crit_sq) {
00589
00590 sdyn* list[2];
00591 list[0] = bb;
00592 list[1] = nn;
00593 make_tuple_cm(list, 2, radius, meta);
00594
00595 n_bin++;
00596 bb = last_bb;
00597
00598
00599
00600 for_all_daughters(sdyn, b, bbb)
00601 if (bbb->get_nn_ptr() == bb
00602 || bbb->get_nn_ptr() == nn
00603 || bbb->get_nnn_ptr() == bb
00604 || bbb->get_nnn_ptr() == nn)
00605 bbb->set_nn_ptr(NULL);
00606 } else {
00607 nn->set_nn_ptr(NULL);
00608 if (debug) cerr << ": not isolated" << flush;
00609 }
00610 }
00611 if (debug) cerr << endl;
00612 }
00613
00614 last_bb = bb;
00615
00616
00617
00618 if (bb != NULL)
00619
00620 bb = bb->get_younger_sister();
00621
00622 else {
00623
00624
00625
00626
00627
00628
00629
00630
00631 bb = b->get_oldest_daughter();
00632 while (bb != NULL && bb->get_nn_ptr() == NULL)
00633 bb = bb->get_younger_sister();
00634 }
00635 }
00636
00637 return n_bin;
00638 }
00639
00640
00641
00642
00643
00644
00645
00646 local int find_and_make_tuple(sdyn* b, int k_tuple, bool dynamics,
00647 bool stability, int debug)
00648 {
00649 if (debug > 1) cerr << "find_and_make_tuple: k = " << k_tuple << endl;
00650
00651 if (k_tuple < 2)
00652
00653 return 0;
00654
00655 else if (k_tuple == 2)
00656
00657 return find_and_make_binaries(b, dynamics, stability, debug);
00658
00659 else {
00660
00661 sdyn** list = new sdyn*[k_tuple+1];
00662
00663 for_all_daughters(sdyn, b, bi) {
00664 list[0] = bi;
00665 int nlist = 1;
00666 for (int i = 1; i <= k_tuple; i++) {
00667 sdyn* nn = list[i-1]->get_nn_ptr();
00668 bool dup = FALSE;
00669 for (int j = 0; j < i; j++)
00670 if (list[j] == nn) dup = TRUE;
00671 if (!dup)
00672 list[nlist++] = nn;
00673 else
00674 break;
00675 }
00676
00677 if (debug > 1) cerr << "bi = " << id(bi)
00678 << " nlist = " << nlist << endl;
00679
00680
00681
00682 if (nlist == k_tuple) {
00683
00684
00685
00686
00687
00688 if (debug) {
00689 cerr << "candidate " << k_tuple << "-tuple";
00690 for (int i = 0; i < k_tuple; i++)
00691 cerr << " " << id(list[i]);
00692 cerr << flush;
00693 }
00694
00695
00696
00697 int n = count_daughters(b);
00698 sdyn** rest = new sdyn*[n-k_tuple+1];
00699 int n_rest = 0;
00700
00701 for_all_daughters(sdyn, b, bj) {
00702 bool dup = FALSE;
00703 for (int i = 0; i < k_tuple; i++)
00704 if (bj == list[i]) {
00705 dup = TRUE;
00706 break;
00707 }
00708 if (!dup) rest[n_rest++] = bj;
00709 }
00710
00711
00712
00713 bool is_binary = TRUE;
00714 if (dynamics && !is_bound(list, k_tuple)) is_binary = FALSE;
00715
00716 if (is_binary) {
00717
00718
00719
00720 real radius = max(tuple_size(list, k_tuple),
00721 tuple_virial_radius(list, k_tuple));
00722
00723 for (int i = 0; i < k_tuple; i++)
00724 radius += list[i]->get_radius();
00725
00726 real r_crit_sq = ISOL_FACTOR_SQ * radius * radius;
00727
00728 real dist_sq = distance_sq(list, k_tuple, rest, n_rest);
00729 delete rest;
00730
00731 if (r_crit_sq < dist_sq) {
00732 sdyn* cm = make_tuple_cm(list, k_tuple, radius);
00733 if (debug) {
00734 cerr << ", radius = " << radius << endl;
00735 pp(cm, cerr);
00736 }
00737 return 1;
00738 }
00739 if (debug) cerr << ": not isolated\n";
00740
00741 } else {
00742 delete rest;
00743 if (debug) cerr << ": not bound\n";
00744 }
00745 }
00746 }
00747 delete list;
00748 }
00749
00750 return 0;
00751 }
00752
00753
00754
00755
00756
00757 void make_tree(sdyn* b, bool dynamics, bool stability, int k_max, int debug)
00758 {
00759 b->flatten_node();
00760
00761
00762
00763 if (k_max <= 0) k_max = 1000000;
00764 set_tqflag(b, 0);
00765
00766 int nt;
00767 do {
00768 nt = 0;
00769 for (int k_tuple = 2;
00770 k_tuple < min(k_max + 1, count_daughters(b));
00771 k_tuple++) {
00772
00773
00774
00775
00776
00777 if (k_tuple < 4) find_neighbors(b);
00778
00779 if ( (nt = find_and_make_tuple(b, k_tuple, dynamics,
00780 stability, debug)) > 0)
00781 break;
00782 }
00783 } while (nt > 0);
00784
00785 check_tqflag(b);
00786 }
00787
00788 #else
00789
00790 local void delete_node(sdyn* b)
00791 {
00792
00793
00794
00795 sdyn* bi = b->get_oldest_daughter();
00796 while (bi) {
00797 sdyn* tmp = bi->get_younger_sister();
00798 delete_node(bi);
00799 bi = tmp;
00800 }
00801 delete b;
00802 }
00803
00804 #define USAGE " Usage: make_tree [-b] [-d] [-D [#]] [-k #] [-o] [-s]"
00805
00806 main(int argc, char **argv)
00807 {
00808 sdyn* root;
00809
00810 int debug = 0;
00811 bool dynamics = FALSE;
00812 int k_max = 10000000;
00813 bool output = TRUE;
00814 bool stability = FALSE;
00815
00816 check_help();
00817
00818 int i = 0;
00819 while (++i < argc) if (argv[i][0] == '-')
00820 switch (argv[i][1]) {
00821 case 'b': k_max = 2;
00822 break;
00823 case 'd': dynamics = 1 - dynamics;
00824 break;
00825 case 'D': i++;
00826 if (i == argc || argv[i][0] == '-') {
00827 debug = 1;
00828 i--;
00829 } else
00830 debug = atoi(argv[i]);
00831 break;
00832 case 'k': k_max = atoi(argv[++i]);
00833 break;
00834 case 'o': output = 1 - output;
00835 break;
00836 case 's': stability = 1 - stability;
00837 break;
00838 default: cerr << USAGE << endl;
00839 get_help();
00840 }
00841
00842
00843
00844 while (root = get_sdyn(cin)) {
00845
00846
00847
00848
00849
00850 if (root->get_name() == NULL) root->set_name("root");
00851
00852 make_tree(root, dynamics, stability, k_max, debug);
00853
00854 if (debug) pp(root, cerr);
00855 if (output) put_sdyn(cout, *root);
00856
00857
00858
00859 delete_node(root);
00860 }
00861 }
00862 #endif