00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 #include "hdyn.h"
00038 #include <star/dstar_to_kira.h>
00039
00040 #define USE_DT_PERTURBERS true
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081 #define SEP_EPSILON 0.01 // arbitrary, but small
00082 #define SEP_FACTOR (1.0 + SEP_EPSILON)
00083
00084 #define OUTSIDE_SEMI(sep, sma) ((SEP_FACTOR)*(sep) > (sma))
00085
00086
00087
00088 #define KEP_OUTSIDE_SEMI(k) \
00089 ((SEP_FACTOR)*((k).get_separation()) > ((k).get_semi_major_axis()))
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175 static int init_binary_type;
00176 static int binary_type;
00177
00178 #define UNKNOWN_STATUS 0
00179 #define STABLE_OUTER 1
00180 #define STABLE_INNER 2
00181 #define NOT_APPROACHING 3
00182 #define PERICENTER_REFLECTION 4
00183 #define FULL_MERGER 5
00184 #define CONTINUE_MERGER 6
00185 #define PERTURBED 7
00186 #define MULTIPLE_CM 8
00187 #define UNPERTURBED_MULTIPLE_COMPONENT 9
00188 #define UNKNOWN_PERTURBERS 10
00189 #define DEFERRED 11
00190
00191 static char* bt[12] = {"unknown status",
00192 "stable multiple outer binary",
00193 "stable multiple inner binary",
00194 "components not approaching",
00195 "pericenter reflection",
00196 "full binary merger",
00197 "continue existing merger",
00198 "perturbed binary",
00199 "multiple system",
00200 "unperturbed multiple component",
00201 "no valid perturber list",
00202 "unperturbed motion deferred"};
00203
00204 static int multiple_type;
00205
00206 #define NOT_MULTIPLE 0
00207 #define FULL_MULTIPLE 1
00208 #define APOCENTER_REFLECTION 2
00209
00210 static char* tt[3] = {"not multiple",
00211 "full_multiple merger",
00212 "apocenter reflection"};
00213
00214
00215
00216
00217
00218 local inline real get_energy(hdyn* b, real& separation)
00219 {
00220
00221
00222 if (b->is_top_level_node()) return 0;
00223
00224 hdyn* s = b->get_binary_sister();
00225 separation = abs(b->get_pos() - s->get_pos());
00226
00227 return 0.5*square(b->get_vel() - s->get_vel())
00228 - b->get_parent()->get_mass() / separation;
00229 }
00230
00231 local inline real get_semi(hdyn* bcm)
00232 {
00233
00234
00235 real semi = 0;
00236
00237 if (bcm->is_parent()) {
00238
00239
00240
00241
00242 if (bcm->get_oldest_daughter()->get_kepler()) {
00243 semi = bcm->get_oldest_daughter()->get_kepler()
00244 ->get_semi_major_axis();
00245 } else {
00246 real sep;
00247 real energy = get_energy(bcm->get_oldest_daughter(), sep);
00248 semi = -0.5 * bcm->get_mass() / energy;
00249 }
00250 }
00251
00252 if (semi < 0) semi = -VERY_LARGE_NUMBER;
00253
00254 return semi;
00255 }
00256
00257 local inline real get_period(real mass, real sma)
00258 {
00259
00260
00261
00262 return TWO_PI * sqrt(sma*sma*sma / mass);
00263 }
00264
00265 local inline void print_found_multiple(hdyn* b,
00266 bool real_multiple,
00267 kepler& outer,
00268 real inner_semi1,
00269 real inner_semi2,
00270 real mass1,
00271 real mass2)
00272 {
00273 int p = cerr.precision(HIGH_PRECISION);
00274 cerr << endl;
00275
00276 if (!real_multiple)
00277 cerr << endl << "impending multiple: ";
00278
00279 cerr << b->get_parent()->format_label();
00280
00281 if (real_multiple)
00282 cerr << " is a hierarchical stable multiple";
00283 else
00284 cerr << " is a multiple CM";
00285
00286 cerr << endl << " at system time " << b->get_system_time() << endl;
00287 cerr << " components " << b->format_label();
00288 cerr << " and " << b->get_binary_sister()->format_label();
00289
00290 if (!real_multiple)
00291 cerr << "; outer orbit is weakly perturbed:" << endl;
00292
00293 cerr.precision(8);
00294
00295 cerr << " perturbation = " << sqrt(b->get_perturbation_squared())
00296 << endl
00297 << " outer peri = " << outer.get_periastron()
00298 << " inner semi = ";
00299
00300 if (inner_semi1 > 0) cerr << inner_semi1 << " ";
00301 if (inner_semi2 > 0) cerr << inner_semi2;
00302
00303 cerr << endl
00304 << " outer period = " << outer.get_period()
00305 << " inner period = ";
00306
00307 if (inner_semi1 > 0) cerr << get_period(mass1, inner_semi1) << " ";
00308 if (inner_semi2 > 0) cerr << get_period(mass2, inner_semi2);
00309
00310 cerr << endl
00311 << " parent dt = " << b->get_parent()->get_next_time()
00312 - b->get_system_time()
00313 << endl;
00314
00315 cerr.precision(p);
00316 }
00317
00318 local inline void print_startup_message(hdyn * b, int type, bool new_kep)
00319 {
00320 int p = cerr.precision(HIGH_PRECISION);
00321 cerr << endl;
00322
00323 if (new_kep)
00324 cerr << "starting new";
00325 else
00326 cerr << "continuing existing";
00327
00328 cerr << " unperturbed motion for "
00329 << b->format_label();
00330 cerr << " and " << b->get_binary_sister()->format_label();
00331
00332 if (b->get_slow())
00333 cerr << " (slowdown = " << b->get_kappa() << ")";
00334
00335
00336
00337 cerr << endl;
00338
00339 cerr << " at time " << b->get_time()
00340 << " " << " (system_time = " << b->get_system_time() << ")"
00341 << endl;
00342
00343 cerr << " " << bt[type] << " (binary_type = " << type << ")";
00344
00345 cerr.precision(8);
00346
00347 if (b->get_kepler())
00348 cerr << " period = " << b->get_kepler()->get_period();
00349
00350 cerr << endl;
00351 cerr.precision(p);
00352
00353 cerr << " perturbation = " << sqrt(b->get_perturbation_squared());
00354
00355 if (b->get_parent()->get_nn() && b->get_parent()->get_nn()->is_valid())
00356 cerr << " (" << b->get_parent()->get_nn()->format_label() << ")";
00357
00358 cerr << endl;
00359
00360 #if 0
00361 if (streq(b->format_label(), "xxx"))
00362 b->get_kepler()->print_all();
00363 #endif
00364
00365 }
00366
00367 local inline void print_binary_data(hdyn* bi)
00368 {
00369 PRL(bi->get_perturbation_squared());
00370 PRL(bi->get_unperturbed_timestep());
00371 PRL(bi->get_fully_unperturbed());
00372 PRL(bi->get_d_nn_sq());
00373 PRL(bi->get_perturbation_radius_factor());
00374 PRL(bi->find_perturber_node());
00375 if (bi->find_perturber_node())
00376 PRL(bi->find_perturber_node()->get_valid_perturbers());
00377 PRL(bi->get_d_coll_sq());
00378 PRL(bi->get_coll()->format_label());
00379 }
00380
00381 local inline bool is_multiple(hdyn* b)
00382 {
00383
00384
00385
00386 if (b->is_top_level_node()) return false;
00387 return !( b->is_leaf() && b->get_binary_sister()->is_leaf() );
00388 }
00389
00390 local inline real dt_overshoot(hdyn *b)
00391 {
00392
00393
00394
00395 if (!b->get_parent())
00396 return 0;
00397 else
00398 return 0.9 * b->get_parent()->get_timestep();
00399 }
00400
00401
00402
00403 #include "hdyn_inline.C"
00404
00405
00406 local inline real dt_perturbers(hdyn *b)
00407 {
00408
00409
00410
00411
00412
00413
00414
00415 hdyn *top = b->get_top_level_node();
00416 real t_min = VERY_LARGE_NUMBER;
00417
00418 if (top->get_valid_perturbers()) {
00419
00420 real scale = binary_scale(top);
00421 real gamma = sqrt(b->get_kira_options()->multiple_merge_tolerance);
00422
00423
00424
00425 int np = top->get_n_perturbers();
00426 hdyn **plist = top->get_perturber_list();
00427
00428 for (int j = 0; j < np; j++) {
00429
00430 hdyn *p = plist[j];
00431 if (!p->is_top_level_node()) {
00432 if (p->get_elder_sister()) continue;
00433 p = p->get_top_level_node();
00434 }
00435
00436
00437
00438
00439
00440 real rpert3 = crit_separation_cubed(top, p->get_mass(),
00441 scale, gamma);
00442
00443 real rpert = pow(rpert3, 1.0/3);
00444
00445
00446
00447
00448 vector dpos = top->get_pos() - p->get_pos();
00449 vector dvel = top->get_vel() - p->get_vel();
00450 vector dacc = top->get_acc() - p->get_acc();
00451
00452 real dr = abs(dpos);
00453 real vr = dvel * dpos / dr;
00454 real ar = dacc * dpos / dr;
00455
00456 real tr = time_to_radius(dr - rpert, vr, ar);
00457
00458 if (tr < t_min) t_min = tr;
00459 if (tr <= 0) break;
00460 }
00461
00462 } else
00463
00464 t_min = -1;
00465
00466 return t_min;
00467 }
00468
00469 local void check_perturbers(hdyn *b)
00470 {
00471
00472
00473
00474 real t_min = dt_perturbers(b);
00475
00476 if (t_min >= 0)
00477
00478 cerr << " " << b->get_top_level_node()->get_n_perturbers()
00479 << " perturbers, perturber crossing time = "
00480 << t_min << endl;
00481
00482 else
00483
00484 cerr << " no valid perturber list" << endl;
00485 }
00486
00487
00488
00489
00490
00491
00492
00493 void set_allow_unperturbed(hdyn *b,
00494 bool value)
00495 {
00496 b->get_kira_options()->allow_unperturbed = value;
00497 if (!b->get_kira_options()->allow_unperturbed)
00498 b->get_kira_options()->allow_multiples = false;
00499 }
00500
00501 void set_allow_multiples(hdyn *b,
00502 bool value)
00503 {
00504 b->get_kira_options()->allow_multiples = value;
00505 if (b->get_kira_options()->allow_multiples)
00506 b->get_kira_options()->allow_unperturbed = true;
00507 }
00508
00509 void toggle_unperturbed(hdyn *b, int level)
00510 {
00511 if (level == 0)
00512 b->get_kira_options()->allow_unperturbed
00513 = !b->get_kira_options()->allow_unperturbed;
00514 else
00515 b->get_kira_options()->allow_multiples
00516 = !b->get_kira_options()->allow_multiples;
00517
00518
00519
00520 if (!b->get_kira_options()->allow_unperturbed)
00521 b->get_kira_options()->allow_multiples = false;
00522 if (b->get_kira_options()->allow_multiples)
00523 b->get_kira_options()->allow_unperturbed = true;
00524 }
00525
00526 void print_unperturbed_options(hdyn *b)
00527 {
00528 cerr << "Unperturbed options: allow_unperturbed = "
00529 << b->get_kira_options()->allow_unperturbed
00530 << ", allow_multiples = "
00531 << b->get_kira_options()->allow_multiples
00532 << endl;
00533 }
00534
00535
00536
00537 void hdyn::print_unperturbed_binary_params()
00538 {
00539 cerr << " perturbed timestep for " << format_label()
00540 << " is " << timestep << endl;
00541
00542 cerr << " pos*vel = " << pos*vel
00543 << endl
00544 << " a = " << kep->get_semi_major_axis()
00545 << " e = " << kep->get_eccentricity()
00546 << " r = " << kep->get_separation()
00547 << endl
00548 << " peri = " << kep->get_periastron()
00549 << " apo = " << kep->get_semi_major_axis()
00550 * (1 + kep->get_eccentricity())
00551 << endl
00552 << " period = " << kep->get_period()
00553 << " perturbation = " << sqrt(perturbation_squared)
00554 << endl;
00555
00556 PRI(4); PRL(unperturbed_timestep);
00557
00558 PRI(4); PRL(get_parent()->get_next_time());
00559 PRI(4); PRL(get_parent()->timestep);
00560 PRI(4); print_nn(get_parent(), 2);
00561 }
00562
00563 void hdyn::update_dyn_from_kepler()
00564 {
00565 if (diag->unpert_function_id) {
00566 cerr << ">> update_dyn_from_kepler for "
00567 << format_label() << endl;
00568 }
00569
00570 hdyn *sister = get_binary_sister();
00571
00572
00573
00574
00575
00576
00577 if (diag->report_end_unperturbed) {
00578 if (time != system_time) {
00579 cerr << "in update_dyn_from_kepler: ";
00580 PRC(time), PRL(system_time);
00581 }
00582 }
00583
00584 time = system_time;
00585
00586
00587
00588
00589
00590
00591
00592
00593 if (!slow)
00594 kep->transform_to_time(time);
00595 else
00596 kep->transform_to_time(time - unperturbed_timestep
00597 * (1 - 1.0/get_kappa()));
00598
00599
00600
00601
00602
00603
00604 real factor = sister->mass / (mass + sister->mass);
00605 real sfactor = factor - 1.0;
00606 pos = kep->get_rel_pos() * factor;
00607 vel = kep->get_rel_vel() * factor;
00608 pred_pos = pos;
00609 pred_vel = vel;
00610
00611 prev_posvel = posvel;
00612 posvel = pos*vel;
00613
00614 sister->time = time;
00615 sister->pred_pos = kep->get_rel_pos() * sfactor;
00616 sister->pred_vel = kep->get_rel_vel() * sfactor;
00617 sister->pos = kep->get_rel_pos() * sfactor;
00618 sister->vel = kep->get_rel_vel() * sfactor;
00619
00620 clear_interaction();
00621 calculate_acc_and_jerk(true);
00622
00623 store_old_force();
00624
00625 update_binary_sister(this);
00626 }
00627
00628 bool hdyn::is_close_pair()
00629 {
00630 if (kep == NULL) return false;
00631 if (kep->get_energy() >= 0) return false;
00632
00633 real rp = kep->get_periastron();
00634 real sum_radius = radius + get_binary_sister()->radius;
00635
00636 if (rp < 5 * sum_radius) {
00637
00638
00639
00640
00641
00642
00643
00644 if (perturbation_squared
00645 < options->full_merge_tol_for_close_binary) {
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655 return true;
00656 }
00657 }
00658 return false;
00659 }
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670 static char* wp[11] = {"unknown status",
00671 "not low-level node",
00672 "unbound orbit",
00673 "no perturber node",
00674 "no valid perturbers",
00675 "perturbation too large",
00676 "extended outer orbit",
00677 "inside semi and perturbed",
00678 "short parent time step",
00679 "already uperturbed",
00680 "weakly perturbed"};
00681
00682 bool hdyn::is_weakly_perturbed(int& status)
00683 {
00684 if (diag->unpert_function_id) {
00685 cerr << ">> check is_weakly_perturbed for "
00686 << format_label() << " at time " << system_time << endl;
00687 }
00688
00689 status = 0;
00690
00691 if (!is_low_level_node()) {
00692 status = 1;
00693 return false;
00694 }
00695
00696
00697
00698
00699
00700 real separation, energy;
00701
00702 if ((energy = get_energy(this, separation)) >= 0) {
00703 status = 2;
00704 return false;
00705 }
00706
00707 hdyn* pnode = find_perturber_node();
00708
00709 #if 0
00710
00711
00712
00713
00714 if (!pnode) {
00715 status = 3;
00716 return false;
00717 }
00718
00719 #else
00720
00721
00722
00723
00724
00725 if (!pnode) {
00726
00727
00728
00729
00730
00731 if (kep) {
00732
00733
00734
00735
00736
00737 status = 9;
00738 return true;
00739
00740 } else {
00741
00742 status = 3;
00743 return false;
00744
00745 }
00746 }
00747
00748 #endif
00749
00750 if (!pnode->valid_perturbers) {
00751
00752
00753
00754 status = 4;
00755 return false;
00756 }
00757
00758
00759
00760 if (perturbation_squared > options->multiple_merge_tolerance) {
00761 status = 5;
00762 return false;
00763 }
00764
00765
00766
00767
00768
00769 real semi_major_axis = -0.5 * parent->get_mass() / energy;
00770
00771 if (semi_major_axis > 5 * separation) {
00772 status = 6;
00773 return false;
00774 }
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787 bool is_weakly_pert = false;
00788
00789 if (OUTSIDE_SEMI(separation, semi_major_axis))
00790 is_weakly_pert = true;
00791 else if (pnode->n_perturbers == 0)
00792 is_weakly_pert = true;
00793
00794 status = 7;
00795
00796 if (is_weakly_pert) {
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807 real period = get_period(parent->get_mass(), semi_major_axis);
00808 real pdt2 = (real)(get_parent()->get_next_time() - time)
00809 + dt_overshoot(this);
00810
00811 if (period <= pdt2 || USE_DT_PERTURBERS) {
00812
00813 status = 10;
00814 return true;
00815
00816 } else if (diag->report_multiple && diag->unpert_report_level > 0) {
00817
00818 cerr << endl << "Multiple " << get_parent()->format_label()
00819 << " is weakly perturbed, but parent time step is too short"
00820 << endl
00821 << " period = " << period << " pdt2 = " << pdt2
00822 << " parent step = " << get_parent()->timestep
00823 << endl;
00824
00825 check_perturbers(this);
00826
00827 #if 0
00828 pp3(get_parent());
00829
00830 print_binary_from_dyn_pair(this, get_younger_sister());
00831 cerr << endl;
00832 if (is_parent()) {
00833 print_binary_from_dyn_pair(get_oldest_daughter(),
00834 get_oldest_daughter()
00835 ->get_younger_sister());
00836 cerr << endl;
00837 }
00838 if (get_younger_sister()->is_parent()) {
00839 print_binary_from_dyn_pair(get_younger_sister()
00840 ->get_oldest_daughter(),
00841 get_younger_sister()
00842 ->get_oldest_daughter()
00843 ->get_younger_sister());
00844 cerr << endl;
00845 }
00846 #endif
00847
00848 }
00849
00850 status = 8;
00851
00852 }
00853
00854 return false;
00855 }
00856
00857
00858
00859 #define NEAR_MULTIPLE_FAC 1.2
00860
00861
00862
00863
00864
00865
00866
00867 bool hdyn::is_stable(int& status,
00868 bool top_level)
00869 {
00870 if (diag->unpert_function_id) {
00871 cerr << ">> check is_stable for "
00872 << format_label() << endl;
00873 }
00874
00875 status = 0;
00876
00877 if (!is_low_level_node()) {
00878 status = 1;
00879 return false;
00880 }
00881
00882
00883
00884
00885
00886
00887
00888
00889
00890
00891
00892
00893
00894
00895 hdyn* sister = get_binary_sister();
00896 if (!sister) {
00897 status = 2;
00898 return false;
00899 }
00900
00901
00902
00903 if (is_leaf() && sister->is_leaf()) {
00904 status = 3;
00905 return true;
00906 }
00907
00908
00909
00910
00911 kepler outerkep;
00912
00913 if (kep == NULL) {
00914 outerkep.set_time(time);
00915 outerkep.set_total_mass(parent->get_mass());
00916 outerkep.set_rel_pos(pos - sister->pos);
00917 outerkep.set_rel_vel(vel - sister->vel);
00918 outerkep.initialize_from_pos_and_vel();
00919 } else
00920 outerkep = *kep;
00921
00922 real outer_peri = outerkep.get_periastron();
00923
00924 real inner_semi1 = get_semi(this);
00925 real inner_semi2 = get_semi(sister);
00926 real inner_semi_sum = inner_semi1 + inner_semi2;
00927
00928 if (inner_semi_sum < 0) {
00929 status = 4;
00930 return false;
00931 } else if (inner_semi_sum == 0) {
00932 status = 5;
00933 return true;
00934 }
00935
00936
00937
00938
00939 real peri_fac = 0;
00940
00941 if (options->use_aarseth_criterion) {
00942
00943 real e_outer = outerkep.get_eccentricity();
00944 real total_mass = outerkep.get_total_mass();
00945
00946
00947
00948
00949
00950
00951
00952
00953 real binary_fac = 0;
00954
00955 if (inner_semi1 > 0)
00956 binary_fac = pow(inner_semi1, 5) / pow(mass, 2);
00957
00958 if (inner_semi2 > 0)
00959 binary_fac = max(binary_fac, pow(inner_semi2, 5)
00960 / pow(sister->mass, 2));
00961
00962 if (binary_fac > 0)
00963 peri_fac = pow(outer_peri/options->aarseth_stable_fac, 5)
00964 * (1-e_outer)
00965 / (binary_fac * pow(total_mass*(1+e_outer), 2));
00966
00967 } else {
00968
00969
00970
00971
00972
00973 peri_fac = outer_peri / (inner_semi_sum
00974 * options->unconditional_stable_fac);
00975
00976 }
00977
00978
00979
00980
00981
00982
00983
00984
00985
00986
00987
00988
00989
00990
00991
00992
00993 hdyn *c = this;
00994 if (inner_semi2 > inner_semi1) c = sister;
00995
00996 c = c->get_oldest_daughter();
00997
00998
00999
01000 real cos_i = 0;
01001
01002 real dx2 = square(c->get_pos());
01003 real dv2 = square(c->get_vel());
01004
01005 if (dx2 > 0 && dv2 > 0) {
01006 vector n_inner = c->get_pos() ^ c->get_vel() / sqrt(dx2 * dv2);
01007 cos_i = n_inner * outerkep.get_normal_unit_vector();
01008 }
01009
01010 if (options->use_aarseth_criterion)
01011 peri_fac *= pow(4 / (3 + cos_i), 5);
01012 else
01013 peri_fac *= 4 / (3 + cos_i);
01014
01015 bool stable_a = (peri_fac > 1);
01016
01017 if (stable_a) {
01018
01019
01020
01021
01022 if (top_level)
01023 multiple_type = FULL_MULTIPLE;
01024
01025 #if 0
01026 PRC(cos_i);
01027 if (options->use_aarseth_criterion)
01028 PRL(pow(peri_fac, 0.2));
01029 else
01030 PRL(peri_fac);
01031 #endif
01032
01033 } else {
01034
01035
01036
01037
01038 if (top_level && options->partial_stable_fac*inner_semi_sum
01039 < outerkep.get_separation()) {
01040
01041
01042
01043
01044 real peri_time = (xreal)outerkep.pred_advance_to_periastron()
01045 - time;
01046
01047 if (peri_time > 0.8 * outerkep.get_period()) {
01048
01049
01050
01051
01052 if (top_level)
01053 multiple_type = APOCENTER_REFLECTION;
01054
01055 stable_a = true;
01056
01057 } else {
01058
01059 if (top_level && diag->report_impending_multiple_status)
01060 cerr << "Outer orbit " << parent->format_label()
01061 << " is partially unperturbed but not compact...\n";
01062 }
01063 }
01064 }
01065
01066
01067
01068 bool stable_b = stable_a;
01069
01070 if (stable_a) {
01071
01072 int status_1;
01073 if (is_parent())
01074 stable_b &= get_oldest_daughter()->is_stable(status_1, false);
01075
01076 int status_2;
01077 if (sister->is_parent())
01078 stable_b &= sister->get_oldest_daughter()
01079 ->is_stable(status_2, false);
01080
01081 status = 100 + 10*status_1 + status_2;
01082 }
01083
01084
01085
01086
01087 if (top_level) {
01088
01089 if (diag->report_impending_multiple_status
01090 && !stable_a
01091 && (options->unconditional_stable_fac*inner_semi_sum
01092 < NEAR_MULTIPLE_FAC*outer_peri
01093 || options->partial_stable_fac*inner_semi_sum
01094 < NEAR_MULTIPLE_FAC*outerkep.get_separation())) {
01095
01096
01097
01098 print_found_multiple(this, false, outerkep,
01099 inner_semi1, inner_semi2,
01100 mass, sister->mass);
01101 }
01102
01103 if (stable_b && diag->report_multiple) {
01104
01105 if (diag->multiple_report_level > 0) {
01106
01107 if (multiple_type == FULL_MULTIPLE)
01108 print_found_multiple(this, true, outerkep,
01109 inner_semi1, inner_semi2,
01110 mass, sister->mass);
01111 else if (multiple_type == APOCENTER_REFLECTION) {
01112
01113 int p = cerr.precision(HIGH_PRECISION);
01114 cerr << "\nfound partially stable multiple "
01115 << parent->format_label()
01116 << " at time " << time << endl;
01117 cerr.precision(p);
01118
01119 hdyn* pnode = find_perturber_node();
01120 if (!pnode)
01121 cerr << "pnode is NULL" << endl;
01122 else {
01123 PRC(pnode->format_label());
01124 PRL(pnode->n_perturbers);
01125 }
01126
01127 cerr << "outer period = " << outerkep.get_period() << endl;
01128 cerr << "inner period = ";
01129 if (inner_semi1 > 0)
01130 cerr << get_period(mass, inner_semi1) << " ";
01131 if (inner_semi2 > 0)
01132 cerr << get_period(sister->mass, inner_semi2);
01133 cerr << endl;
01134 }
01135 }
01136 }
01137
01138 if (stable_a && !stable_b && diag->report_multiple) {
01139 cerr << "\nmultiple " << parent->format_label()
01140 << " stable, components not, at time " << time
01141 << endl;
01142 }
01143 }
01144
01145 return stable_b;
01146 }
01147
01148
01149
01150 bool hdyn::is_unperturbed_and_approaching()
01151
01152
01153
01154
01155
01156
01157
01158
01159
01160
01161
01162
01163
01164
01165
01166
01167
01168
01169
01170
01171
01172
01173
01174
01175 {
01176 if (!options->allow_unperturbed) return false;
01177
01178
01179 if (diag->unpert_function_id) {
01180 cerr << ">> check is_unperturbed_and_approaching for "
01181 << format_label() << " at time " << system_time << endl;
01182 }
01183
01184 init_binary_type = binary_type = UNKNOWN_STATUS;
01185
01186
01187
01188
01189
01190
01191
01192
01193
01194
01195
01196 if (is_multiple(this)) {
01197
01198 init_binary_type = binary_type = MULTIPLE_CM;
01199
01200 if (!options->allow_multiples) return false;
01201
01202
01203
01204
01205
01206
01207
01208
01209
01210
01211
01212
01213
01214
01215
01216
01217 multiple_type = NOT_MULTIPLE;
01218 int weak_stat;
01219
01220 if (is_weakly_perturbed(weak_stat)) {
01221
01222 #if 0
01223 cerr << endl
01224 << format_label()
01225 << " is weakly perturbed at time " << time
01226 << " perturbation = " << sqrt(perturbation_squared)
01227 << endl;
01228 #endif
01229
01230 int stable_stat;
01231 if (is_stable(stable_stat)) {
01232
01233 init_binary_type = binary_type = STABLE_OUTER;
01234 return true;
01235
01236
01237
01238
01239
01240
01241
01242 }
01243
01244 } else {
01245
01246 #if 0
01247 cerr << endl
01248 << format_label() << " is not weakly perturbed at time "
01249 << time
01250 << endl
01251 << "perturbation = " << sqrt(perturbation_squared)
01252 << " status = " << weak_stat
01253 << " (" << wp[weak_stat] << ")"
01254 << endl;
01255 #endif
01256
01257 }
01258
01259 } else {
01260
01261
01262
01263 if (slow && slow->get_stop()) {
01264
01265
01266
01267
01268
01269
01270
01271
01272
01273 init_binary_type = binary_type = PERTURBED;
01274 return false;
01275 }
01276
01277
01278
01279
01280
01281
01282 if (get_parent()->get_kepler()) {
01283
01284
01285
01286
01287
01288
01289 init_binary_type = binary_type = UNPERTURBED_MULTIPLE_COMPONENT;
01290 return true;
01291 }
01292
01293 bool approaching = (posvel < 0);
01294
01295
01296 if (!approaching && !get_kepler() && !slow) {
01297
01298
01299
01300
01301
01302
01303
01304
01305
01306
01307
01308
01309
01310
01311
01312
01313
01314
01315 approaching = (posvel*posvel < 1.e-6 * square(pos)*square(vel));
01316 }
01317
01318 if (!approaching) {
01319
01320
01321
01322
01323 init_binary_type = binary_type = NOT_APPROACHING;
01324 return false;
01325 }
01326
01327 if (!find_perturber_node()) {
01328
01329
01330
01331
01332
01333
01334
01335 init_binary_type = binary_type = UNKNOWN_PERTURBERS;
01336
01337 if (kep) {
01338
01339
01340
01341
01342
01343
01344
01345 return true;
01346
01347 } else {
01348
01349
01350
01351
01352
01353
01354
01355 if (perturbation_squared < 0 || perturbation_squared > 1)
01356 return false;
01357
01358 }
01359 }
01360
01361 if (!get_kepler()
01362 && options->optimize_scheduling
01363 && !options->optimize_block) {
01364
01365
01366
01367
01368 int it = (int) get_system_time();
01369 real tt = get_system_time() - it;
01370 real dtt = timestep/get_kappa();
01371 it =(int)(tt/dtt + 0.1);
01372
01373
01374
01375
01376
01377 if (it%4 != 0) {
01378 init_binary_type = binary_type = DEFERRED;
01379 return false;
01380 }
01381 }
01382
01383
01384
01385
01386
01387
01388
01389
01390
01391
01392
01393 if ((perturbation_squared
01394 < gamma2 * options->partial_merge_factor)
01395 && is_low_level_leaf()
01396 && younger_sister->is_low_level_leaf()) {
01397
01398
01399
01400
01401
01402
01403
01404
01405
01406
01407 init_binary_type = binary_type = PERICENTER_REFLECTION;
01408 return true;
01409
01410 } else {
01411
01412 real pert_fac = 1;
01413
01414 if (!kep) {
01415
01416
01417
01418
01419
01420
01421 if ((perturbation_squared < options->full_merge_tolerance)
01422 && is_low_level_leaf()
01423 && younger_sister->is_low_level_leaf()) {
01424
01425
01426
01427
01428
01429
01430
01431
01432
01433
01434
01435
01436
01437
01438
01439
01440 if (get_parent()->timestep
01441 > 10 * timestep/get_kappa()) {
01442
01443 kepler kepl;
01444 hdyn *sister = get_binary_sister();
01445
01446 kepl.set_time(time);
01447 kepl.set_total_mass(parent->get_mass());
01448 kepl.set_rel_pos(pos - sister->pos);
01449 kepl.set_rel_vel(vel - sister->vel);
01450 kepl.initialize_from_pos_and_vel();
01451
01452
01453
01454
01455
01456
01457
01458
01459
01460 if (kepl.get_energy() < 0.0) {
01461
01462 if (KEP_OUTSIDE_SEMI(kepl)) {
01463
01464
01465
01466
01467
01468
01469
01470
01471 real dtp = get_parent()->get_next_time()
01472 - time;
01473 if (!slow) dtp += get_parent()->get_timestep();
01474
01475
01476
01477
01478
01479 if (kepl.get_period() < dtp) {
01480
01481
01482
01483
01484
01485
01486
01487
01488
01489
01490
01491
01492
01493
01494
01495
01496
01497
01498
01499
01500
01501
01502
01503
01504
01505
01506
01507 if (slow) {
01508
01509 if (!slow->get_stop()) {
01510 cerr << endl
01511 << "is_unperturbed_and_approaching:"
01512 << " scheduling end of slow motion"
01513 << endl
01514 << " "
01515 << " for " << format_label()
01516 << " at time " << get_system_time()
01517 << endl;
01518
01519 slow->set_stop();
01520 }
01521
01522 } else {
01523
01524
01525
01526
01527 init_binary_type = binary_type
01528 = FULL_MERGER;
01529
01530
01531
01532
01533
01534
01535
01536
01537
01538
01539
01540
01541 pert_fac = pow(kepl.get_apastron()
01542 / kepl.get_separation(),
01543 6);
01544
01545
01546
01547 }
01548 }
01549 }
01550 }
01551 }
01552 }
01553
01554 }
01555
01556 if (kep || binary_type == FULL_MERGER) {
01557
01558
01559
01560
01561 real crit_pert2 = options->full_merge_tolerance
01562 * options->relax_factor;
01563
01564
01565
01566 if (pert_fac*perturbation_squared < crit_pert2
01567 || is_close_pair()) {
01568
01569 if (kep)
01570 init_binary_type = binary_type = CONTINUE_MERGER;
01571
01572 return true;
01573
01574 }
01575 }
01576 }
01577 }
01578
01579
01580
01581
01582 init_binary_type = binary_type = PERTURBED;
01583 return false;
01584 }
01585
01586
01587
01588
01589
01590
01591 void hdyn::startup_unperturbed_motion()
01592 {
01593
01594
01595
01596
01597
01598
01599
01600
01601 if (diag->unpert_function_id) {
01602 cerr << endl << ">> startup_unperturbed_motion for "
01603 << format_label() << " at time " << system_time << endl;
01604 }
01605
01606 bool new_unpert = true;
01607 if (get_kepler()) new_unpert = false;
01608
01609
01610 update_kepler_from_hdyn();
01611
01612 fully_unperturbed = false;
01613
01614 if (diag->report_start_unperturbed) {
01615 if (binary_type != PERICENTER_REFLECTION
01616 || diag->report_pericenter_reflection) {
01617 print_startup_message(this, binary_type, new_unpert);
01618 }
01619 }
01620
01621
01622
01623
01624 int save_binary_type = binary_type;
01625
01626
01627
01628
01629
01630
01631
01632
01633
01634
01635
01636
01637
01638
01639
01640 if (slow) timestep /= get_kappa();
01641
01642
01643
01644
01645
01646
01647
01648
01649 real steps = set_unperturbed_timestep(true);
01650
01651
01652
01653
01654
01655
01656 if (slow) timestep *= get_kappa();
01657
01658
01659
01660
01661
01662 if (diag->report_start_unperturbed && binary_type != save_binary_type) {
01663
01664 if (save_binary_type == PERICENTER_REFLECTION
01665 && !diag->report_pericenter_reflection)
01666 print_startup_message(this, save_binary_type, new_unpert);
01667
01668 cerr << " binary_type changed to " << binary_type
01669 << ": " << bt[binary_type] << endl;
01670
01671 }
01672
01673
01674
01675
01676
01677
01678
01679
01680 if (steps < options->min_unpert_steps) {
01681
01682 if (diag->report_start_unperturbed
01683 || (steps <= 0 && diag->report_zero_unpert_steps)) {
01684 cerr << "\nstartup_unperturbed_motion: calculated step size = "
01685 << steps << endl
01686 << "do not apply unperturbed motion to " << format_label()
01687 << " at time " << system_time << "\n";
01688 }
01689
01690 delete kep;
01691 kep = NULL;
01692 unperturbed_timestep = -VERY_LARGE_NUMBER;
01693 get_binary_sister()->unperturbed_timestep = -VERY_LARGE_NUMBER;
01694 get_binary_sister()->kep = NULL;
01695
01696 if (slow)
01697 slow->set_stop(false);
01698
01699 return;
01700 }
01701
01702 unperturbed_timestep = timestep * steps;
01703 get_binary_sister()->unperturbed_timestep = unperturbed_timestep;
01704
01705
01706
01707 if (diag->report_start_unperturbed) {
01708 if (binary_type != PERICENTER_REFLECTION
01709 || diag->report_pericenter_reflection) {
01710
01711 cerr << " dt = " << timestep
01712 << " dt_unpert = " << unperturbed_timestep << endl;
01713
01714 if (diag->unpert_report_level > 0)
01715 print_unperturbed_binary_params();
01716
01717 }
01718 }
01719
01720
01721
01722
01723 if (is_multiple(this)) {
01724
01725 binary_type = STABLE_INNER;
01726
01727 if (is_parent())
01728 get_oldest_daughter()
01729 ->startup_unperturbed_motion();
01730
01731 if (get_binary_sister()->is_parent())
01732 get_binary_sister()->get_oldest_daughter()
01733 ->startup_unperturbed_motion();
01734 }
01735
01736
01737
01738
01739 if (!RESOLVE_UNPERTURBED_PERTURBERS && fully_unperturbed) {
01740
01741
01742
01743 hdynptr *cpt_list = new hdynptr[2*n_leaves()];
01744 int nl = 0;
01745
01746
01747
01748
01749 for_all_nodes(hdyn, get_parent(), bb)
01750 if (bb != get_parent()) cpt_list[nl++] = bb;
01751
01752 correct_perturber_lists(get_root(), cpt_list, nl, get_parent());
01753 delete [] cpt_list;
01754 }
01755
01756
01757
01758
01759
01760
01761
01762
01763
01764
01765
01766
01767
01768
01769
01770
01771
01772 #if 0
01773 putrq(get_parent()->get_dyn_story(), "unpert_startup_time",
01774 get_system_time());
01775 int ifull = fully_unperturbed;
01776 putiq(get_parent()->get_dyn_story(), "fully_unperturbed", ifull);
01777 #endif
01778
01779 }
01780
01781
01782
01783 real hdyn::set_unperturbed_timestep(bool check_phase)
01784
01785
01786
01787
01788
01789
01790
01791
01792
01793
01794
01795
01796
01797
01798
01799
01800
01801
01802
01803
01804
01805
01806
01807
01808 {
01809
01810
01811
01812
01813
01814
01815
01816
01817
01818
01819
01820
01821
01822
01823
01824
01825
01826
01827
01828 if (diag->unpert_function_id) {
01829 cerr << ">> set_unperturbed_timestep for "
01830 << format_label() << endl;
01831 }
01832
01833 if (!check_phase) {
01834
01835
01836 }
01837
01838 hdyn * sister = get_binary_sister();
01839 real steps = 0;
01840
01841
01842
01843 if (is_multiple(this)) {
01844
01845
01846
01847
01848 } else {
01849
01850
01851
01852
01853 binary_type = PERICENTER_REFLECTION;
01854
01855
01856
01857
01858
01859
01860 real mean_anomaly = kep->get_mean_anomaly();
01861 if (kep->get_energy() < 0)
01862 mean_anomaly = sym_angle(mean_anomaly);
01863
01864 if (mean_anomaly >= 0) {
01865
01866
01867
01868
01869 steps = 0;
01870
01871 } else {
01872
01873 real peri_time = -mean_anomaly / kep->get_mean_motion();
01874 steps = ceil(2 * peri_time / timestep);
01875
01876
01877
01878
01879
01880
01881 if (slow) steps -= 1;
01882
01883 }
01884 }
01885
01886 if (kep->get_energy() < 0) {
01887
01888
01889
01890 if (is_multiple(this) && multiple_type == APOCENTER_REFLECTION) {
01891
01892
01893
01894
01895
01896
01897
01898 real apo_time = (xreal)kep->pred_advance_to_periastron()
01899 - time - (xreal)(0.5*kep->get_period());
01900 real steps = floor(((2 * apo_time) / timestep));
01901
01902
01903
01904
01905 if (diag->report_multiple) {
01906 cerr << "multiple (" << tt[multiple_type] << "): "
01907 << format_label() << endl;
01908 PRC(apo_time), PRC(kep->get_period()); PRL(steps);
01909 }
01910
01911 binary_type = STABLE_OUTER;
01912
01913 } else if (!check_phase
01914 || KEP_OUTSIDE_SEMI(*kep)
01915 || (get_parent()->kep != NULL)) {
01916
01917
01918
01919
01920
01921
01922
01923
01924
01925
01926
01927 if (slow) {
01928
01929 if (!slow->get_stop()) {
01930 cerr << "set_unperturbed_timestep (#1): "
01931 << "scheduling end of slow motion"
01932 << endl
01933 << " for "
01934 << format_label()
01935 << " at time " << get_system_time() << endl;
01936 slow->set_stop();
01937 }
01938
01939
01940
01941
01942 } else {
01943
01944
01945
01946
01947
01948
01949
01950
01951
01952
01953
01954
01955
01956
01957
01958
01959
01960
01961
01962
01963 real usteps = get_unperturbed_steps(!is_multiple(this));
01964
01965
01966
01967
01968
01969
01970 if (usteps <= 0) {
01971
01972 if (diag->report_zero_unpert_steps) {
01973
01974 cerr << endl << " set_unperturbed_timestep: "
01975 << "zero step for unperturbed binary\n";
01976
01977 int p = cerr.precision(HIGH_PRECISION);
01978 PRI(4); PRL(time);
01979 cerr << " parent: " << get_parent()->format_label()
01980 << endl;
01981 PRI(4); PRL((get_parent()->get_next_time()));
01982 PRI(4); PRL(kep->get_period());
01983 PRI(4); PRL(usteps);
01984 cerr.precision(p);
01985 }
01986
01987
01988
01989 } else {
01990
01991 steps = usteps;
01992 binary_type = FULL_MERGER;
01993
01994 fully_unperturbed = true;
01995
01996 }
01997 }
01998 }
01999
02000
02001
02002
02003
02004
02005
02006
02007
02008
02009
02010
02011
02012
02013
02014
02015
02016
02017
02018 if (binary_type == PERICENTER_REFLECTION && KEP_OUTSIDE_SEMI(*kep)) {
02019
02020
02021
02022 #if 0
02023
02024
02025 cerr << endl
02026 << "**** binary_type == PERICENTER_REFLECTION "
02027 << "&& KEP_OUTSIDE_SEMI(*kep) ****"
02028 << endl << endl;
02029 #endif
02030
02031 if (slow) {
02032
02033 if (!slow->get_stop()) {
02034 cerr << "set_unperturbed_timestep (#2): "
02035 << "scheduling end of slow motion"
02036 << endl
02037 << " for "
02038 << format_label()
02039 << " at time " << get_system_time() << endl;
02040 slow->set_stop();
02041 }
02042
02043
02044
02045
02046 } else {
02047 steps = ceil(kep->get_period()/timestep);
02048 binary_type = FULL_MERGER;
02049 fully_unperturbed = true;
02050 }
02051 }
02052 }
02053
02054
02055
02056
02057
02058 unperturbed_timestep = timestep * steps;
02059 if (slow) unperturbed_timestep *= get_kappa();
02060
02061 sister->kep = kep;
02062 sister->unperturbed_timestep = unperturbed_timestep;
02063 sister->fully_unperturbed = fully_unperturbed;
02064
02065 if (steps < 0) {
02066 cerr << endl
02067 << "set_unperturbed_timestep: steps negative!"
02068 << " -- the code will break soon...;-("
02069 << endl;
02070 PRC(timestep); PRC(steps); PRL(unperturbed_timestep);
02071 kep->print_all();
02072 }
02073
02074 return steps;
02075 }
02076
02077
02078
02079 local xreal latest_time(xreal t_min, xreal t_max, real dtblock,
02080 real ma_min, real ma_max,
02081 real mean_anomaly, real mean_motion)
02082 {
02083
02084
02085
02086
02087
02088
02089
02090
02091 if (ma_min < -PI) return t_min;
02092 if (ma_max >= 0) return t_min;
02093 if (ma_min >= ma_max) return t_min;
02094
02095 real f = floor((real)t_max / dtblock);
02096 xreal t_last = dtblock * f;
02097
02098 if (t_last <= t_min) return t_min;
02099
02100
02101
02102
02103 real ma = sym_angle(mean_anomaly + mean_motion * (real)(t_last - t_min));
02104
02105 if (ma > ma_min && ma < ma_max) return t_last;
02106
02107
02108
02109 real dma = sym_angle(dtblock * mean_motion);
02110
02111 if (dma == 0) return t_min;
02112
02113
02114
02115
02116
02117
02118 ma -= ma_min;
02119 ma_max -= ma_min;
02120 ma_min = 0;
02121
02122
02123
02124
02125
02126
02127
02128
02129 if (dma < 0 && dma > -ma_max) {
02130
02131
02132
02133
02134 t_last -= dtblock * ceil((2*M_PI - ma) / (-dma));
02135
02136 } else if (dma > 0 && dma < ma_max) {
02137
02138
02139
02140
02141 t_last -= dtblock * ceil((ma - ma_max) / dma);
02142
02143 } else {
02144
02145
02146
02147 while (t_last > t_min) {
02148 t_last -= dtblock;
02149 ma -= dma;
02150 if (ma <= 0) ma += 2*M_PI;
02151 if (ma > 2*M_PI) ma -= 2*M_PI;
02152
02153 if (ma < ma_max) break;
02154 }
02155 }
02156
02157 return t_last;
02158 }
02159
02160 real hdyn::get_unperturbed_steps(bool to_apo,
02161
02162 bool predict)
02163
02164
02165
02166
02167
02168
02169
02170
02171
02172
02173
02174
02175 {
02176
02177
02178
02179
02180
02181
02182
02183
02184
02185
02186
02187
02188
02189
02190
02191 hdyn * p = get_parent();
02192 if (p->is_low_level_node() && p->get_elder_sister() != NULL)
02193 p = p->get_elder_sister();
02194
02195 real pdt = p->get_next_time() - time;
02196
02197 if (pdt > unpert_step_limit) {
02198 if (diag->report_continue_unperturbed)
02199 cerr << "get_unperturbed_steps: unperturbed step for "
02200 << format_label()
02201 << " limited by unpert_step_limit" << endl;
02202 pdt = unpert_step_limit;
02203 }
02204
02205
02206
02207
02208
02209 if (pdt < system_time - time) {
02210 if (diag->report_continue_unperturbed)
02211 cerr << "get_unperturbed_steps: unpert step for "
02212 << format_label()
02213 << " increased to reach system_time" << endl;
02214 pdt = system_time - time;
02215 }
02216
02217 if (pdt < 0) {
02218 cerr << endl << "get_unperturbed_steps: ";
02219 PRC(p->get_next_time()); PRL(time);
02220 pp3(p);
02221 cerr << "*no* corrective action taken\n";
02222 return 0;
02223 }
02224
02225 real pdt2 = pdt + dt_overshoot(this);
02226
02227
02228
02229
02230 if (USE_DT_PERTURBERS && is_multiple(this)) {
02231
02232
02233
02234 real pert_dt = dt_perturbers(this);
02235 if (pert_dt > 0) pdt2 = max(pdt2, 0.25*pert_dt);
02236 }
02237
02238
02239
02240
02241
02242
02243
02244
02245
02246
02247
02248
02249
02250
02251
02252
02253
02254
02255
02256
02257
02258
02259
02260
02261
02262
02263
02264
02265
02266
02267
02268
02269
02270
02271
02272
02273
02274
02275
02276
02277
02278
02279
02280
02281
02282
02283
02284
02285
02286
02287
02288 real orb = ceil(pdt / kep->get_period());
02289
02290
02291
02292
02293 if (orb <= 0) {
02294
02295
02296
02297
02298 if (kep->get_period() <= pdt2)
02299 orb = 1;
02300
02301
02302
02303
02304 }
02305
02306 real mean_anomaly = sym_angle(kep->get_mean_anomaly());
02307
02308
02309
02310 real pert_steps = 0;
02311
02312 if (to_apo) {
02313
02314
02315
02316
02317
02318
02319 real apo_time = (M_PI - mean_anomaly) / kep->get_mean_motion();
02320
02321
02322
02323
02324
02325
02326
02327
02328
02329 if (mean_anomaly > 0.9*M_PI
02330 && kep->get_period() < pdt2) apo_time += kep->get_period();
02331
02332 pert_steps = ceil( (max(0.0, orb - 1) * kep->get_period() + apo_time)
02333 / timestep
02334 + 1);
02335
02336
02337
02338
02339
02340
02341
02342 } else {
02343
02344 pert_steps = floor(orb * kep->get_period() / timestep);
02345
02346
02347
02348
02349
02350
02351
02352
02353 }
02354
02355
02356
02357
02358 if (time + pert_steps*timestep < system_time) {
02359 if (diag->report_continue_unperturbed)
02360 cerr << "get_unperturbed_steps: unpert step for "
02361 << format_label()
02362 << " increased to reach system_time" << endl;
02363 pert_steps += ceil(kep->get_period() / timestep);
02364 }
02365
02366
02367
02368 real d_mean_anomaly = timestep * kep->get_mean_motion();
02369 real end_mean_anomaly = sym_angle(mean_anomaly
02370 + pert_steps * d_mean_anomaly);
02371 int mcount = 0;
02372
02373 if (end_mean_anomaly > 0) {
02374
02375
02376
02377
02378
02379 mcount = (int)(kep->get_period() / timestep);
02380
02381 while (end_mean_anomaly <= M_PI && mcount > 0) {
02382 end_mean_anomaly += d_mean_anomaly;
02383 pert_steps += 1;
02384 mcount--;
02385 }
02386
02387 if (end_mean_anomaly >= M_PI) end_mean_anomaly -= 2*M_PI;
02388
02389 if (false && mcount <= 0)
02390 cerr << "get_unperturbed_steps: mcount = 0 for "
02391 << format_label() << " at time " << time << endl;
02392 }
02393
02394
02395
02396
02397
02398
02399 if (pert_steps > 0 && options->optimize_scheduling) {
02400
02401
02402
02403
02404
02405
02406
02407
02408
02409
02410
02411 if (!options->optimize_block) {
02412
02413
02414
02415
02416
02417
02418
02419
02420
02421
02422 int minus = (int)((end_mean_anomaly + M_PI) / d_mean_anomaly);
02423 int plus = (int)((-0.9*M_PI - end_mean_anomaly) / d_mean_anomaly);
02424
02425
02426
02427 if (minus > pert_steps/2) minus = (int)(pert_steps/2);
02428 if (plus > pert_steps/2) plus = (int)(pert_steps/2);
02429
02430
02431
02432 real new_steps = pert_steps - minus;
02433 real p2 = 2;
02434 while (new_steps <= pert_steps + plus) {
02435
02436 if (fmod(new_steps, p2) != 0) new_steps += p2/2;
02437
02438
02439
02440 p2 *= 2;
02441 }
02442
02443
02444
02445 p2 /= 2;
02446 new_steps -= p2/2;
02447
02448
02449
02450 pert_steps = new_steps;
02451
02452 } else {
02453
02454
02455
02456
02457
02458
02459
02460
02461
02462
02463
02464
02465
02466
02467
02468
02469
02470
02471
02472
02473
02474
02475
02476
02477
02478
02479
02480
02481
02482 xreal t_min = time + kep->get_period();
02483 xreal t_max = p->get_next_time() + 0.5*p->get_timestep();
02484
02485
02486
02487 real ma_min = -0.999*M_PI;
02488 real ma_max = -0.900*M_PI;
02489
02490
02491
02492
02493 xreal t_next = t_min;
02494 real dtblock;
02495 int kb;
02496
02497 for (kb = 0, dtblock = 1; dtblock >= timestep; kb++, dtblock /= 2)
02498 if ((t_next = latest_time(t_min, t_max, dtblock,
02499 ma_min, ma_max,
02500 mean_anomaly, kep->get_mean_motion()))
02501 > t_min)
02502 break;
02503
02504
02505
02506 #if 0
02507 cerr << endl << "get_unperturbed_steps for "
02508 << format_label() << " at time " << system_time<< ":"
02509 << endl;
02510 PRI(4); PRL(pert_steps);
02511 PRI(4); PRL(get_effective_block(time));
02512 PRI(4); PRL(get_effective_block(timestep));
02513 PRI(4); PRL(get_effective_block(pert_steps*timestep));
02514 PRI(4); PRL(get_effective_block(time+pert_steps*timestep));
02515
02516 #endif
02517 if (t_next <= t_min
02518 || kb >= get_effective_block(time+pert_steps*timestep)) {
02519
02520
02521
02522
02523 #if 0
02524 cerr << " retaining unoptimized pert_steps" << endl;
02525 #endif
02526
02527 } else {
02528
02529 real old_steps = pert_steps;
02530 pert_steps = floor(((real)(t_next - time)) / timestep + 0.1);
02531
02532 #if 0
02533 PRI(4); PRC(kb); PRC(dtblock); PRL(dtblock/timestep);
02534 PRI(4); PRC(pert_steps); PRL(pert_steps/old_steps);
02535 PRI(4); PRL(get_effective_block(pert_steps*timestep));
02536 PRI(4); PRL(get_effective_block(time+pert_steps*timestep));
02537
02538 if (get_effective_block(time+pert_steps*timestep) != kb)
02539 cerr << " ????" << endl;
02540 #endif
02541
02542 }
02543 }
02544 }
02545
02546 return pert_steps;
02547 }
02548
02549
02550
02551 bool hdyn::integrate_unperturbed_motion(bool& reinitialize,
02552 bool force_time)
02553 {
02554
02555
02556
02557
02558
02559
02560
02561
02562
02563
02564
02565
02566
02567
02568 if (diag->unpert_function_id) {
02569 cerr << endl << ">> integrate_unperturbed_motion for "
02570 << format_label() << " at time " << system_time << endl;
02571 }
02572
02573 bool unpert = true;
02574 reinitialize = false;
02575
02576 if (!kep) return false;
02577
02578 hdyn *sister = get_binary_sister();
02579 time += unperturbed_timestep;
02580
02581 if (slow) slow->inc_tau(unperturbed_timestep/get_kappa());
02582
02583 if (time != system_time) {
02584
02585
02586
02587
02588
02589
02590
02591
02592
02593
02594
02595 real dt = time - system_time;
02596 if (dt != 0) {
02597
02598 if (!force_time && diag->report_continue_unperturbed) {
02599
02600 cerr << endl << "integrate_unperturbed_motion for "
02601 << format_label() << endl;
02602
02603 int p = cerr.precision(HIGH_PRECISION);
02604 cerr << "time and system_time are different:" << endl;
02605 PRC(time); PRL(system_time);
02606
02607
02608
02609
02610
02611 cerr << "Forcing time to system time..." << endl;
02612 cerr.precision(p);
02613 }
02614 time = system_time;
02615 }
02616 }
02617
02618
02619
02620 real initial_sep_sq = kep->get_separation() * kep->get_separation();
02621
02622
02623
02624
02625
02626
02627
02628
02629
02630
02631
02632
02633
02634
02635
02636
02637
02638 update_dyn_from_kepler();
02639
02640
02641
02642
02643
02644
02645
02646
02647
02648
02649
02650
02651
02652
02653
02654
02655
02656
02657
02658
02659
02660
02661 bool save_unpert = fully_unperturbed;
02662 fully_unperturbed = false;
02663
02664 if (unperturbed_timestep < kep->get_period()) {
02665 kc->partial_unpert_orbit++;
02666
02667 }
02668 else {
02669 kc->full_unpert_step++;
02670 kc->full_unpert_orbit += (int) (unperturbed_timestep
02671 / kep->get_period());
02672
02673
02674 }
02675
02676 #if 0
02677 if (streq(format_label(), "xxx")) {
02678 cerr << "in integrate_unperturbed motion for " << format_label()
02679 << endl;
02680 get_kepler()->print_all();
02681 }
02682 #endif
02683
02684
02685
02686
02687 bool is_u = is_unperturbed_and_approaching();
02688
02689 #if 0
02690 if (streq(format_label(), "xxx")) {
02691 PRL(posvel);
02692 PRL(is_u);
02693 }
02694 #endif
02695
02696
02697
02698 real set_u = 0;
02699
02700
02701
02702
02703 if (is_u)
02704 set_u = set_unperturbed_timestep(!force_time);
02705
02706
02707
02708
02709
02710 if (is_u && set_u) {
02711
02712
02713
02714 if (diag->report_continue_unperturbed
02715 || (diag->report_multiple && is_multiple(this)
02716 && (diag->multiple_report_level > 0
02717 || diag->unpert_report_level > 0))) {
02718
02719 int p = cerr.precision(HIGH_PRECISION);
02720 cerr << "\ncontinuing unperturbed motion for "
02721 << format_label();
02722 cerr << " and " << get_binary_sister()->format_label()
02723 << endl
02724 << " at time " << time << " (next: " << set_u << " steps)"
02725 << endl;
02726
02727 cerr.precision(p);
02728 cerr << " dt = " << timestep
02729 << " dt_unpert = " << unperturbed_timestep
02730 << " period = " << get_kepler()->get_period()
02731 << endl
02732 << " perturbation = " << sqrt(perturbation_squared)
02733 << " (" << bt[init_binary_type] << ")"
02734 << endl;
02735
02736 if (diag->unpert_report_level > 0)
02737 print_unperturbed_binary_params();
02738
02739 }
02740
02741 } else {
02742
02743
02744
02745 unpert = false;
02746
02747
02748
02749
02750
02751 bool verbose = diag->report_end_unperturbed
02752 || (is_multiple(this) && diag->report_multiple);
02753
02754
02755
02756
02757
02758
02759
02760
02761 if (save_unpert && !RESOLVE_UNPERTURBED_PERTURBERS)
02762 expand_perturber_lists(get_root(), get_parent(), verbose);
02763
02764
02765
02766
02767
02768 if (verbose) {
02769
02770
02771
02772 if (binary_type != NOT_APPROACHING
02773 || diag->report_pericenter_reflection
02774 || fully_unperturbed) {
02775
02776 int p = cerr.precision(HIGH_PRECISION);
02777 cerr << "\nending unperturbed motion for "
02778 << format_label();
02779 cerr << " and " << get_binary_sister()->format_label()
02780 << " at time " << time << endl;
02781 cerr << bt[binary_type] << " (binary_type = " << binary_type;
02782
02783 cerr.precision(p);
02784 cerr << ") perturbation = " << sqrt(perturbation_squared);
02785
02786 hdyn *pnn = get_parent()->get_nn();
02787 if (pnn && pnn->is_valid())
02788 cerr << " (" << pnn->format_label() << ")";
02789
02790 cerr << endl;
02791
02792 if (diag->unpert_report_level > 0
02793 || diag->end_unpert_report_level > 0) {
02794
02795 print_unperturbed_binary_params();
02796
02797 if (binary_type != NOT_APPROACHING) {
02798
02799 hdyn* p = get_parent();
02800 hdyn* pnn = p->get_nn();
02801
02802 print_binary_from_dyn_pair(this, get_binary_sister(),
02803 0, 0, true);
02804 cerr << endl;
02805 if (pnn) {
02806 print_binary_from_dyn_pair(p, pnn, 0, 0, true);
02807 cerr << endl;
02808 } else
02809 cerr << "nn is NULL" << endl;
02810
02811 if (pnn
02812 && (diag->unpert_report_level > 1
02813 || diag->end_unpert_report_level > 1)) {
02814
02815 pp3_minimal(get_top_level_node(), cerr);
02816
02817
02818
02819
02820 kepler outerkep;
02821
02822 outerkep.set_time(time);
02823 outerkep.set_total_mass(p->get_mass());
02824 outerkep.set_rel_pos(p->pos - pnn->pos);
02825 outerkep.set_rel_vel(p->vel - pnn->vel);
02826 outerkep.initialize_from_pos_and_vel();
02827
02828 real r_end = outerkep.get_separation();
02829 if (perturbation_squared
02830 > options->full_merge_tolerance)
02831 r_end
02832 *= sqrt(perturbation_squared
02833 / options->full_merge_tolerance);
02834 if (r_end > outerkep.get_apastron())
02835 r_end = 0.9999*outerkep.get_apastron();
02836 real transit_time
02837 = 2 * (outerkep.pred_advance_to_radius(r_end)
02838 - (real)time);
02839
02840 real ave_step
02841 = timestep * sqrt(kep->get_periastron()
02842 /kep->get_separation());
02843
02844 PRI(4); PRL(transit_time);
02845 PRI(4); PRL(ave_step);
02846
02847 hdyn *pnode = find_perturber_node();
02848 if (pnode) {
02849 cerr << " estimate "
02850 << 2 * pnode->n_perturbers
02851 * (transit_time/ave_step) / 1e6
02852 << " million force calculations to"
02853 << " end of encounter"
02854 << endl;
02855 cerr << " perturber node: "
02856 << pnode->format_label()
02857 << endl;
02858 cerr << " n_pert = "
02859 << pnode->n_perturbers
02860 << endl;
02861 PRI(4); print_nn(find_perturber_node(), 2);
02862 }
02863
02864 PRI(4); PRC(is_u); PRL(set_u);
02865 }
02866 }
02867 }
02868 }
02869
02870 #if 0
02871 if (streq(format_label(), "xxx"))
02872 get_kepler()->print_all();
02873 #endif
02874
02875 }
02876
02877 bool update_dynamics[2] = {false, false};
02878
02879
02880
02881
02882
02883
02884
02885
02886
02887
02888
02889
02890 if (get_use_dstar() && has_dstar(this)) {
02891
02892 create_or_delete_binary(get_parent(),
02893 update_dynamics);
02894
02895
02896
02897
02898
02899
02900
02901
02902 if (!is_valid()) {
02903 reinitialize = true;
02904 return false;
02905 }
02906
02907
02908
02909
02910
02911
02912
02913
02914
02915 if (!update_dynamics[0] && update_dynamics[1]) {
02916
02917 if (diag->report_start_unperturbed ||
02918 diag->report_continue_unperturbed ||
02919 diag->report_end_unperturbed)
02920 cerr << "\nCorrected timestep for change "
02921 << "in binary elements.\n";
02922
02923 update_dyn_from_kepler();
02924
02925
02926 set_first_timestep(0.5*kep->get_period());
02927 get_binary_sister()->timestep = timestep;
02928
02929 get_parent()->mass = mass + get_binary_sister()->get_mass();
02930 }
02931
02932 reinitialize = update_dynamics[0];
02933 if (reinitialize)
02934 cerr << "integrate_unperturbed_motion: reinitialization "
02935 << "forced by binary evolution" << endl
02936 << "parent = " << get_parent()->format_label()
02937 << " time = " << get_system_time() << endl;
02938 }
02939
02940
02941
02942
02943 delete kep;
02944 kep = NULL;
02945 get_binary_sister()->kep = NULL;
02946 unperturbed_timestep = -VERY_LARGE_NUMBER;
02947 get_binary_sister()->unperturbed_timestep = -VERY_LARGE_NUMBER;
02948 fully_unperturbed = false;
02949 get_binary_sister()->fully_unperturbed = false;
02950
02951
02952
02953 if (!(update_dynamics[0] || update_dynamics[1])) {
02954
02955
02956
02957 real sep_sq = square(pos - get_binary_sister()->pos);
02958
02959 if (sep_sq < 0.75*initial_sep_sq) {
02960
02961
02962
02963 real target_timestep = timestep
02964 * pow(sep_sq/initial_sep_sq, 0.75);
02965 while (timestep > target_timestep) timestep /= 2;
02966
02967 if (diag->report_continue_unperturbed)
02968 cerr << "\nintegrate_unperturbed_motion: timestep for "
02969 << format_label() << " reduced to " << timestep
02970 << " on restart at time " << time << endl;
02971
02972 get_binary_sister()->timestep = timestep;
02973 }
02974 }
02975 }
02976
02977 return unpert;
02978 }