00001
00002
00003
00004
00005
00006 #include "double_star.h"
00007
00008 #define REPORT_BINARY_EVOLUTION false
00009 #define REPORT_RECURSIVE_EVOLUTION false
00010 #define REPORT_FUNCTION_NAMES false
00011 #define REPORT_TRANFER_STABILITY false
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 double_star * new_double_star(node* n, real sma, real ecc,
00022 real start_time, int id,
00023 binary_type type)
00024 {
00025 double_star* element = new double_star(n);
00026 element->initialize(type, sma, ecc, start_time, id);
00027
00028 element->set_donor_timescale(element->get_primary(), true);
00029
00030 element->determine_minimal_timestep();
00031
00032 element->evolve_element(start_time);
00033
00034 element->post_constructor();
00035
00036 return element;
00037 }
00038
00039 double_star::double_star(node* n) : star(n) {
00040
00041 semi=eccentricity=binary_age=minimal_timestep=velocity=0;
00042 donor_timescale=0;
00043 identity = donor_identity=0;
00044 donor_type=NAS;
00045 first_contact=FALSE;
00046 }
00047
00048 void double_star::initialize(binary_type type, real sma,
00049 real ecc, real age, int id) {
00050
00051 semi = sma;
00052 eccentricity = ecc;
00053 bin_type = type;
00054 binary_age = age;
00055 identity = id;
00056
00057 initial.semi = semi;
00058 initial.q = mass_ratio();
00059 initial.mass_prim = get_primary()->get_total_mass();
00060 initial.eccentricity = eccentricity;
00061
00062 get_primary()->set_identity(0);
00063 get_secondary()->set_identity(1);
00064
00065 refresh_memory();
00066 }
00067
00068 real double_star::mass_ratio() {
00069 real mp = get_primary()->get_total_mass();
00070 real ms = get_secondary()->get_total_mass();
00071
00072 real q = ms/mp;
00073 if (q>1) q = mp/ms;
00074
00075 return q;
00076 }
00077
00078 real double_star::get_evolve_timestep() {
00079
00080 real delta_t = cnsts.safety(maximum_timestep);
00081
00082 if (bin_type != Merged) {
00083 if (get_primary()->get_evolve_timestep() <
00084 get_secondary()->get_evolve_timestep())
00085 return min(delta_t, get_primary()->get_evolve_timestep());
00086 else
00087 return min(delta_t, get_secondary()->get_evolve_timestep());
00088 }
00089 else {
00090 return min(delta_t, get_primary()->get_evolve_timestep());
00091 }
00092
00093 }
00094
00095
00096 binary_type double_star::obtain_binary_type() {
00097
00098 binary_type type_of_binary = Unknown_Binary_Type;
00099
00100 real rl_p = roche_radius(get_primary());
00101 real rl_s = roche_radius(get_secondary());
00102
00103 real rp = get_primary()->get_effective_radius();
00104 real rs = get_secondary()->get_effective_radius();
00105
00106
00107
00108
00109
00110
00111
00112 if (semi <= 0 && eccentricity <= 0)
00113 type_of_binary = Merged;
00114 else if (eccentricity >= 1)
00115 type_of_binary = Disrupted;
00116 else if (rp >= rl_p || rs > rl_s)
00117 type_of_binary = Semi_Detached;
00118 else if (rp >= rl_p && rs >= rl_s)
00119 type_of_binary = Contact;
00120 else if (semi <= rp * cnsts.parameters(tidal_circularization_radius) ||
00121 semi <= rs * cnsts.parameters(tidal_circularization_radius))
00122 type_of_binary = Synchronized;
00123 else
00124 type_of_binary = Detached;
00125
00126
00127
00128 return type_of_binary;
00129 }
00130
00131 real double_star::roche_radius(star * str) {
00132
00133
00134
00135
00136
00137 if (bin_type == Merged || bin_type == Disrupted)
00138 return VERY_LARGE_NUMBER;
00139
00140 real mr = str->get_total_mass()
00141 / str->get_companion()->get_total_mass();
00142 real q1_3 = pow(mr, cnsts.mathematics(one_third));
00143 real q2_3 = pow(q1_3, 2);
00144
00145 return semi*0.49*q2_3/(0.6*q2_3 + log(1 + q1_3));
00146 }
00147
00148 real double_star::roche_radius(const real a, const real m1, const real m2) {
00149
00150 real q = m1/m2;
00151 real q1_3 = pow(q, cnsts.mathematics(one_third));
00152 real q2_3 = pow(q1_3, 2);
00153
00154 return a*0.49*q2_3/(0.6*q2_3 + log(1 + q1_3));
00155 }
00156
00157 void double_star::put_element() {
00158
00159
00160
00161 ofstream outfile("binev.data", ios::app|ios::out);
00162 if(!outfile) cerr << "error: couldn't create file binev.data"<<endl;
00163
00164 outfile << identity << "\t" << binary_age << endl;
00165 outfile << identity << endl;
00166 get_primary()->put_element();
00167 get_secondary()->put_element();
00168
00169 initial.put_element();
00170 outfile << bin_type << " " << eccentricity << " "
00171 << get_period() << " " << semi << " " << velocity << "\n" << endl;
00172
00173 outfile.close();
00174 }
00175
00176 void double_star::put_hrd(ostream & s) {
00177
00178 s << "2\n ";
00179 get_primary()->put_hrd(s);
00180 s << " ";
00181 get_secondary()->put_hrd(s);
00182 }
00183
00184
00185 void double_star::print_status() {
00186 cout << "status at time = " << binary_age << endl;
00187
00188 if (get_primary()->no_of_elements()>1)
00189 get_primary()->print_status();
00190 if (get_secondary()->no_of_elements()>1)
00191 get_secondary()->print_status();
00192
00193 cout << type_string(bin_type);
00194 switch (bin_type) {
00195 case Merged:
00196 cout << " {" << type_string(get_primary()->get_element_type())
00197 << "}" << endl;
00198 cout << "M = "<<get_primary()->get_total_mass()
00199 << "\t R = "<<get_primary()->get_effective_radius()
00200 << "\t V = "<<get_primary()->get_velocity() << endl;
00201 break;
00202 case Disrupted:
00203 cout << " )" << type_string(get_primary()->get_element_type())
00204 << ", " << type_string(get_secondary()->get_element_type())
00205 << "(" << endl;
00206 cout << "M = "<<get_primary()->get_total_mass()
00207 << "\t R = "<<get_primary()->get_effective_radius()
00208 << "\t V = "<<get_primary()->get_velocity() << endl;
00209 cout << "m = "<<get_secondary()->get_total_mass()
00210 << "\t r = "<<get_secondary()->get_effective_radius()
00211 << "\t v = "<<get_secondary()->get_velocity() << endl;
00212 break;
00213 default:
00214 if (get_primary()->get_spec_type(Rl_filling))
00215 cout << " [";
00216 else
00217 cout << " (";
00218 cout << type_string(get_primary()->get_element_type())
00219 << ", " << type_string(get_secondary()->get_element_type());
00220 if (get_secondary()->get_spec_type(Rl_filling))
00221 cout << "]" << endl;
00222 else
00223 cout << ")" << endl;
00224 cout << "M = "<<get_primary()->get_total_mass()
00225 << "\t R = "<<get_primary()->get_effective_radius() << endl;
00226 cout << "m = "<<get_secondary()->get_total_mass()
00227 << "\t r = "<<get_secondary()->get_effective_radius() << endl;
00228 cout << "a = "<<semi<<"\t e = "<<eccentricity
00229 << "\t v = "<<get_velocity() << endl;
00230 }
00231 }
00232
00233 void double_star::put_state() {
00234
00235 star *a, *b;
00236 if (get_use_hdyn()) {
00237 a = get_primary();
00238 b = get_secondary();
00239 }
00240 else {
00241 a = get_initial_primary();
00242 b = get_initial_secondary();
00243 }
00244
00245 switch (bin_type) {
00246 case Merged:
00247 cerr << " {";
00248 get_primary()->put_state();
00249 cerr << "}" << endl;
00250 break;
00251 case Disrupted:
00252 cerr << " )";
00253 a->put_state();
00254 cerr << ", ";
00255 b->put_state();
00256 cerr << "(" << endl;
00257 break;
00258 default:
00259 if (a->get_spec_type(Rl_filling))
00260 cerr << " [";
00261 else
00262 cerr << " (";
00263 a->put_state();
00264 cerr << ", ";
00265 b->put_state();
00266 if (b->get_spec_type(Rl_filling))
00267 cerr << "]";
00268 else
00269 cerr << ")";
00270
00271 real pday = get_period();
00272 if (pday<0.04)
00273 cerr << " Porb = " << pday*1440 << " minutes";
00274 else if (pday<1)
00275 cerr << " Porb = " << pday*24 << " hours";
00276 else if (pday<365.25)
00277 cerr << " Porb = " << pday << " days";
00278 else
00279 cerr << " Porb = " << pday/365.25 << " years";
00280 }
00281 }
00282
00283 void double_star::print_roche() {
00284
00285
00286 if (bin_type!=Merged) {
00287 get_initial_primary()->print_roche();
00288 get_initial_secondary()->print_roche();
00289 }
00290 else get_primary()->print_roche();
00291
00292 cerr<<get_period();
00293 }
00294
00295 void double_star::dump(ostream & s, bool brief) {
00296
00297
00298 if (brief) {
00299 star* stp = get_initial_primary();
00300 star* sts = get_initial_secondary();
00301
00302 real m1 = stp->get_total_mass();
00303 real m2 = sts->get_total_mass();
00304
00305 real primary_roche_lobe, secondary_roche_lobe;
00306 if (bin_type==Merged || bin_type==Disrupted) {
00307 primary_roche_lobe = 2 * stp->get_effective_radius();
00308 secondary_roche_lobe = 2 * sts->get_effective_radius();
00309 }
00310 else {
00311 primary_roche_lobe = roche_radius(semi, m1, m2);
00312 secondary_roche_lobe = roche_radius(semi, m2, m1);
00313 }
00314
00315 s << identity << " "
00316 << binary_age << " "
00317 << semi << " "
00318 << eccentricity << " "
00319
00320 << stp->get_node()->format_label() << " "
00321 << stp->get_element_type() << " "
00322 << m1 << " "
00323 << primary_roche_lobe - stp->get_effective_radius() << " "
00324
00325 << sts->get_node()->format_label() << " "
00326 << sts->get_element_type() << " "
00327 << m2 << " "
00328 << secondary_roche_lobe - sts->get_effective_radius()
00329 << endl;
00330
00331
00332
00333
00334
00335
00336 }
00337 else {
00338 if(bin_type!=Merged) {
00339
00340 int n_elements = no_of_elements();
00341
00342 s << n_elements
00343 << "\n " << identity
00344 << " " << binary_age
00345 << " " << bin_type
00346 << " " << eccentricity
00347 << " " << get_period()
00348 << " " << semi
00349 << " " << velocity
00350 << endl;
00351 initial.dump(s);
00352
00353 s << " ";
00354 get_primary()->dump(s, brief);
00355 s << " ";
00356 get_secondary()->dump(s, brief);
00357 }
00358 else get_primary()->dump(s, brief);
00359 }
00360 }
00361
00362 void double_star::dump(char * filename, bool brief) {
00363
00364
00365 ofstream s(filename, ios::app|ios::out);
00366 if (!s) cerr << "error: couldn't create file " << filename <<endl;
00367
00368 if (brief) {
00369 star* stp = get_initial_primary();
00370 star* sts = get_initial_secondary();
00371
00372 real m1 = stp->get_total_mass();
00373 real m2 = sts->get_total_mass();
00374 real primary_roche_lobe, secondary_roche_lobe;
00375
00376 if (bin_type==Merged || bin_type==Disrupted) {
00377 primary_roche_lobe = 2 * stp->get_effective_radius();
00378 secondary_roche_lobe = 2 * sts->get_effective_radius();
00379 }
00380 else {
00381 primary_roche_lobe = roche_radius(semi, m1, m2);
00382 secondary_roche_lobe = roche_radius(semi, m2, m1);
00383 }
00384
00385 s << identity << " "
00386 << binary_age << " "
00387 << semi << " "
00388 << eccentricity << " "
00389
00390 << stp->get_node()->format_label() << " "
00391 << stp->get_element_type() << " "
00392 << m1 << " "
00393 << primary_roche_lobe - stp->get_effective_radius() << " "
00394
00395 << sts->get_node()->format_label() << " "
00396 << sts->get_element_type() << " "
00397 << m2 << " "
00398 << secondary_roche_lobe - sts->get_effective_radius()
00399 << endl;
00400
00401 }
00402 else {
00403 int n_elements = no_of_elements();
00404
00405 s << n_elements
00406 << "\n " << identity
00407 << " " << binary_age
00408 << " " << bin_type
00409 << " " << eccentricity
00410 << " " << get_period()
00411 << " " << semi
00412 << " " << velocity
00413 << endl;
00414 initial.dump(s);
00415
00416 s << " ";
00417 get_primary()->dump(s, brief);
00418 s << " ";
00419 get_secondary()->dump(s, brief);
00420 }
00421
00422 s.close();
00423 }
00424
00425 void double_star::adjust_binary_after_wind_loss(star * donor,
00426 const real md_dot,
00427 const real dt) {
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439 if (bin_type!=Merged && bin_type!=Disrupted) {
00440 star* accretor = donor->get_companion();
00441
00442 real M_old = get_total_mass();
00443 real old_donor_mass = donor->get_total_mass();
00444 real old_accretor_mass = accretor->get_total_mass();
00445
00446 real ma_dot = accretor->accrete_from_stellar_wind(md_dot, dt);
00447 donor = donor->reduce_mass(md_dot);
00448
00449 real M_new = get_total_mass();
00450 real new_donor_mass = donor->get_total_mass();
00451 real new_accretor_mass = accretor->get_total_mass();
00452
00453 if (md_dot>0 && ma_dot>=0) {
00454
00455
00456
00457
00458
00459 real eta = ma_dot/md_dot;
00460 semi *= pow(pow(new_donor_mass/old_donor_mass, eta)
00461 * new_accretor_mass/old_accretor_mass, -2)
00462 * M_old/M_new;
00463 }
00464 }
00465 else {
00466 donor = donor->reduce_mass(md_dot);
00467 donor->get_companion()->set_spec_type(Accreting, false);
00468 }
00469
00470
00471 }
00472
00473 real double_star::angular_momentum() {
00474
00475
00476
00477
00478 real omega = TWO_PI/(get_period()*cnsts.physics(days));
00479 real mp = get_primary()->get_total_mass()*cnsts.parameters(solar_mass);
00480 real ms = get_secondary()->get_total_mass()*cnsts.parameters(solar_mass);
00481 real a = semi*cnsts.parameters(solar_radius);
00482
00483 return omega*mp*ms*a*a*(1-eccentricity*eccentricity)/(mp+ms);
00484 }
00485
00486 void double_star::circularize() {
00487
00488
00489
00490
00491
00492
00493
00494 real pericenter = semi*(1-eccentricity);
00495
00496 if((bin_type != Merged && bin_type != Disrupted) &&
00497 (pericenter<= cnsts.parameters(tidal_circularization_radius)
00498 * get_primary()->get_effective_radius() ||
00499 pericenter<= cnsts.parameters(tidal_circularization_radius)
00500 * get_secondary()->get_effective_radius()) &&
00501 (eccentricity>0 && eccentricity<1.)) {
00502 real peri_new = cnsts.parameters(tidal_circularization_radius)
00503 * max(get_primary()->get_effective_radius(),
00504 get_secondary()->get_effective_radius());
00505 real circ_semi = semi*(1-eccentricity*eccentricity);
00506 real new_ecc = circ_semi/peri_new - 1;
00507
00508
00509 if(new_ecc<=0) {
00510 semi=circ_semi;
00511 eccentricity = 0;
00512 }
00513 else {
00514 semi = circ_semi/(1 - new_ecc*new_ecc);
00515 eccentricity = new_ecc;
00516 }
00517
00518
00519
00520 real rotation_period = cnsts.physics(days)*get_period();
00521 get_primary()->set_rotation_period(rotation_period);
00522 get_secondary()->set_rotation_period(rotation_period);
00523 }
00524
00525 }
00526
00527
00528 void double_star::force_circularization() {
00529
00530
00531 if((bin_type != Merged && bin_type != Disrupted) &&
00532 (eccentricity>0 && eccentricity<1.)) {
00533 semi *= (1-eccentricity*eccentricity);
00534 eccentricity = 0;
00535 real rotation_period = cnsts.physics(days)*get_period();
00536 get_primary()->set_rotation_period(rotation_period);
00537 get_secondary()->set_rotation_period(rotation_period);
00538 }
00539 }
00540
00541
00542
00543
00544 void double_star::determine_minimal_timestep() {
00545
00546 minimal_timestep = cnsts.safety(timestep_factor)*donor_timescale;
00547
00548 if(minimal_timestep<cnsts.safety(minimum_timestep)) {
00549 cerr << " minimal_timestep < safety minimum ";
00550 cerr << " in double_star::determine_minimal_timestep: ";
00551 cerr << minimal_timestep << endl;
00552 minimal_timestep = cnsts.safety(minimum_timestep);
00553 }
00554 }
00555
00556
00557
00558
00559 real double_star::internal_time_step(const real evolve_timestep) {
00560
00561 real dt;
00562 if (get_use_hdyn()) {
00563
00564 dt = cnsts.star_to_dyn(binary_update_time_fraction) * evolve_timestep;
00565 }
00566 else {
00567
00568 dt = cnsts.safety(maximum_binary_update_time_fraction)
00569 * evolve_timestep;
00570 }
00571
00572 return dt;
00573 }
00574
00575 real double_star::determine_dt(const real ageint, const real time_done) {
00576
00577
00578
00579
00580 real dtime = ageint - time_done;
00581
00582
00583
00584 real dtime_ev = internal_time_step(get_primary()->get_evolve_timestep());
00585
00586 if (bin_type != Merged) {
00587 dtime_ev = min(dtime_ev, internal_time_step(
00588 get_secondary()->get_evolve_timestep()));
00589
00590 dtime = min(dtime, dtime_ev);
00591
00592 if(bin_type != Disrupted) {
00593
00594 real dt_orbit = orbital_timescale();
00595
00596 dtime = min(dtime, dt_orbit);
00597
00598
00599
00600 }
00601 }
00602 else
00603 dtime = min(dtime, dtime_ev);
00604
00605 if(dtime>cnsts.safety(maximum_timestep))
00606 dtime = cnsts.safety(maximum_timestep);
00607 if(dtime<cnsts.safety(minimum_timestep))
00608 dtime = cnsts.safety(minimum_timestep);
00609
00610 return dtime;
00611 }
00612
00613
00614
00615 void double_star::set_donor_timescale(star* donor,
00616 bool first) {
00617
00618
00619
00620 if (first) {
00621
00622
00623
00624
00625
00626
00627
00628
00629 donor_timescale = donor->get_companion()->kelvin_helmholds_timescale();
00630 current_mass_transfer_type = Unknown;
00631 }
00632 else
00633 donor_timescale =
00634 donor->mass_transfer_timescale(current_mass_transfer_type);
00635
00636 donor_identity = donor->get_identity();
00637 donor_type = donor->get_element_type();
00638
00639
00640
00641 }
00642
00643 #if 0
00644
00645 void double_star::binary_in_contact(const real dt) {
00646
00647
00648 real rl_p = roche_radius(get_primary());
00649 real rl_s = roche_radius(get_secondary());
00650
00651 if (get_primary()->get_effective_radius() >= rl_p) {
00652 if (get_secondary()->get_effective_radius() < rl_s) {
00653 if (!ready_for_mass_transfer(get_primary())) return;
00654 semi_detached(get_primary(), get_secondary(), dt);
00655 }
00656 else
00657 contact_binary(dt);
00658 }
00659 else if (get_secondary()->get_effective_radius() >= rl_s) {
00660 if (!ready_for_mass_transfer(get_secondary())) return;
00661 semi_detached(get_secondary(), get_primary(), dt);
00662 }
00663
00664
00665 }
00666
00667 bool double_star::ready_for_mass_transfer(star* donor) {
00668
00669
00670
00671 real old_dt_min = minimal_timestep;
00672 bool mass_transfer_allowed = TRUE;
00673
00674 mass_transfer_type type = Unknown;
00675
00676 if (donor->get_identity()!=donor_identity) {
00677 donor_identity = donor->get_identity();
00678 donor_type = donor->get_element_type();
00679 donor_timescale = donor->mass_transfer_timescale(type);
00680
00681 determine_minimal_timestep();
00682
00683 if(old_dt_min<=minimal_timestep)
00684 mass_transfer_allowed = TRUE;
00685 else
00686 mass_transfer_allowed = FALSE;
00687 }
00688
00689 return mass_transfer_allowed;
00690 }
00691
00692 #endif
00693
00694
00695 void double_star::semi_detached(star* donor,
00696 star* accretor,
00697 real dt) {
00698
00699
00700
00701
00702 if (!stable(donor)) {
00703 cerr << "semi_deatched not stable => ::common_envelope" << endl;
00704
00705 common_envelope();
00706 }
00707 else if (get_current_mass_transfer_type()==Dynamic) {
00708 cerr << "dynamic mass transfer => ::dynamic_mass_transfer" << endl;
00709
00710 common_envelope();
00711
00712
00713 }
00714 else {
00715
00716 if (REPORT_TRANFER_STABILITY) {
00717 cerr << "stable mass transfer => ::perform_mass_transfer" << endl;
00718 }
00719
00720 perform_mass_transfer(dt, donor, accretor);
00721 }
00722
00723
00724
00725 }
00726
00727
00728 void double_star::contact(star* donor,
00729 star* accretor,
00730 real dt) {
00731
00732
00733
00734
00735
00736 real M_old = get_total_mass();
00737 real old_donor_mass = donor->get_total_mass();
00738 real old_accretor_mass = accretor->get_total_mass();
00739
00740
00741
00742
00743
00744
00745
00746 real md_dot=0;
00747 donor = donor->subtrac_mass_from_donor(dt, md_dot);
00748
00749
00750
00751
00752
00753
00754
00755
00756 if (md_dot>0) {
00757 real ma_dot = accretor->add_mass_to_accretor(md_dot, dt);
00758
00759 real M_new = get_total_mass();
00760 real new_donor_mass = donor->get_total_mass();
00761 real new_accretor_mass = accretor->get_total_mass();
00762
00763
00764 real a_fr;
00765 if (!accretor->remnant()) {
00766
00767 a_fr = pow(old_donor_mass*old_accretor_mass
00768 / (new_donor_mass*new_accretor_mass), 2);
00769 semi *= pow(M_new/M_old,
00770 2*cnsts.parameters(specific_angular_momentum_loss) + 1)*a_fr;
00771 }
00772 else {
00773 real alpha = 1 - ma_dot/md_dot;
00774 if (alpha<1) {
00775 a_fr = (new_donor_mass/old_donor_mass)
00776 * pow(new_accretor_mass/old_accretor_mass, 1/(1-alpha));
00777 semi *= (M_old/M_new)/pow(a_fr, 2);
00778 }
00779 else {
00780 a_fr = exp(2*(new_donor_mass-old_donor_mass)/new_accretor_mass);
00781 semi *= (M_old/M_new)*a_fr/pow(new_donor_mass/old_donor_mass, 2);
00782 }
00783 }
00784
00785
00786
00787 #if 0
00788 real t_donor = donor->mass_transfer_timescale();
00789 if (((q_old<=1 && q_new>=1) ||
00790 (t_donor<0.1*donor_timescale || t_donor>10*donor_timescale)) &&
00791 (bin_type!=Disrupted && bin_type!=Merged)) {
00792 set_donor_timescale(t_donor,
00793 donor->get_element_type(),
00794 donor->get_identity());
00795 determine_minimal_timestep();
00796 }
00797 #endif
00798
00799 }
00800
00801
00802
00803
00804
00805 }
00806
00807 bool double_star::stable(star* st) {
00808
00809
00810
00811
00812
00813
00814
00815
00816
00817 real J_star;
00818 if(st) {
00819 J_star = st->angular_momentum();
00820 }
00821 else {
00822 real J_prim = get_primary()->angular_momentum();
00823 real J_sec = get_secondary()->angular_momentum();
00824
00825 J_star = max(J_prim, J_sec);
00826
00827 }
00828
00829 real J_bin = angular_momentum();
00830
00831 if(REPORT_TRANFER_STABILITY) {
00832 PRC(J_star);PRL(J_bin);
00833 }
00834
00835 if (J_star >= J_bin *
00836 cnsts.parameters(Darwin_Riemann_instability_factor)) {
00837
00838 cerr << "Spiral-in: Darwin Riemann instability"<<endl;
00839
00840 return FALSE;
00841 }
00842
00843 return TRUE;
00844 }
00845
00846 #if 0
00847
00848 void double_star::update_binary_parameters() {
00849
00850
00851 real primary_mass = get_primary()->get_total_mass();
00852 real secondary_mass = get_secondary()->get_total_mass();
00853
00854 get_primary()->set_previous_radius(get_primary()->get_radius());
00855 get_secondary()->set_previous_radius(get_secondary()->get_radius());
00856
00857 }
00858 #endif
00859
00860 void double_star::perform_mass_transfer(const real dt,
00861 star * donor,
00862 star * accretor) {
00863
00864
00865
00866
00867
00868 if (REPORT_TRANFER_STABILITY) {
00869 cerr<<"enter perform_mass_transfer("<<dt<<", "
00870 <<donor->get_element_type()<<", "<<accretor->get_element_type()
00871 <<") semi= "<< semi<<endl;
00872 }
00873
00874
00875 real M_old = get_total_mass();
00876 real old_donor_mass = donor->get_total_mass();
00877 real old_accretor_mass = accretor->get_total_mass();
00878
00879
00880 real md_dot=0;
00881 donor = donor->subtrac_mass_from_donor(dt, md_dot);
00882
00883
00884 if (md_dot>0) {
00885 real ma_dot = accretor->add_mass_to_accretor(md_dot, dt);
00886
00887 real M_new = get_total_mass();
00888 real new_donor_mass = donor->get_total_mass();
00889 real new_accretor_mass = accretor->get_total_mass();
00890
00891
00892 real a_fr;
00893 if (!accretor->remnant()) {
00894
00895
00896
00897 a_fr = pow(old_donor_mass*old_accretor_mass
00898 / (new_donor_mass*new_accretor_mass), 2);
00899 semi *= pow(M_new/M_old,
00900 2*cnsts.parameters(specific_angular_momentum_loss)
00901 + 1)*a_fr;
00902 }
00903 else {
00904
00905
00906
00907
00908
00909
00910 real eta = ma_dot/md_dot;
00911 if (eta>0) {
00912 a_fr = (new_donor_mass/old_donor_mass)
00913 * pow(new_accretor_mass/old_accretor_mass, 1/eta);
00914 semi *= (M_old/M_new)/pow(a_fr, 2);
00915 }
00916 else {
00917 a_fr = exp(2*(new_donor_mass-old_donor_mass)
00918 /new_accretor_mass);
00919 semi *= (M_old/M_new)*a_fr
00920 / pow(new_donor_mass/old_donor_mass, 2);
00921 }
00922
00923
00924
00925
00926
00927
00928 if (is_star_in_binary()) {
00929 real mdot_triple = M_old - M_new;
00930 if (mdot_triple>0) {
00931 get_binary()->adjust_triple_after_wind_loss(this,
00932 mdot_triple, dt);
00933 }
00934 else if (is_binary_component()) {
00935 if(mdot_triple<0) {
00936 cerr << "enter perform_mass_transfer(" << dt << ", "
00937 << donor->get_element_type()<<", "
00938 <<accretor->get_element_type()
00939 <<")"<<endl;
00940 cerr<<"Mass lost during non-conservative mass transfer is negative."
00941 <<"mlost ="<<mdot_triple<<endl;
00942 }
00943 }
00944 else {
00945 cerr<<"Presumed binary component is not a binary root, "
00946 << "nor a hierarchical root"<<endl;
00947 }
00948 }
00949 }
00950 }
00951
00952 #if 0
00953 switch(current_mass_transfer_type) {
00954 case Nuclear: get_seba_counters()->nuclear++;
00955 break;
00956 case AML_driven: get_seba_counters()->aml_driven++;
00957 break;
00958 case Thermal: get_seba_counters()->thermal++;
00959 break;
00960 case Dynamic: get_seba_counters()->dynamic++;
00961 break;
00962 }
00963 #endif
00964 }
00965
00966
00967 #if 0
00968
00969
00970
00971
00972 real t_donor = donor->mass_transfer_timescale();
00973 if (((q_old<=1 && q_new>=1) ||
00974 (t_donor<0.1*donor_timescale || t_donor>10*donor_timescale)) &&
00975 (bin_type!=Disrupted && bin_type!=Merged)) {
00976 set_donor_timescale(t_donor,
00977 donor->get_element_type(),
00978 donor->get_identity());
00979 determine_minimal_timestep();
00980 }
00981 #endif
00982
00983
00984 void double_star::post_sn_companion_velocity(star* companion,
00985 const real mdot) {
00986
00987
00988 return ;
00989
00990
00991
00992
00993
00994 real new_total_binary_mass = get_total_mass()-mdot;
00995 real vel = abs((1 - 2*new_total_binary_mass/get_total_mass())
00996 *pow(get_total_mass()
00997 /companion->get_total_mass(), 2));
00998
00999 vel = companion->get_velocity()*sqrt(1 + vel);
01000 companion->set_velocity(vel);
01001
01002 }
01003
01004 void double_star::instantaneous_element() {
01005
01006 try_zero_timestep();
01007 }
01008
01009
01010
01011
01012
01013
01014
01015 void double_star::evolve_element(const real end_time)
01016 {
01017
01018
01019
01020
01021
01022
01023
01024
01025
01026
01027
01028
01029 real current_time = binary_age;
01030 if (binary_age<end_time)
01031 do {
01032 if (REPORT_BINARY_EVOLUTION) {
01033 cerr << "converge binary to system age at t = "
01034 << current_time << " binary age = " << binary_age
01035 << " time step is " << get_evolve_timestep() << endl;
01036 }
01037
01038
01039
01040
01041
01042
01043
01044
01045
01046
01047
01048
01049
01050
01051 current_time += internal_time_step(get_evolve_timestep());
01052
01053
01054 if (current_time>=end_time)
01055 break;
01056
01057 evolve_the_binary(current_time);
01058
01059 } while (binary_age<end_time);
01060 else if (end_time == 0)
01061 try_zero_timestep();
01062 else
01063 circularize();
01064 }
01065
01066 void double_star::try_zero_timestep() {
01067
01068 if (bin_type!=Merged && bin_type!=Disrupted) {
01069
01070 star *p = get_primary();
01071 star *s = get_secondary();
01072 if (p)
01073 p->evolve_element(binary_age);
01074
01075 if(s) {
01076 s->evolve_element(binary_age);
01077 }
01078
01079 circularize();
01080
01081 real rl_p = roche_radius(get_primary());
01082 real rl_s = roche_radius(get_secondary());
01083
01084 real rp = get_primary()->get_effective_radius();
01085 real rs = get_secondary()->get_effective_radius();
01086
01087
01088
01089 if (rp >= rl_p) {
01090
01091 get_primary()->set_spec_type(Rl_filling);
01092 get_primary()->set_spec_type(Accreting, false);
01093 get_secondary()->set_spec_type(Accreting);
01094 }
01095 else
01096 get_primary()->set_spec_type(Rl_filling, false);
01097
01098 if (rs >= rl_s) {
01099
01100
01101 get_secondary()->set_spec_type(Rl_filling);
01102 get_secondary()->set_spec_type(Accreting, false);
01103 get_primary()->set_spec_type(Accreting);
01104
01105
01106
01107 }
01108 else
01109 get_secondary()->set_spec_type(Rl_filling, false);
01110 }
01111
01112 }
01113
01114 void double_star::evolve_the_binary(const real end_time) {
01115
01116
01117
01118 real dt, old_binary_age;
01119 real time_done = 0;
01120 real ageint = end_time - binary_age;
01121
01122 do {
01123
01124
01125 determine_minimal_timestep();
01126 dt = determine_dt(ageint, time_done);
01127
01128
01129
01130 recursive_counter = 0;
01131 old_binary_age = binary_age;
01132
01133 get_primary()->set_previous_radius(get_primary()
01134 ->get_effective_radius());
01135 get_secondary()->set_previous_radius(get_secondary()
01136 ->get_effective_radius());
01137
01138
01139
01140
01141
01142 refresh_memory();
01143
01144 recursive_binary_evolution(dt, binary_age+dt);
01145 calculate_velocities();
01146 time_done += binary_age-old_binary_age;
01147 }
01148 while(time_done<ageint);
01149 }
01150
01151 void double_star::recursive_binary_evolution(real dt,
01152 const real end_time) {
01153
01154
01155
01156
01157
01158
01159 recursive_counter++;
01160 if (REPORT_RECURSIVE_EVOLUTION) {
01161 cerr << "recursive_binary_evolution(dt " << dt
01162 << ", end_time " << end_time << "): " <<bin_type<< endl;
01163 cerr<<dt<<" "<<binary_age<<" "<<end_time<< " "<<recursive_counter<<endl;
01164 cerr << "recursive # " << recursive_counter << endl;
01165 dump(cerr, false);
01166 }
01167
01168 if(recursive_counter>=cnsts.safety(maximum_recursive_calls)) {
01169 cerr << "WARNING: ";
01170 cerr << "recursive_binary_evolution(dt " << dt
01171 << ", end_time " << end_time << "): " <<bin_type<< endl;
01172 cerr<<dt<<" "<<binary_age<<" "<<end_time<<endl;
01173 cerr << "recursive_counter == " << recursive_counter << endl;
01174 dump(cerr);
01175
01176
01177
01178 return;
01179 }
01180
01181 if (binary_age>=end_time) return;
01182
01183 dt = min(dt, determine_dt(end_time, binary_age));
01184 binary_age += dt;
01185
01186
01187
01188
01189
01190 angular_momentum_loss(dt);
01191
01192 star *p = get_primary();
01193 star *s = get_secondary();
01194 if (p)
01195 p->evolve_element(binary_age);
01196
01197 if (bin_type!=Merged && s)
01198 s->evolve_element(binary_age);
01199
01200 p = s = NULL;
01201
01202 if (bin_type!=Merged && bin_type!=Disrupted) {
01203
01204 circularize();
01205
01206 real rl_p = roche_radius(get_primary());
01207 real rl_s = roche_radius(get_secondary());
01208
01209
01210
01211 real rp = get_primary()->get_radius();
01212 real rs = get_secondary()->get_radius();
01213
01214 star* donor = get_primary();
01215 star* accretor = get_secondary();
01216
01217
01218 if (rp >= rl_p) {
01219 get_primary()->set_spec_type(Rl_filling);
01220 get_primary()->set_spec_type(Accreting, false);
01221 get_secondary()->set_spec_type(Accreting);
01222 }
01223 else
01224 get_primary()->set_spec_type(Rl_filling, false);
01225
01226 if (rs >= rl_s) {
01227
01228 donor = get_secondary();
01229 accretor = get_primary();
01230
01231 get_secondary()->set_spec_type(Rl_filling);
01232 get_secondary()->set_spec_type(Accreting, false);
01233 get_primary()->set_spec_type(Accreting);
01234
01235
01236
01237 }
01238 else
01239 get_secondary()->set_spec_type(Rl_filling, false);
01240
01241
01242
01243
01244
01245
01246
01247
01248
01249 if (rp >= rl_p ||
01250 rs >= rl_s) {
01251 if (REPORT_RECURSIVE_EVOLUTION)
01252 cerr << " (donor, accretor) = (" << donor->get_identity()
01253 << ", " << accretor->get_identity()
01254 << ")";
01255
01256
01257
01258
01259 set_donor_timescale(donor);
01260
01261 determine_minimal_timestep();
01262
01263
01264
01265 if (rp >= rl_p &&
01266 rs >= rl_s){
01267
01268
01269
01270
01271
01272
01273 if (!first_contact) {
01274
01275 if (REPORT_RECURSIVE_EVOLUTION)
01276 cerr << "\tFirst contact" << endl;
01277
01278 first_contact=true;
01279
01280
01281
01282
01283
01284
01285 cerr << "First Roche-lobe contact for: ";
01286 put_state();
01287 cerr << endl;
01288 dump("SeBa.data", true);
01289 }
01290 if (REPORT_RECURSIVE_EVOLUTION) {
01291 cerr << "\tContact" << endl;
01292 put_state();
01293 cerr << endl;
01294 dump(cerr, false);
01295 }
01296
01297 bin_type = Contact;
01298 contact_binary(dt);
01299 refresh_memory();
01300 if (binary_age>=end_time)
01301 return;
01302 else {
01303 refresh_memory();
01304 real max_dt = end_time - binary_age;
01305
01306
01307 recursive_binary_evolution(max_dt, end_time);
01308 return;
01309 }
01310 }
01311 else if(dt<=minimal_timestep) {
01312 if (REPORT_RECURSIVE_EVOLUTION) {
01313 cerr << "\tMass transfer" << endl;
01314 put_state();
01315 cerr << endl;
01316 dump(cerr, false);
01317 }
01318
01319 bin_type = Semi_Detached;
01320
01321 if (!first_contact) {
01322 if (REPORT_RECURSIVE_EVOLUTION)
01323 cerr << "\tFirst contact" << endl;
01324
01325 first_contact=true;
01326 donor->first_roche_lobe_contact_story(
01327 accretor->get_element_type());
01328 cerr << "First Roche-lobe contact for: ";
01329 put_state();
01330 cerr << endl;
01331 dump("SeBa.data", true);
01332
01333
01334
01335
01336 }
01337
01338
01339 semi_detached(donor, accretor, dt);
01340
01341
01342
01343 refresh_memory();
01344 if (binary_age>=end_time) return;
01345
01346 dt = minimal_timestep;
01347
01348
01349
01350
01351
01352
01353 if (binary_age + dt > end_time ||
01354 (bin_type==Merged || bin_type == Disrupted))
01355 dt = end_time - binary_age;
01356
01357 recursive_binary_evolution(dt, end_time);
01358 return;
01359 }
01360 else {
01361 if (REPORT_RECURSIVE_EVOLUTION) {
01362 cerr << "\tTotal recall" << endl;
01363 put_state();
01364 cerr << endl;
01365 dump(cerr, false);
01366 }
01367
01368 bin_type = Semi_Detached;
01369 recall_memory();
01370 dt *= 0.5;
01371 recursive_binary_evolution(dt, end_time);
01372 return;
01373 }
01374 }
01375 else if(bin_type == Semi_Detached || bin_type == Contact) {
01376
01377 bin_type = Detached;
01378 get_primary()->set_spec_type(Rl_filling, false);
01379 get_secondary()->set_spec_type(Rl_filling, false);
01380
01381 if (REPORT_RECURSIVE_EVOLUTION) {
01382 cerr << "\tRestep" << endl;
01383 put_state();
01384 cerr << endl;
01385 dump(cerr, false);
01386 }
01387
01388
01389
01390
01391
01392
01393 if (dt>minimal_timestep) {
01394
01395 refresh_memory();
01396 }
01397
01398
01399
01400
01401
01402
01403 recursive_binary_evolution(dt, end_time);
01404 return;
01405 }
01406 else {
01407 if (REPORT_RECURSIVE_EVOLUTION) {
01408 cerr << "\tDetached" << endl;
01409 put_state();
01410 cerr << endl;
01411 dump(cerr, false);
01412 }
01413
01414 if(bin_type != Detached) {
01415 cerr<< "ERROR in ::recursive bin_type != Detached "<<endl;
01416 cerr<< "where should be Detached"<<endl;
01417 dump(cerr, false);
01418 bin_type = Detached;
01419 }
01420
01421
01422 get_primary()->
01423 set_effective_radius(get_primary()->get_radius());
01424 get_secondary()->
01425 set_effective_radius(get_secondary()->get_radius());
01426
01427 refresh_memory();
01428
01429
01430
01431
01432
01433 real max_dt = end_time - binary_age;
01434 if (max_dt < end_time - binary_age) {
01435 cerr << "Time step reduction in double_star::recursive..."
01436 << endl;
01437 cerr << " max_dt (" << max_dt
01438 << ") < end_time - binary_age ("
01439 << end_time - binary_age << ")." << endl;
01440 }
01441
01442 recursive_binary_evolution(max_dt, end_time);
01443 return;
01444 }
01445 }
01446 else {
01447 if (REPORT_RECURSIVE_EVOLUTION) {
01448 cerr << "\tTerminated" << endl;
01449 put_state();
01450 cerr << endl;
01451 dump(cerr, false);
01452 }
01453 get_primary()->set_spec_type(Rl_filling, false);
01454 get_secondary()->set_spec_type(Rl_filling, false);
01455
01456
01457 get_primary()->set_spec_type(Accreting, false);
01458 get_secondary()->set_spec_type(Accreting, false);
01459
01460
01461
01462 refresh_memory();
01463 real max_dt = end_time - binary_age;
01464 recursive_binary_evolution(max_dt, end_time);
01465 }
01466 }
01467
01468
01469
01470
01471 #if 0
01472 void double_star::set_donor_timescale(star * donor) {
01473
01474
01475
01476
01477
01478 if (bin_type!=Merged && bin_type!=Disrupted) {
01479 int id = donor->get_identity();
01480 stellar_type st = donor->get_element_type();
01481 mass_transfer_type type = Unknown;
01482 real t = donor->mass_transfer_timescale(type);
01483 current_mass_transfer_type = type;
01484
01485 if (st!=NAS) {
01486 if (donor_identity!=id) {
01487 donor_identity = id;
01488 donor_type = st;
01489 donor_timescale = t;
01490 }
01491 else if (donor_timescale<=0 || donor_type!=st) {
01492 donor_identity = id;
01493 donor_type = st;
01494 donor_timescale = t;
01495 }
01496 }
01497 }
01498 }
01499
01500
01501 void double_star::set_donor_timescale(const real t, const stellar_type st,
01502 const int id) {
01503
01504 if (bin_type!=Merged && bin_type!=Disrupted) {
01505 if (st!=NAS) {
01506 if (donor_identity==id) {
01507 donor_type = st;
01508 donor_timescale = t;
01509 }
01510 else if(donor_timescale<=0) {
01511 donor_identity = id;
01512 donor_type = st;
01513 donor_timescale = t;
01514 }
01515 }
01516 }
01517
01518 }
01519 #endif
01520
01521
01522 void double_star::common_envelope() {
01523
01524
01525
01526 if (bin_type!=Merged && bin_type!=Disrupted) {
01527
01528 if (!stable()) {
01529 cerr << "Unstable"<<endl;
01530
01531 if (get_primary()->giant_star()) {
01532 if (get_secondary()->giant_star())
01533 double_spiral_in();
01534 else
01535 spiral_in(get_primary(), get_secondary());
01536 }
01537 else if (get_secondary()->giant_star())
01538 spiral_in(get_secondary(), get_primary());
01539 else {
01540 cerr << "Merger double_star::common_envelope" << endl;
01541 dump(cerr, false);
01542
01543 merge_elements(get_primary(), get_secondary());
01544 }
01545 }
01546 else {
01547 if (get_primary()->giant_star()) {
01548 if (get_secondary()->giant_star())
01549 double_spiral_in();
01550 else if (get_secondary()->remnant())
01551 spiral_in(get_primary(),get_secondary());
01552 else
01553 dynamic_mass_transfer(get_primary(), get_secondary());
01554 }
01555 else if (get_secondary()->giant_star()) {
01556 if (get_primary()->remnant())
01557 spiral_in(get_secondary(),get_primary());
01558 else
01559 dynamic_mass_transfer(get_secondary(), get_primary());
01560 }
01561 else {
01562 cerr << "Merger double_star::common_envelope" << endl;
01563 dump(cerr, false);
01564
01565 merge_elements(get_primary(), get_secondary());
01566 }
01567 }
01568
01569
01570 }
01571 }
01572
01573
01574
01575
01576
01577
01578 void double_star::double_spiral_in() {
01579
01580 star *p = get_primary();
01581 star *s = get_secondary();
01582
01583 real mcore_p = p->get_core_mass();
01584 real menv_p = p->get_envelope_mass();
01585 real mtot_p = mcore_p + menv_p;
01586 real mcore_s = s->get_core_mass();
01587 real menv_s = s->get_envelope_mass();
01588 real mtot_s = mcore_s + menv_s;
01589
01590 real r_p = roche_radius(p);
01591 real r_s = roche_radius(s);
01592
01593 real alpha_lambda = cnsts.parameters(common_envelope_efficiency)
01594 * cnsts.parameters(envelope_binding_energy);
01595
01596 real post_ce_orbital_energy = mtot_p*menv_p/(alpha_lambda*r_p)
01597 + mtot_s*menv_s/(alpha_lambda*r_s)
01598 + mtot_p*mtot_s/(2 * semi);
01599
01600 real post_ce_semi = mcore_p*mcore_s/(2*post_ce_orbital_energy);
01601
01602 real rl_p = roche_radius(post_ce_semi, mcore_p, mcore_s);
01603 real rl_s = roche_radius(post_ce_semi, mcore_s, mcore_p);
01604
01605 if (p->get_core_radius() >= rl_p ||
01606 s->get_core_radius() >= rl_s) {
01607
01608 #if 0
01609
01610
01611 real semi_p = p->get_core_radius()
01612 / roche_radius(1, p->get_core_mass(),
01613 s->get_core_mass());
01614 real semi_s = s->get_core_radius()
01615 / roche_radius(1, s->get_core_mass(),
01616 p->get_core_mass());
01617
01618 real post_ce_semi = max(semi_p, semi_s);
01619
01620
01621
01622
01623
01624 real mass_loss_fr = post_ce_semi
01625 / (alpha_lambda * mtot_p * mtot_s)
01626 * (pow(mtot_p, 2)/r_p + pow(mtot_s, 2)/r_s);
01627
01628 real mlf_limit = (menv_p + menv_s)/(mtot_p + mtot_s);
01629 #endif
01630
01631
01632
01633
01634 real semi_p = p->get_core_radius()
01635 / roche_radius(1, mcore_p, mcore_s);
01636 real semi_s = s->get_core_radius()
01637 / roche_radius(1, mcore_s, mcore_p);
01638
01639 real post_ce_semi = max(semi_p, semi_s);
01640
01641
01642
01643
01644
01645
01646
01647
01648
01649
01650
01651
01652
01653
01654
01655
01656
01657
01658
01659
01660 real a = (mtot_p * mtot_s)/(2 * post_ce_semi);
01661 real b = (pow(mtot_p, 2)/r_p + pow(mtot_s, 2)/r_s)
01662 / alpha_lambda;
01663 real c = -b -(mtot_p * mtot_s)/(2 * semi);
01664
01665 real mass_not_lost_fraction = (-b + sqrt(pow(b, 2) - 4 * a * c))
01666 / (2 * a);
01667
01668 real mass_loss_fr = 1 - mass_not_lost_fraction;
01669 real mlf_limit = (menv_p + menv_s)/(mtot_p + mtot_s);
01670
01671 if (mass_loss_fr >= 1) {
01672 cerr << "ERROR: in double_star::double_spiral_in()" << endl;
01673 cerr << " Fraction of mass lost (" << mass_loss_fr
01674 << ") greater then 1" << endl;
01675
01676 dump(cerr, false);
01677 mass_loss_fr = 0.99;
01678 }
01679 else if (mass_loss_fr > mlf_limit) {
01680 cerr << "WARNING: in double_star::double_spiral_in()" << endl;
01681 cerr << " Fraction of mass lost (" << mass_loss_fr
01682 << ") greater then limit (" << mlf_limit << ")" << endl;
01683 dump(cerr, false);
01684 }
01685
01686
01687
01688 real mlost_p = min(mass_loss_fr*mtot_p, 0.99*menv_p);
01689 p->reduce_mass(mlost_p);
01690 real mlost_s = min(mass_loss_fr*mtot_s, 0.99*menv_s);
01691 s->reduce_mass(mlost_s);
01692
01693 cerr << "Merger double_star::double_spiral_in()"<<endl;
01694 dump(cerr, false);
01695
01696 merge_elements(p, s);
01697
01698 }
01699 else {
01700
01701 cerr << "Survival double_star::double_spiral_in()"<<endl;
01702 dump(cerr, false);
01703
01704 semi = post_ce_semi;
01705 p = p->reduce_mass(menv_p);
01706 s = s->reduce_mass(menv_s);
01707 }
01708
01709
01710 }
01711
01712
01713 void double_star::spiral_in(star* larger,
01714 star* smaller) {
01715
01716
01717
01718
01719
01720 if (bin_type!=Merged && bin_type!=Disrupted) {
01721
01722 real mcore_l = larger->get_core_mass();
01723 real menv_l = larger->get_envelope_mass();
01724 real mtot_l = mcore_l + menv_l;
01725
01726
01727
01728
01729
01730
01731
01732 real m_acc = 0;
01733 real mtot_s = smaller->get_total_mass() + m_acc;
01734 menv_l -= m_acc;
01735
01736 real r_lobe = roche_radius(larger)/semi;
01737
01738 real alpha_lambda = cnsts.parameters(common_envelope_efficiency)
01739 * cnsts.parameters(envelope_binding_energy);
01740 real a_spi = semi*(mcore_l/mtot_l)/(1. + (2.*menv_l
01741 / (alpha_lambda *r_lobe*mtot_s)));
01742
01743 real rl_l = roche_radius(a_spi, mcore_l, mtot_s);
01744 real rl_s = roche_radius(a_spi, mtot_s, mcore_l);
01745
01746
01747 if (larger->get_core_radius()>=rl_l ||
01748 smaller->get_radius()>=rl_s) {
01749
01750
01751
01752
01753
01754
01755
01756
01757 real sma_larger = larger->get_core_radius()
01758 / roche_radius(1, larger->get_core_mass(),
01759 smaller->get_total_mass());
01760 real sma_smaller = smaller->get_effective_radius()
01761 / roche_radius(1, smaller->get_total_mass(),
01762 larger->get_core_mass());
01763 real sma_post_ce = max(sma_larger, sma_smaller);
01764
01765 real mass_lost = (mtot_l*mtot_s/(2*sma_post_ce)
01766 - mtot_l*mtot_s/(2*semi))
01767 / (mtot_l/(alpha_lambda*r_lobe*semi)
01768 + mtot_s/(2*sma_post_ce));
01769
01770
01771
01772
01773
01774
01775
01776
01777
01778
01779 if (mass_lost>=menv_l) {
01780 mass_lost = 0.99*menv_l;
01781 }
01782
01783 cerr << "Merger double_star::spiral_in()"<<endl;
01784 dump(cerr, false);
01785
01786
01787
01788
01789 larger = larger->reduce_mass(mass_lost);
01790
01791 if (mtot_l>mtot_s)
01792 merge_elements(larger, smaller);
01793 else
01794 merge_elements(smaller, larger);
01795 }
01796 else {
01797 semi = a_spi;
01798
01799
01800
01801 menv_l -= smaller->add_mass_to_accretor(
01802 larger->get_envelope_mass(),
01803 cnsts.parameters(spiral_in_time));
01804 smaller->set_effective_radius(smaller->get_radius());
01805 larger = larger->reduce_mass(larger->get_envelope_mass());
01806
01807
01808
01809
01810
01811 }
01812 }
01813
01814
01815
01816
01817 }
01818
01819 void double_star::merge_elements(star* consumer,
01820 star* dinner) {
01821
01822
01823
01824
01825 bin_type = Merged;
01826
01827 if (!get_use_hdyn()) {
01828 consumer->set_velocity(velocity);
01829 dinner->set_velocity(velocity);
01830
01831
01832 consumer = consumer->merge_elements(dinner);
01833 semi = 0;
01834 dinner->set_envelope_mass(0);
01835 dinner->set_core_mass(0);
01836 }
01837 else {
01838
01839 }
01840
01841
01842 cerr << "Merger is: "<<endl;
01843 dump(cerr, false);
01844 dump("SeBa.data", true);
01845
01846
01847
01848 }
01849
01850
01851
01852
01853
01854 void double_star::perform_wind_loss(const real dt) {
01855
01856 star* p = get_primary();
01857 star* s = get_secondary();
01858 p->stellar_wind(dt);
01859 s->stellar_wind(dt);
01860 p = s = NULL;
01861
01862
01863
01864
01865 }
01866
01867 void double_star::angular_momentum_loss(const real dt) {
01868
01869
01870
01871
01872 if (bin_type != Merged && bin_type != Disrupted) {
01873 magnetic_stellar_wind(dt);
01874
01875
01876 }
01877 }
01878
01879
01880
01881
01882
01883
01884 void double_star::magnetic_stellar_wind(const real dt) {
01885
01886
01887
01888 real magnetic_braking_aml = mb_angular_momentum_loss();
01889
01890 real a_dot = 2*dt*magnetic_braking_aml;
01891 real semi_new = semi*(1 + a_dot);
01892
01893 if (semi_new<=0) {
01894
01895 cerr << "Merger::magnetic_stellar_wind"<<endl;
01896 dump(cerr, false);
01897
01898 if (get_primary()->get_effective_radius() >
01899 get_secondary()->get_effective_radius())
01900 merge_elements(get_primary(), get_secondary());
01901 else
01902 merge_elements(get_secondary(), get_primary());
01903
01904
01905
01906 }
01907 else if(semi_new <= get_primary()->get_core_radius() +
01908 get_secondary()->get_core_radius() ) {
01909 semi = semi_new;
01910 cerr << "magnetic stellar wind => ::common_envelope" << endl;
01911 common_envelope();
01912
01913
01914
01915
01916
01917 }
01918 else {
01919 semi = semi_new;
01920 gravrad(dt);
01921 }
01922 }
01923
01924
01925
01926
01927 real double_star::de_dt_gwr(const real e) {
01928
01929 real de_dt = (-305/15)*e*(1 + (121/304)*e*e)/pow(1-e*e, 2.5);
01930 de_dt *= get_primary()->get_total_mass()
01931 * get_secondary()->get_total_mass()
01932 * get_total_mass()/pow(semi, 4.);
01933
01934 return de_dt;
01935 }
01936
01937
01938
01939 void double_star::gravrad(const real dt) {
01940
01941 real G3M3_C5R4 = pow(cnsts.physics(G)
01942 * cnsts.parameters(solar_mass), 3.)
01943 / (pow(cnsts.physics(C), 5.)
01944 * pow(cnsts.parameters(solar_radius), 4.));
01945
01946
01947 if(semi/sqrt(get_total_mass())<=6.) {
01948 real e_new = eccentricity
01949 + G3M3_C5R4*de_dt_gwr(eccentricity)
01950 * dt*cnsts.physics(Myear);
01951
01952 real a_new;
01953 if (e_new > 0 && eccentricity > 0) {
01954 real c0 = (semi*(1-pow(eccentricity,2))/pow(eccentricity, 12./19.))
01955 / pow(1 + 121*pow(eccentricity, 2.)/304, 870./2299.);
01956
01957 a_new = (c0*pow(e_new, 12./19.)/(1-pow(e_new, 2.)))
01958 * pow(1 + 121*pow(e_new, 2.)/304, 870./2299.);
01959 }
01960 else {
01961 e_new = 0;
01962 semi *= (1-eccentricity*eccentricity);
01963 real G3M3_C5 = pow(cnsts.physics(G)
01964 *cnsts.parameters(solar_mass), 3.)
01965 / pow(cnsts.physics(C), 5.);
01966 real c0 = G3M3_C5* 256
01967 * get_primary()->get_total_mass()
01968 * get_secondary()->get_total_mass()
01969 * get_total_mass()/5.;
01970 c0 = pow(semi*cnsts.parameters(solar_radius), 4.)
01971 - c0*dt*cnsts.physics(Myear);
01972 c0 = max(c0, 0.);
01973 a_new = pow(c0, 0.25)/cnsts.parameters(solar_radius);
01974 }
01975
01976 if (a_new<=0) {
01977
01978 cerr << "Merger::gravrad"<<endl;
01979 dump(cerr, false);
01980
01981 if (get_primary()->get_total_mass() >
01982 get_secondary()->get_total_mass())
01983 merge_elements(get_primary(), get_secondary());
01984 else
01985 merge_elements(get_secondary(), get_primary());
01986
01987
01988 }
01989 else if(a_new <= get_primary()->get_core_radius() +
01990 get_secondary()->get_core_radius() ) {
01991 semi=a_new;
01992 eccentricity = e_new;
01993 cerr << "gravrad => ::common_envelope" << endl;
01994 common_envelope();
01995
01996
01997
01998
01999
02000 }
02001 else {
02002 semi=a_new;
02003 eccentricity = e_new;
02004 }
02005 }
02006 }
02007
02008 #if 0
02009 real double_star::mdot_according_to_roche_radius_change(star* donor,
02010 star* accretor) {
02011
02012
02013
02014
02015
02016
02017 real mdot = 0;
02018 if (bin_type != Merged && bin_type != Disrupted) {
02019
02020 real r_don = donor->get_effective_radius();
02021 real m_don = donor->get_total_mass();
02022 real m_acc = accretor->get_total_mass();
02023
02024 real zeta_lobe = zeta(donor, accretor);
02025 real J_mb = 0;
02026 if (donor->magnetic()) {
02027 real c_mb = -3.8e-30*cnsts.parameters(solar_mass)*cnsts.physics(G)
02028 / cnsts.parameters(solar_radius);
02029 J_mb = cnsts.physics(Myear)*c_mb * pow(m_don+m_acc, 2)
02030 * pow(r_don, cnsts.parameters(magnetic_braking_exponent))
02031 / (m_acc*pow(semi, 5));
02032 }
02033
02034 real J_gr=0;
02035 if (semi/sqrt(get_total_mass())<=6.) {
02036 real c_gr = -32*pow(cnsts.parameters(solar_mass)*cnsts.physics(G), 3)
02037 / (5*pow(cnsts.physics(C), 5)
02038 * pow(cnsts.parameters(solar_radius), 4));
02039 J_gr = cnsts.physics(Myear)*c_gr*m_don*m_acc*(m_don+m_acc)/pow(semi, 4);
02040 }
02041
02042
02043 real drdot_dr=0;
02044 mdot = m_don*abs((2*(J_mb+J_gr) - drdot_dr)
02045 / (zeta_lobe + 2*(5./6. - m_don/m_acc)));
02046 }
02047
02048
02049 return mdot;
02050 }
02051 #endif
02052
02053
02054
02055
02056
02057
02058 real double_star::mdot_according_to_roche_radius_change(star* donor,
02059 star* accretor) {
02060 real mdot = 0;
02061 if (bin_type != Merged && bin_type != Disrupted) {
02062
02063 real m_don = donor->get_total_mass();
02064 real m_acc = accretor->get_total_mass();
02065
02066 real zeta_th = donor->zeta_thermal();
02067 real rl = roche_radius(donor);
02068
02069
02070
02071
02072
02073
02074
02075
02076
02077 real dm = cnsts.safety(timestep_factor) * donor->get_total_mass();
02078
02079 real rl_2 = roche_radius(semi, m_don-dm, m_acc+dm);
02080
02081 real J_mb = mb_angular_momentum_loss();
02082 real J_gwr = gwr_angular_momentum_loss(m_don, m_acc, semi);
02083
02084
02085 real zeta_dimensionless_lobe = (rl_2 - rl)*m_don/(-1.*dm*rl);
02086 mdot = m_don*abs((2*(J_mb+J_gwr))
02087 / (2*(m_don/m_acc-1.) - zeta_th + zeta_dimensionless_lobe));
02088
02089 real mdot_analytic = m_don*J_gwr/(m_don/m_acc - 2./3);
02090
02091 }
02092
02093 return mdot;
02094 }
02095
02096
02097
02098
02099 void double_star::calculate_velocities() {
02100
02101 if(bin_type != Merged && bin_type != Disrupted) {
02102 real mu = get_primary()->get_total_mass()/get_total_mass();
02103 real mean_r = semi*(1+0.5*eccentricity*eccentricity);
02104 real v_rel = sqrt(cnsts.physics(G)*get_total_mass()
02105 *cnsts.parameters(solar_mass)
02106 *((2/(mean_r*cnsts.parameters(solar_radius)))
02107 - (1/(semi*cnsts.parameters(solar_radius)))));
02108 v_rel /= cnsts.physics(km_per_s);
02109 get_primary()->set_velocity((1-mu)*v_rel);
02110 get_secondary()->set_velocity(mu*v_rel);
02111 }
02112 }
02113
02114
02115
02116
02117 void double_star::contact_binary(real dt) {
02118
02119 if (REPORT_FUNCTION_NAMES)
02120 cerr << "::contact_binary(dt = "<<dt << ")" << endl;
02121
02122
02123 if (get_primary()->get_element_type() == Main_Sequence &&
02124 get_secondary()->get_element_type() == Main_Sequence) {
02125
02126
02127
02128
02129
02130
02131
02132
02133
02134
02135
02136
02137
02138
02139
02140
02141
02142
02143
02144 } else {
02145
02146 common_envelope();
02147 }
02148
02149 }
02150
02151
02152
02153
02154 void double_star::dynamic_mass_transfer(star* larger, star* smaller) {
02155
02156
02157
02158 if (bin_type!=Merged && bin_type!=Disrupted) {
02159
02160 real M_core = larger->get_core_mass();
02161 real M_env = larger->get_envelope_mass();
02162 real M_tot = M_env + M_core;
02163
02164
02165
02166 real m_acc = 0;
02167 real m_new = smaller->get_total_mass() - m_acc;
02168 M_env -= m_acc;
02169
02170
02171
02172 real gamma = cnsts.parameters(dynamic_mass_transfer_gamma);
02173
02174 real J_i = sqrt(semi) * (M_tot * m_new)/sqrt(M_tot + m_new);
02175 real J_f_over_sqrt_af = (M_core * m_new)/sqrt(M_core + m_new);
02176 real J_lost = gamma * M_env * J_i/ (M_tot + m_new);
02177 real sqrt_a_f = max(0.,(J_i - J_lost)/J_f_over_sqrt_af);
02178 real a_f = pow(sqrt_a_f, 2);
02179
02180 if(REPORT_BINARY_EVOLUTION) {
02181
02182 PRL(pow(M_tot/M_core, 2));
02183 PRL((M_tot + m_new)/(M_core + m_new));
02184 PRL(exp(-2. * M_env/m_new));
02185 }
02186
02187 real rl_l = roche_radius(a_f, M_core, m_new);
02188 real rl_s = roche_radius(a_f, m_new, M_core);
02189
02190
02191
02192
02193
02194 if (larger->get_core_radius()>=rl_l ||
02195 smaller->get_radius()>=rl_s) {
02196
02197 PRC(smaller->get_radius());PRC(rl_s);PRL(a_f);
02198
02199 cerr << "Merger double_star::dynamic_mass_transfer" << endl;
02200 dump(cerr, false);
02201 merge_elements(larger,smaller);
02202 }
02203 else {
02204
02205
02206 if(REPORT_BINARY_EVOLUTION) {
02207
02208 cerr << "semi before = " << semi << endl;
02209 cerr << "semi after = " << a_f << endl;
02210
02211 real Eorb1 = (M_tot * m_new)/(2 * semi);
02212 real Ebind = (M_tot * (M_tot - M_core))/larger->get_radius();
02213 real Eorb2 = (M_core * m_new) / (2*a_f);
02214
02215 PRC(Eorb1);PRC(Eorb2);PRL(Ebind);
02216 cerr << "(Eorb2 - Eorb1)/Ebind = "
02217 << (Eorb2 - Eorb1)/Ebind << endl;
02218 }
02219
02220 semi = a_f;
02221 smaller->add_mass_to_accretor(larger->get_envelope_mass(),
02222 cnsts.parameters(spiral_in_time));
02223 smaller->set_effective_radius(smaller->get_radius());
02224
02225 larger = larger->reduce_mass(larger->get_envelope_mass());
02226
02227 }
02228
02229
02230
02231 }
02232
02233
02234 }
02235
02236
02237
02238 #if 0
02239
02240
02241 void double_star::dynamic_mass_transfer(star* larger, star* smaller) {
02242
02243
02244
02245 if (bin_type!=Merged && bin_type!=Disrupted) {
02246
02247
02248 real beta = cnsts.parameters(specific_angular_momentum_loss);
02249
02250
02251
02252
02253
02254
02255
02256
02257
02258
02259
02260
02261
02262
02263
02264
02265
02266
02267 real M_core = larger->get_core_mass();
02268 real M_env = larger->get_envelope_mass();
02269 real M_tot = M_env + M_core;
02270
02271
02272
02273
02274 real m_acc = 0;
02275 real m_new = smaller->get_total_mass() - m_acc;
02276 M_env -= m_acc;
02277
02278 real a_f = semi*pow(M_tot/M_core,2)
02279 *pow((M_core + m_new)/(M_tot + m_new),
02280 2 * beta + 1);
02281
02282 real Eorb1 = (M_tot * m_new)/(2 * semi);
02283 real Ebind = (M_tot * (M_tot - M_core))/larger->get_radius();
02284
02285 real rl_l = roche_radius(a_f, M_core, m_new);
02286 real rl_s = roche_radius(a_f, m_new, M_core);
02287
02288
02289
02290
02291
02292
02293 if (larger->get_core_radius()>=rl_l ||
02294 smaller->get_radius()>=rl_s) {
02295
02296 PRC(smaller->get_radius());PRC(rl_s);PRL(a_f);
02297
02298 cerr << "Merger double_star::dynamic_mass_transfer" << endl;
02299 dump(cerr, false);
02300 merge_elements(larger,smaller);
02301 }
02302 else {
02303
02304 cerr << "semi before = " << semi << endl;
02305 semi = a_f;
02306 cerr << "semi after = " << semi << endl;
02307
02308 real Eorb2 = (M_core * m_new) / (2*semi);
02309
02310 PRC(Eorb1);PRC(Eorb2);PRL(Ebind);
02311 cerr << "(Eorb2 - Eorb1)/Ebind = " << (Eorb2 - Eorb1)/Ebind << endl;
02312 smaller->add_mass_to_accretor(larger->get_envelope_mass(),
02313 cnsts.parameters(spiral_in_time));
02314 smaller->set_effective_radius(smaller->get_radius());
02315
02316 larger = larger->reduce_mass(larger->get_envelope_mass());
02317
02318 }
02319
02320
02321
02322 }
02323
02324
02325 }
02326 #endif
02327
02328 bool double_star::low_mass_star() {
02329
02330 return (get_total_mass()<=cnsts.parameters(low_mass_star_mass_limit))
02331 ?true: false;
02332 }
02333
02334 bool double_star::medium_mass_star() {
02335
02336 return (!low_mass_star() && !high_mass_star())?true:false;
02337 }
02338
02339 bool double_star::high_mass_star() {
02340
02341 return (get_total_mass()>cnsts.parameters(medium_mass_star_mass_limit))
02342 ?true: false;
02343 }
02344
02345
02346 void double_star::refresh_memory() {
02347
02348 star *p = get_primary();
02349 star *s = get_secondary();
02350 get_primary()->refresh_memory();
02351 get_secondary()->refresh_memory();
02352 p=s=NULL;
02353
02354 previous.binary_age = binary_age;
02355 previous.semi = semi;
02356 previous.eccentricity = eccentricity;
02357
02358 previous.donor_timescale = donor_timescale;
02359
02360 }
02361
02362 void double_star::recall_memory() {
02363
02364 star *p = get_primary();
02365 star *s = get_secondary();
02366 p->recall_memory();
02367 s->recall_memory();
02368 p=s=NULL;
02369
02370 binary_age = previous.binary_age;
02371 semi = previous.semi;
02372 eccentricity = previous.eccentricity;
02373
02374 donor_timescale = previous.donor_timescale;
02375 }
02376
02377
02378
02379
02380
02381
02382
02383
02384 real double_star::zeta(star * donor,
02385 star * accretor) {
02386
02387
02388 if (bin_type!=Merged && bin_type!=Disrupted) {
02389
02390 #if 0
02391 real md_dot, ma_dot;
02392 real dt = cnsts.safety(minimum_timestep);
02393 if (get_donor_timescale()>0) {
02394 md_dot=donor->get_relative_mass()*dt/get_donor_timescale();
02395 }
02396 else {
02397 md_dot=cnsts.safety(minimum_mass_step);
02398 }
02399 md_dot = min(md_dot, donor->get_envelope_mass())
02400 + cnsts.safety(minimum_mass_step);
02401 ma_dot = accretor->accretion_limit(md_dot, dt);
02402 #endif
02403
02404
02405 real md_dot = min(donor->get_total_mass(),
02406 cnsts.safety(minimum_mass_step));
02407
02408
02409 PRC(md_dot);PRC(donor_timescale);PRL(donor->get_relative_mass());
02410 real dt = md_dot * donor_timescale/donor->get_relative_mass();
02411 real ma_dot = accretor->accretion_limit(md_dot, dt);
02412
02413 real M_old = get_total_mass();
02414 real old_donor_mass = donor->get_total_mass();
02415 real old_accretor_mass = accretor->get_total_mass();
02416 real q_old = old_accretor_mass/old_donor_mass;
02417
02418 real M_new = get_total_mass() - md_dot + ma_dot;
02419 real new_donor_mass = donor->get_total_mass() - md_dot;
02420 real new_accretor_mass = accretor->get_total_mass() + ma_dot;
02421 real q_new = new_accretor_mass/new_donor_mass;
02422
02423 real a_fr, new_semi;
02424 real beta = cnsts.parameters(specific_angular_momentum_loss);
02425 a_fr = pow(old_donor_mass*old_accretor_mass
02426 / (new_donor_mass*new_accretor_mass), 2);
02427 new_semi = semi*pow(M_new/M_old, 2*beta + 1)*a_fr;
02428
02429 real a_dot=0;
02430
02431 real magnetic_braking_aml = mb_angular_momentum_loss();
02432 real grav_rad_aml = gwr_angular_momentum_loss(get_primary()
02433 ->get_total_mass(),
02434 get_secondary()
02435 ->get_total_mass(),
02436 semi);
02437
02438
02439
02440 a_dot = 2*dt*semi*(magnetic_braking_aml+grav_rad_aml);
02441
02442 new_semi += a_dot;
02443
02444
02445 real rl = roche_radius(donor);
02446
02447 real rl_d = roche_radius(new_semi,
02448 new_donor_mass,
02449 new_accretor_mass);
02450
02451
02452 real d_lnr = (rl_d - rl)/rl;
02453 real d_lnm = (new_donor_mass - donor->get_total_mass())
02454 / donor->get_total_mass();
02455
02456 real zeta;
02457 if(d_lnm==0) {
02458 cerr << "WARNING: d_lnm (= " << d_lnm << ") has an illegal value"
02459 << endl;
02460 zeta = 0;
02461 dump(cerr, true);
02462 }
02463 else {
02464 zeta = d_lnr/d_lnm;
02465 }
02466
02467
02468
02469
02470
02471
02472
02473
02474
02475 return zeta;
02476 }
02477
02478
02479 return 1;
02480 }
02481
02482 void double_star::enhance_cluster_profile(cluster_profile& c_prof) {
02483
02484 double_profile binary;
02485
02486 binary.enhance_double_profile(this);
02487 c_prof.enhance_cluster_profile(binary);
02488 }
02489
02490
02491 real double_star::orbital_timescale() {
02492
02493 real magnetic_braking_aml = mb_angular_momentum_loss();
02494 real grav_rad_aml = gwr_angular_momentum_loss(get_primary()
02495 ->get_total_mass(),
02496 get_secondary()
02497 ->get_total_mass(),
02498 semi);
02499 real dt = cnsts.safety(maximum_timestep);
02500
02501 real aml_loss = abs(magnetic_braking_aml)
02502 + abs(grav_rad_aml);
02503
02504
02505 if (aml_loss> 0)
02506 dt=.1/aml_loss;
02507
02508 return dt;
02509 }
02510
02511
02512 real double_star::gwr_angular_momentum_loss(const real m_prim,
02513 const real m_sec,
02514 const real sma) {
02515
02516 real m_tot = m_prim + m_sec;
02517 real J_gwr = 0;
02518
02519 if(sma/sqrt(m_tot)<=6.) {
02520
02521 real c_gwr = -32*pow(cnsts.parameters(solar_mass)*
02522 cnsts.physics(G), 3)
02523 / (5*pow(cnsts.physics(C), 5)*
02524 pow(cnsts.parameters(solar_radius), 4));
02525
02526 J_gwr = c_gwr*m_prim*m_sec*m_tot/pow(sma, 4);
02527
02528 }
02529
02530 return J_gwr*cnsts.physics(Myear);
02531 }
02532
02533
02534 real double_star::mb_angular_momentum_loss() {
02535
02536 real c_mb = -3.8e-30*cnsts.parameters(solar_mass)*cnsts.physics(G)
02537 / cnsts.parameters(solar_radius);
02538
02539 real J_mb_prim = 0;
02540 if (get_primary()->magnetic() && eccentricity<=
02541 cnsts.parameters(corotation_eccentricity))
02542 J_mb_prim = c_mb * pow(get_total_mass(), 2)
02543 * pow(get_primary()->get_effective_radius(),
02544 cnsts.parameters(magnetic_braking_exponent))
02545 / (get_secondary()->get_total_mass()*pow(semi, 5));
02546
02547 real J_mb_sec = 0;
02548 if (get_secondary()->magnetic() && eccentricity<=
02549 cnsts.parameters(corotation_eccentricity))
02550 J_mb_sec = c_mb * pow(get_total_mass(), 2)
02551 * pow(get_secondary()->get_effective_radius(),
02552 cnsts.parameters(magnetic_braking_exponent))
02553 / (get_primary()->get_total_mass()*pow(semi, 5));
02554
02555 real J_mb=(J_mb_prim+J_mb_sec)*cnsts.physics(Myear);
02556
02557 return J_mb;
02558
02559 }
02560
02561
02562
02563
02564
02565
02566 real double_star::circularization_radius(const real m1, const real m2) {
02567
02568 real q = m2/m1;
02569 real r_c = semi*(1+q)*pow(0.5 - 0.227 * log10(q), 4);
02570
02571 return r_c;
02572 }
02573
02574
02575 real double_star::get_period() {
02576
02577 real p = 2*PI*sqrt(pow(semi*cnsts.parameters(solar_radius), 3.)
02578 / (cnsts.physics(G)*get_total_mass()
02579 *cnsts.parameters(solar_mass)))
02580 / cnsts.physics(days);
02581
02582 if(p<=0) p=1;
02583
02584 return p;
02585 }
02586
02587
02588 real double_star::potential_energy() {
02589
02590 real GM2_R = cnsts.physics(G)*pow(cnsts.parameters(solar_mass), 2)
02591 / cnsts.parameters(solar_radius);
02592 real u = GM2_R*get_primary()->get_total_mass()
02593 * get_secondary()->get_total_mass()/semi;
02594
02595 return -u;
02596 }
02597 real double_star::kinetic_energy() {
02598
02599 real M_km_s = cnsts.parameters(solar_mass)
02600 * pow(cnsts.physics(km_per_s), 2);
02601 real k = 0.5*M_km_s*get_total_mass()*velocity*velocity;
02602
02603 return k;
02604 }
02605
02606 real double_star::total_energy() {
02607 return kinetic_energy() + potential_energy();
02608 }
02609
02610
02611