Main Page   Class Hierarchy   Data Structures   File List   Data Fields   Globals  

single_star.C

Go to the documentation of this file.
00001 // 
00002 // single_star.C
00003 //
00004 #include <fstream.h>
00005 #include "single_star.h"
00006 #include "proto_star.h"
00007 //#include "main_sequence.h"
00008 
00009 // Only to make SPZDCH star known to this file 
00010 #include "SPZDCH_star.h"
00011 
00012 #define REPORT_MASS_TRANSFER_TIMESCALE true
00013 
00014 single_star * new_single_star(stellar_type type,        // All defaults are
00015                               int  id,                  // now specified in
00016                               real t_cur,
00017                               real t_rel,
00018                               real m_rel,
00019                               real m_tot,
00020                               real m_core,
00021                               real co_core,
00022                               real p_rot,
00023                               real b_fld,
00024                               node* n)
00025 {
00026    //cerr << "Initialize from: "<< type_string(type)<<endl;
00027    //PRC(id);PRC(t_cur);PRC(t_rel);PRC(m_rel);PRC(m_tot);
00028    //PRL(m_core); 
00029 
00030   single_star* element = 0;
00031   switch(type) {
00032   case SPZDCH_Star: element = new SPZDCH_star(n);
00033     break;
00034   case Proto_Star: element = new proto_star(n);
00035     break;
00036   case Planet:
00037   case Brown_Dwarf: element = new brown_dwarf(n);
00038     break;
00039   case Main_Sequence: element = new main_sequence(n);
00040     break;
00041   case Hertzsprung_Gap: element = new hertzsprung_gap(n);
00042     break;
00043   case Sub_Giant: element = new sub_giant(n);
00044     break;
00045   case Horizontal_Branch: element = new horizontal_branch(n);
00046     break;
00047   case Super_Giant: element = new super_giant(n);
00048     break;
00049   case Carbon_Star:  
00050   case Helium_Star:  
00051   case Helium_Giant: element = new helium_star(n);
00052     break;
00053   case Hyper_Giant: element = new hyper_giant(n);
00054     break;
00055   case Helium_Dwarf:
00056   case Carbon_Dwarf:
00057   case Oxygen_Dwarf: element = new white_dwarf(n);
00058     break;
00059   case Thorn_Zytkow: element = new thorne_zytkow(n);
00060     break;
00061   case Xray_Pulsar:
00062   case Radio_Pulsar:
00063   case Neutron_Star: element = new neutron_star(n);
00064     element->set_rotation_period(p_rot);
00065     element->set_magnetic_field(b_fld);
00066     break;
00067   case Black_Hole: element = new black_hole(n);
00068     break;
00069   case Disintegrated: element = new disintegrated(n);
00070     break;
00071 //  default: element = new main_sequence(n);
00072   default: cerr << "No default stellar type in new_single_star()"<<endl;
00073            exit(1);
00074                     
00075   }
00076       
00077   element->initialize(id, t_cur, t_rel, m_rel, m_tot, m_core, co_core);
00078 
00079   element->post_constructor();
00080       
00081   return element;
00082 }
00083 
00084 single_star::single_star(node* n) : star(n) {
00085 
00086     star_type = NAS;
00087     for (int i=NAC; i<no_of_spec_type; i++)
00088       spec_type[i] = NAC;
00089     current_time=relative_age=0;
00090     last_update_age = next_update_age=0;
00091     relative_mass = accreted_mass=0;
00092     envelope_mass=core_mass=0;
00093     core_radius=effective_radius=radius=0;
00094     COcore_mass = 0;
00095     luminosity=0;
00096     velocity=0;
00097     wind_constant=0;
00098     magnetic_field = rotation_period = 0;
00099     birth_mass=0;
00100 }
00101 
00102 
00103 single_star::single_star(single_star & rv) : star(rv) {
00104 
00105   identity      = rv.identity;
00106 
00107   for (int i=NAC; i<no_of_spec_type; i++)
00108     spec_type[i] = rv.spec_type[i];
00109 
00110   //            copy star
00111   current_time  = rv.current_time;
00112   relative_age  = rv.relative_age;
00113   relative_mass = rv.relative_mass;
00114   envelope_mass = rv.envelope_mass;
00115   core_mass     = rv.core_mass;
00116   COcore_mass   = rv.COcore_mass;
00117 
00118   core_radius   = rv.core_radius;
00119   radius        = rv.radius;
00120   luminosity    = rv.luminosity;
00121   effective_radius = rv.effective_radius;
00122   last_update_age = rv.last_update_age;
00123   next_update_age = rv.next_update_age;
00124   velocity        = rv.velocity;
00125   wind_constant   = rv.wind_constant;
00126   accreted_mass   = rv.accreted_mass;
00127   magnetic_field  = rv.magnetic_field;
00128   rotation_period = rv.rotation_period;
00129   birth_mass      = rv.birth_mass;
00130                         
00131   //              copy stellar history.
00132   previous.current_time    = rv.previous.current_time;
00133   previous.last_update_age = rv.previous.last_update_age;
00134   previous.next_update_age = rv.previous.next_update_age;
00135   previous.relative_age    = rv.previous.relative_age;
00136   previous.relative_mass   = rv.previous.relative_mass;
00137   previous.envelope_mass   = rv.previous.envelope_mass;
00138   previous.core_mass       = rv.previous.core_mass;
00139   previous.COcore_mass     = rv.previous.COcore_mass;
00140 
00141   previous.radius          = rv.previous.radius;
00142   previous.effective_radius= rv.previous.effective_radius;
00143   previous.magnetic_field  = rv.previous.magnetic_field;
00144   previous.rotation_period = rv.previous.rotation_period;
00145   previous.birth_mass      = rv.previous.birth_mass;
00146 
00147 }
00148 
00149 void single_star::post_constructor() {
00150 
00151 //(GN+SPZ Apr 28 1999) stars with M < 8 Msun have wind per phase:
00152   update_wind_constant();
00153 
00154     // MEmory refrsh to prevent helium star to become white dwarf with
00155     // zero-mass core.
00156     // Not clear yet if companion and binary must also be updated?
00157     // (SPZ+GN, 10 Nov 1998)
00158       if (is_binary_component())
00159          get_binary()->refresh_memory();
00160       else
00161          refresh_memory();
00162 //    refresh_memory();
00163     
00164     if (is_binary_component() && get_binary()->get_bin_type()==Detached)
00165       get_binary()->set_first_contact(false);
00166 
00167     if (is_binary_component())
00168       get_binary()->dump("SeBa.data", true);
00169     else 
00170 // (GN May 12 1999) skrews up output
00171 //    {
00172 //      dump("SeBa.data", true);
00173 //      cerr << endl;
00174 //    }
00175   
00176 
00177     if (remnant()) {
00178       if (is_binary_component())
00179         get_binary()->dump("binev.data", false);
00180       else
00181         dump("binev.data", false);
00182     }
00183 
00184 }
00185 
00186 void single_star::initialize(int id, real t_cur,
00187                              real t_rel, real m_rel, real m_tot,
00188                              real m_core, real co_core) {
00189 
00190    //cerr << "Initialize from: ";
00191    //PRC(id);PRC(t_cur);PRC(t_rel);PRC(m_rel);PRC(m_tot);PRL(m_core);
00192   
00193   real m_env = m_tot - m_core;
00194   if (m_rel<=0 || m_rel>cnsts.parameters(maximum_main_sequence)) {
00195     cerr << "Mass of initial star is prefered to be "
00196          << "\nwithin reasonable limits <0, "
00197          << cnsts.parameters(maximum_main_sequence)
00198          << "] \nbut found (mass = " << m_rel << ")" << endl;
00199     if (m_rel<=0)
00200       exit (-1);
00201   }
00202 
00203   identity = id;
00204   luminosity = 0.01;
00205   current_time = t_cur;
00206   relative_age = t_rel;
00207   relative_mass = max(m_rel, m_env+m_core);
00208   previous.envelope_mass = envelope_mass = m_env;
00209   core_mass = m_core;
00210   COcore_mass = co_core;
00211 
00212   instantaneous_element();
00213 
00214   // (SPZ+GN: 26 Jul 2000) 
00215   // update_wind_constant() must be called before
00216   update_wind_constant();
00217   adjust_next_update_age();
00218 
00219   // Was previously done after adjust_next_update_age, which may be wrong?
00220   instantaneous_element();
00221 
00222   update();
00223 }
00224 
00225 // Determine size of stellar core from fits to
00226 // temperature and luminosity from figure of
00227 // Iben, I.Jr., and Tutukov, A.V., 1985, ApJSS 58, 661.
00228 real single_star::helium_core_radius() {
00229 
00230   // Safety. Should ne be required.
00231   if (core_mass==0) {
00232     cerr << "WARNING single_star::helium_core_radius():" << endl;
00233     cerr << "        core_radius == 0" << endl;
00234     cerr << "        action: return 0;" << endl;
00235     return 0;
00236   }
00237 
00238   real r_he_core;
00239   real tmp = log10(core_mass)
00240             * (0.4509 - 0.1085*log10(core_mass)) + 4.7143;
00241   real lum  = 8.33*tmp - 36.8;
00242   tmp = 1.e-3*pow(10., tmp);
00243   lum  = pow(10., lum);
00244 
00245   // helium core is smaller than helium star of same mass.
00246   // reasoning: after spiral-in class helium_star is supposed to
00247   // handle further mass transfer.
00248   //  real fraction = 0.5; // (SPZ+GN: 6 Oct 1998)
00249   real fraction =1.; // But gives unrealistic mass transfer after spiral-in
00250   r_he_core = fraction*33.45*sqrt(lum)/pow(tmp, 2);
00251  
00252   return min(radius, r_he_core);
00253 }
00254 
00255 real single_star::main_sequence_time(const real mass) {
00256 
00257   real t_ms = (2550. + 667.*pow(mass,2.5) + pow(mass,4.5) )
00258             / (0.0327*pow(mass,1.5) + 0.346*pow(mass,4.5));
00259 
00260   return t_ms;
00261 }
00262 
00263 real single_star::main_sequence_time() {
00264 
00265   real t_ms = (2550. + 667.*pow(relative_mass,2.5) 
00266             + pow(relative_mass,4.5) )
00267             / (0.0327*pow(relative_mass,1.5) 
00268             + 0.346*pow(relative_mass,4.5));
00269 
00270   return t_ms;
00271 }
00272 
00273 real single_star::hertzsprung_gap_time(const real mass, const real t_ms) {
00274 
00275   return 0.54*t_ms/(mass*(mass - 2.1) + 23.3);
00276 }
00277 
00278 real single_star::hertzsprung_gap_time(const real t_ms) {
00279  
00280   return 0.54*t_ms/(relative_mass*(relative_mass - 2.1) + 23.3);
00281 }
00282 
00283 real single_star::helium_giant_time(const real mass, const real t_ms) {
00284 
00285   real l_bms = base_main_sequence_luminosity(mass);
00286   real l_he = helium_giant_luminosity(mass);
00287 
00288   return t_ms*l_bms/(l_he*(pow(mass, 0.42) + 0.8));
00289 }
00290 
00291 real single_star::helium_giant_time(const real t_ms) {
00292 
00293   real l_bms = base_main_sequence_luminosity();
00294   real l_he  = helium_giant_luminosity();
00295 
00296   return t_ms*l_bms/(l_he*(pow(relative_mass, 0.42) + 0.8));
00297 }
00298 
00299 real single_star::base_giant_branch_time(const real mass, const real t_ms) {
00300 
00301   real t_g    = 0.15 * t_ms;
00302   real l_g    = giant_luminosity(mass);
00303   // (SPZ+GN: 26 Jul 2000) mass added to function call:
00304   real l_bagb = base_agb_luminosity(l_g, mass);
00305 
00306   return t_g - t_g*pow((l_g/l_bagb), 0.855);
00307 }
00308 
00309 real single_star::base_giant_branch_time(const real t_ms) {
00310 
00311   real t_g    = 0.15 * t_ms;
00312   real l_g    = giant_luminosity();
00313   real l_bagb = base_agb_luminosity(l_g);
00314 
00315   return t_g - t_g*pow((l_g/l_bagb), 0.855);
00316 }
00317 
00318 real single_star::base_giant_time(const real mass, const real t_ms) {
00319 
00320   real t_gs  = 0.15*t_ms;
00321   real l_g   = giant_luminosity(mass);
00322   real l_agb = agb_luminosity(mass);
00323 
00324   return t_gs*pow(l_g/l_agb, 0.855);
00325 }
00326 
00327 real single_star::base_giant_time(const real t_ms) {
00328 
00329   real t_gs  = 0.15*t_ms;
00330   real l_g   = giant_luminosity();
00331   real l_agb = agb_luminosity();
00332 
00333   return t_gs*pow(l_g/l_agb, 0.855);
00334 }
00335 
00336 real single_star::nucleair_evolution_time(const real mass) {
00337 
00338   real l_g = giant_luminosity(mass);
00339   //(SPZ+GN: 26 Jul 2000) mass should be passed through
00340   real l_bagb = base_agb_luminosity(l_g, mass); 
00341   real l_agb = agb_luminosity(mass);
00342 
00343   real t_ms = main_sequence_time(mass);
00344   real t_g = 0.15*t_ms;
00345   real t_hg = hertzsprung_gap_time(mass, t_ms);
00346   real t_bgb = t_g - t_g*pow((l_g/l_bagb), 0.855);
00347   real t_he = helium_giant_time(mass, t_ms); //(SPZ+GN: 26 Jul 2000) add 'mass'
00348   real t_gs = t_g;
00349   real t_b = t_gs*pow(l_g/l_agb, 0.855);
00350   real t_agb = t_gs - t_bgb - t_b;
00351 
00352   return t_ms + t_hg + t_bgb + t_he + t_agb;
00353 }
00354 
00355 
00356 real single_star::nucleair_evolution_time() {
00357 
00358   real l_g = giant_luminosity();
00359   real l_bagb = base_agb_luminosity(l_g);
00360   real l_agb = agb_luminosity();
00361 
00362   real t_ms = main_sequence_time();
00363   real t_g = 0.15*t_ms;
00364   real t_hg = hertzsprung_gap_time(t_ms);
00365   real t_bgb = t_g - t_g*pow((l_g/l_bagb), 0.855);
00366   real t_he = helium_giant_time(t_ms); 
00367   real t_gs = t_g;
00368   real t_b = t_gs*pow(l_g/l_agb, 0.855);
00369   real t_agb = t_gs - t_bgb - t_b;
00370 
00371   return t_ms + t_hg + t_bgb + t_he + t_agb;
00372 }
00373 
00374 real single_star::base_main_sequence_luminosity() {
00375 
00376   real l_bms;
00377   if (relative_mass<=1.093) {
00378     l_bms =  (1.107*pow(relative_mass, 3.)
00379               +   240.7*pow(relative_mass, 9.))
00380           /  (1. + 281.9*pow(relative_mass, 4.));
00381   }
00382   else {
00383     l_bms =  (13990.*pow(relative_mass, 5.))
00384           /             (pow(relative_mass, 4.)   
00385                          +  2151.*pow(relative_mass, 2)
00386                          +  3908.*relative_mass +9536.);
00387   }
00388   
00389   return l_bms;
00390 }
00391 
00392 real single_star::base_main_sequence_luminosity(const real mass) {
00393 
00394   real l_bms;
00395   if (mass<=1.093) {
00396     l_bms =  (1.107*pow(mass, 3.)+ 240.7*pow(mass, 9.))
00397           /  (1. + 281.9*pow(mass, 4.));
00398   }
00399   else {
00400     l_bms =  (13990.*pow(mass, 5.))
00401           / (pow(mass, 4.) + 2151.*pow(mass, 2)+3908.*mass +9536.);
00402   }
00403    
00404   return l_bms;
00405 }
00406 
00407 real single_star::giant_luminosity(const real mass) {
00408 
00409   real l_g = (2.15 + 0.22*pow(mass, 3.))*pow(mass, 2)
00410            / (5.0e-6*pow(mass, 4.)+1.4e-2*mass*mass + 1.);
00411 
00412   return l_g;
00413 }
00414 
00415 real single_star::giant_luminosity() {
00416   
00417   real l_g = (2.15 + 0.22*pow(relative_mass, 3.))
00418            *  pow(relative_mass, 2)
00419            / (5.0e-6*pow(relative_mass, 4.)
00420            +  1.4e-2*relative_mass*relative_mass + 1.);
00421 
00422   return l_g;
00423 }
00424 
00425 real single_star::helium_giant_luminosity(const real mass) {
00426 
00427   // Prescription according to EFT89.
00428   //real l_bms = base_main_sequence_luminosity(mass);
00429   //return 0.763*pow(mass, 0.46)*l_bms
00430   //  + 50.0/pow(mass, 0.1);
00431 
00432   // Changed (SPZ+GN:09/98) as in Tout et all. 97.
00433   real l_g = base_giant_branch_luminosity(mass);
00434   real l_HeI = base_agb_luminosity(l_g, mass);
00435   real l_He = 49*pow(mass, 0.364) + 0.86*pow(mass, 4.);
00436 
00437   return min(l_He, l_HeI);
00438 }
00439 
00440 real single_star::helium_giant_luminosity() {
00441 
00442   //    Helium core bunring giant.
00443   //real l_bms = base_main_sequence_luminosity();
00444   //return 0.763*pow(relative_mass, 0.46)*l_bms
00445   //  + 50.0/pow(relative_mass, 0.1);
00446 
00447   // Changed (SPZ+GN:09/98) as in Tout et all. 97.
00448   real l_g = base_giant_branch_luminosity(relative_mass);
00449   real l_HeI = base_agb_luminosity(l_g, relative_mass);
00450   real l_He = 49*pow(relative_mass, 0.364)
00451             +  0.86*pow(relative_mass, 4.);
00452 
00453   return min(l_He, l_HeI);
00454 
00455 }
00456 
00457 real single_star::base_giant_branch_luminosity(const real mass) {
00458 
00459   real kappa, lambda;
00460   real log_mass = log10(mass);
00461 
00462   if (mass<1.334) {
00463     kappa  = 0.2594 + 0.1348*log_mass;
00464     lambda = 0.144 - 0.8333*log_mass;
00465   }
00466   else {
00467     kappa  = 0.092088 + 0.059338*log_mass;
00468     lambda = -0.05713 + log_mass*(0.3756 -0.1744);
00469   }
00470 
00471   real l_bms = base_main_sequence_luminosity(mass);
00472 
00473   return l_bms*pow(10., kappa + lambda);
00474 }
00475 
00476 
00477 real single_star::base_giant_branch_luminosity() {
00478 
00479   real kappa, lambda;
00480   real log_mass = log10(relative_mass);
00481 
00482   if (relative_mass<1.334) {
00483     kappa  = 0.2594 + 0.1348*log_mass;
00484     lambda = 0.144 - 0.8333*log_mass;
00485   }
00486   else {
00487     kappa  = 0.092088 + 0.059338*log_mass;
00488     lambda = -0.05713 + log_mass*(0.3756 -0.1744);
00489   }
00490 
00491   real l_bms = base_main_sequence_luminosity();
00492 
00493   return l_bms*pow(10., kappa + lambda);
00494 }
00495 
00496 real single_star::base_agb_luminosity(const real l_g) {
00497 
00498   // EFT89 method.
00499   //return l_g + 2.e3;
00500   
00501   // Changed (SPZ+GN:09/98) as in Tout et all. 97.
00502   real l_agb=2454.7;
00503   if (relative_mass >
00504       cnsts.parameters(upper_ZAMS_mass_for_degenerate_core)) 
00505     l_agb = 6.5*pow(min(relative_mass, 20.), 3.25);
00506   
00507   return max(l_agb, l_g);
00508 }
00509 
00510 real single_star::base_agb_luminosity(const real l_g,
00511                                       const real mass) {
00512 
00513   real l_agb=2454.7;
00514   if (mass >
00515       cnsts.parameters(upper_ZAMS_mass_for_degenerate_core)) 
00516     l_agb = 6.5*pow(min(mass, 20.), 3.25);
00517   
00518   return max(l_agb, l_g);
00519 }
00520 
00521 real single_star::agb_luminosity(const real mass) {
00522 
00523   return mass*(4.0e3 + 5.0e2*mass);
00524 }
00525 
00526 real single_star::agb_luminosity() {
00527  
00528   return relative_mass*(4.0e3 + 5.0e2*relative_mass);
00529 }
00530 
00531 real single_star::maximum_luminosity(const real mass) {
00532 
00533   return 4000*mass + 500*pow(mass,2);
00534 }
00535 
00536 real single_star::maximum_luminosity() {
00537   return 4000*relative_mass + 500*pow(relative_mass,2);
00538 }
00539      
00540 // Helium core lifetime.
00541 // Tabulation method is better since it depends on the mass
00542 // of the core only.
00543 real single_star::helium_time() {
00544 
00545   real m = get_total_mass();
00546 
00547   // Optional but rather old
00548   // Iben and Tutukov, 1985, ApJSS, 58, 661.
00549   // t_he =  0.56*t_ms/pow(relative_mass, 0.52);
00550   
00551   // Helium Star lifetime from 
00552   // Pols O.R., 1993,
00553   // PhD Thesis, University of Amsterdam, P13, Eq. 2.15
00554 
00555   real t_he = 0;
00556   if (m<=0.7) 
00557     t_he = 10.76*pow(m, -3.75); 
00558   else if(m<=1.6) 
00559     t_he = 17.1*pow(m, -2.45); 
00560   else if(m<=4.8) 
00561     t_he = 11.48*pow(m, -1.6); 
00562   else    
00563     t_he = 2.37*pow(m, -0.6);
00564 
00565   return t_he;
00566 }
00567 
00568 real single_star::temperature() {
00569 //  cerr<<"single_star::temperature()"<<endl;
00570 //  PRC(luminosity);PRL(effective_radius);
00571 
00572   // Effective radius is the radius of the star as it really is.
00573   // radius is the equilibrium radius of the star.
00574   // return pow(1130.*luminosity/(radius*radius), 0.25); // in [1000K]
00575 
00576 
00577   real T_eff = cnsts.parameters(Tsun)
00578              * pow(luminosity/pow(effective_radius, 2), 0.25); // in [K]
00579   
00580   return T_eff;
00581 }
00582 
00583 real single_star::magnitude() {
00584 
00585   return -2.5*log10(luminosity) + 4.75 - bolometric_correction();
00586 }
00587 
00588 // real function bolometric_correction()
00589 // calculates bolometric correction for giant stars
00590 // input: stellar effective surface temperature in kKelvin.
00591 // output: bolometric correction for giant star in cgs.
00592 real single_star::bolometric_correction() {
00593 
00594   // temperature() is defined in Kelvin.
00595   // here we should use old 10^3K implementation 
00596   // (SPZ+GN: 1 Oct 1998)
00597   real temp_in_kK = 0.001 * temperature();
00598   real bc;
00599 
00600   if (temp_in_kK < 4.195)
00601     bc = 2.5*log10((1.724e-7*pow(temp_in_kK,11.) + 1.925e-2)
00602                    / (1. + 1.884e-9*pow(temp_in_kK,14.)));
00603   else if (temp_in_kK >=  4.195 &&
00604            temp_in_kK <= 10.89)
00605     bc = 2.5*log10((7.56e-2*pow(temp_in_kK,1.5))
00606                    / (1. + 6.358e-5*pow(temp_in_kK, 4.5)));
00607   else
00608     bc = 2.5*log10((2728/pow(temp_in_kK,3.5) + 1.878e-2*temp_in_kK)
00609                    /(1. + 5.362e-5*pow(temp_in_kK,3.5)));
00610 
00611   return bc;
00612 }
00613 
00614 // wind_velocity(): Calculates stellar wind velocoty.
00615 // Steller wind velocity is 2.5 times stellar escape velocity
00616 real single_star::wind_velocity() {
00617 
00618   real v_esc2 = cnsts.physics(G)
00619               * cnsts.parameters(solar_mass)*get_total_mass()
00620               / (effective_radius*cnsts.parameters(solar_radius));
00621   real v_wind = 2.5*sqrt(v_esc2)/cnsts.physics(km_per_s);
00622 
00623   return v_wind;
00624 }
00625 
00626 real single_star::kelvin_helmholds_timescale() {
00627 
00628   // Equilibrium radius is 'single_star::radius'
00629   // Effective radius may be puffed up by accretion or subtraction of mass.
00630 
00631   return 31.56*pow(relative_mass,2.)/(radius*luminosity); // [Myr]
00632 }
00633 
00634 real single_star::nucleair_evolution_timescale() {
00635   // overloaded for main_sequence:: as
00636   // t_nuc = 10^10 [years] Msun/Lsun.
00637   // Assumed that 0.1 Msun is thermalized.
00638 
00639   // but for giants etc. we use the following, based on
00640   // dimensional grounds and empirical comparison with
00641   // Pols, 1994, A&A 290, 119
00642   // (SPZ+GN:30 Sep 1998)
00643   
00644 //  real fused_mass = 0.1*relative_mass;
00645 //
00646 //  real t_nuc = cnsts.parameters(energy_to_mass_in_internal_units)
00647 //             * fused_mass/luminosity;
00648 //
00649 //  real t_kh = kelvin_helmholds_timescale();
00650 //
00651 //  return sqrt(t_nuc * t_kh);
00652   
00653 
00654 // (GN+SPZ Apr 28 1999) giant lifetime is ~ 10% of ms life time
00655 
00656   return 0.1*main_sequence_time();
00657 
00658 }
00659 
00660 real single_star::dynamic_timescale() {
00661 
00662   return 5.08e-11*sqrt(pow(radius, 3.)/relative_mass);    // [Myr]
00663 }
00664 
00665 
00666 bool single_star::low_mass_star() {
00667 
00668   bool is_low_mass_star = false;
00669 
00670   if (!remnant()) {
00671     if(relative_mass <= cnsts.parameters(low_mass_star_mass_limit)) 
00672       is_low_mass_star = true;
00673   }
00674   else if (get_total_mass() <=
00675            cnsts.parameters(low_mass_star_mass_limit)) {
00676     is_low_mass_star = true;
00677   }
00678 
00679   return is_low_mass_star;
00680 }
00681 
00682 bool single_star::medium_mass_star() {
00683   
00684   return (!low_mass_star() && !high_mass_star())?true:false;
00685 }
00686 
00687 bool single_star::high_mass_star() {
00688   
00689   if(remnant())
00690     return (get_total_mass()>cnsts.parameters(medium_mass_star_mass_limit))
00691            ?true :false;
00692   else
00693     return (get_relative_mass()>cnsts.parameters(medium_mass_star_mass_limit))
00694            ?true :false;
00695 }
00696 
00697 void single_star::read_element() {
00698 
00699   real total_mass, log_temp, log_lum;
00700   real bol_corr, temp, mv;
00701   int type = (int)star_type;
00702   cin >> type >> relative_age >> relative_mass
00703       >> total_mass >> core_mass >> radius >> log_temp
00704       >> log_lum >> bol_corr >> mv >> velocity
00705       >> magnetic_field >>  rotation_period;
00706 
00707   envelope_mass = total_mass - core_mass;
00708   temp = pow(log_temp, 10);
00709   luminosity = pow(log_lum, 10);
00710 }
00711 
00712 void single_star::put_element() {
00713 
00714   ofstream outfile("binev.data", ios::app|ios::out);
00715   if (!outfile) cerr << "error: couldn't create file binev.data"<<endl;
00716 
00717   real bol_corr = bolometric_correction();
00718   real mv = magnitude();
00719   outfile << star_type << " " << relative_age << " "
00720           << relative_mass << " " << get_total_mass() << " "
00721           << core_mass << " " << radius << " "
00722           << log10(temperature()) << " "
00723           << log10(luminosity) << " " << bol_corr << " "
00724           << mv << " " << " " << velocity << " "
00725           << magnetic_field <<  rotation_period << endl;
00726 
00727   outfile.close();
00728 }
00729 
00730 void single_star::dump(ostream & s, bool brief) {
00731 
00732   if (brief) {
00733     
00734     s << get_node()->format_label() << " "
00735       << get_current_time() << " "
00736       << "0 1   ";
00737     s << get_node()->format_label() << " "        
00738       << get_element_type() << " "
00739       << get_total_mass() << " "
00740       << radius << "    ";
00741     s << "0 0 0 0" << endl;
00742   }
00743   else
00744     {
00745       real bol_corr = bolometric_correction();
00746       int s1, s2, s3, s4, s5, s6;
00747       s1 = get_spec_type(Emission);
00748       s2 = get_spec_type(Blue_Straggler);
00749       s3 = get_spec_type(Barium);
00750       s4 = get_spec_type(Rl_filling) + get_spec_type(Accreting);
00751       s5 = get_spec_type(Runaway);
00752       s6 = get_spec_type(Merger);
00753 
00754       s << "1\n ";
00755       s << get_element_type() << " " << s1 << " " << s2 << " "
00756         << s3 << " " << s4 << " " << s5 << " " << s6 << endl;
00757       s <<" " << identity
00758         << " " << current_time
00759         << " " << relative_age 
00760         << " " << relative_mass
00761         << " " << get_total_mass()
00762         << " " << core_mass
00763         << " " << radius
00764         << " " << effective_radius
00765         << " " << log10(temperature())
00766         << " " << log10(luminosity)
00767         << " " << bol_corr
00768         << " " << magnitude()
00769         << " " << velocity
00770         << " " << magnetic_field
00771         << " " << rotation_period
00772         << endl;
00773     }
00774 }
00775 
00776 void single_star::dump(char * filename, bool brief) {
00777 
00778   ofstream s(filename, ios::app|ios::out);
00779   if (!s) cerr << "error: couldn't create file "<<filename<<endl;
00780 
00781   if (brief) {
00782     
00783     s << get_node()->format_label() << " "
00784       << get_current_time() << " "
00785       << "0 1   ";
00786     s << get_node()->format_label() << " "        
00787       << get_element_type() << " "
00788       << get_total_mass() << " "
00789       << radius << " ";
00790     s << "0 0 0 0" << endl;
00791 
00792   }
00793   else
00794     {
00795 
00796       real bol_corr = bolometric_correction();
00797       int s1, s2, s3, s4, s5, s6;
00798       s1 = get_spec_type(Emission);
00799       s2 = get_spec_type(Blue_Straggler);
00800       s3 = get_spec_type(Barium);
00801       s4 = get_spec_type(Rl_filling) + get_spec_type(Accreting);
00802       s5 = get_spec_type(Runaway);
00803       s6 = get_spec_type(Merger);
00804 
00805       s << "1\n ";
00806       s << get_element_type() << " " << s1 << " " << s2 << " "
00807         << s3 << " " << s4 << " " << s5 << " " << s6 << endl;
00808       s <<" " << identity
00809         << " " << current_time
00810         << " " << relative_age
00811         << " " << relative_mass
00812         << " " << get_total_mass()
00813         << " " << core_mass
00814         << " " << radius
00815         << " " << effective_radius
00816         << " " << log10(temperature())
00817         << " " << log10(luminosity)
00818         << " " << bol_corr
00819         << " " << magnitude()
00820         << " " << velocity
00821         << " " << magnetic_field
00822         << " " << rotation_period
00823         << endl;
00824 
00825     }
00826   s.close();
00827 }
00828 
00829 void single_star::put_state() {
00830 
00831   star_state str;
00832   str.init_star_state(dynamic_cast(single_star*, this));
00833   str.make_star_state(dynamic_cast(single_star*, this));
00834 
00835   str.put_star_state();
00836 }
00837 
00838 void single_star::put_hrd(ostream & s) {
00839 
00840   int s1, s2, s3, s4, s5, s6;
00841   s1 = get_spec_type(Emission);
00842   s2 = get_spec_type(Blue_Straggler);
00843   s3 = get_spec_type(Barium);
00844   s4 = get_spec_type(Rl_filling) + get_spec_type(Accreting);
00845   s5 = get_spec_type(Runaway);
00846   s6 = get_spec_type(Merger);
00847 
00848   s << "1\n ";
00849   s << s1 << " " << s2 << " " << s3 << " " << s4 << " "
00850     << s5 << " " << s6 << " ";
00851   s << get_total_mass()
00852     << " " << log10(temperature()) 
00853     << " " << log10(luminosity) 
00854     << endl;
00855 }
00856 
00857 void single_star::refresh_memory() {
00858 
00859   previous.star_type = get_element_type();
00860   previous.current_time = current_time;
00861   previous.last_update_age = last_update_age;
00862   previous.next_update_age = next_update_age;
00863   previous.relative_age = relative_age;
00864   previous.relative_mass = relative_mass;
00865   previous.envelope_mass = envelope_mass;
00866   previous.core_mass = core_mass;
00867   previous.COcore_mass = COcore_mass;
00868 
00869   previous.radius = radius;
00870   previous.effective_radius = effective_radius;
00871   
00872   //             Pulsars
00873   previous.magnetic_field  = magnetic_field;
00874   previous.rotation_period = rotation_period;
00875   previous.birth_mass      = birth_mass;
00876 }
00877 
00878 void single_star::recall_memory() {
00879 
00880   star_type        = previous.star_type;
00881   current_time     = previous.current_time;
00882   last_update_age  = previous.last_update_age;
00883   next_update_age  = previous.next_update_age;
00884   relative_age     = previous.relative_age;
00885   relative_mass    = previous.relative_mass;
00886   envelope_mass    = previous.envelope_mass;
00887   core_mass        = previous.core_mass;
00888   COcore_mass      = previous.COcore_mass;
00889 
00890   radius           = previous.radius;
00891   effective_radius = previous.effective_radius;
00892 
00893   // Pulsars
00894   magnetic_field   = previous.magnetic_field;
00895   rotation_period  = previous.rotation_period;
00896   birth_mass       = previous.birth_mass;
00897 }
00898 
00899 // Mass transfer timescale is checked and updated at the moment the
00900 // mass-ratio is reversed.
00901 
00902 // in version 3.3, the mass transfer timescale is updated each
00903 // timestep in ::recursive(), therefore this function is not required.
00904 // It hangs the code
00905 // because mass loss by stellar wind occurs after
00906 // ::mass_ratio_mdot_limit().
00907 // therefore the mass ratio > 1 after ::recursive step.
00908 // (SPZ+GN:11 Oct 1998)
00909 real single_star::mass_ratio_mdot_limit(real mdot) {
00910 
00911     
00912     // No limit for the moment.
00913     return mdot;
00914     
00915     real accretor_mass = 0;
00916 
00917     if (is_binary_component()) 
00918       get_companion()->get_total_mass();
00919 
00920     if (accretor_mass<get_total_mass()) {
00921         real mdot_max = get_total_mass() - accretor_mass;
00922         if (mdot>mdot_max) 
00923         mdot = mdot_max;
00924     }
00925 
00926     int p = cerr.precision(HIGH_PRECISION);
00927     PRC(accretor_mass);PRL(get_total_mass());
00928     cerr.precision(p);
00929   
00930     return mdot;
00931 }
00932 
00933 // Computes expansion of acceptor due to mass accretion.
00934 // At moment accretor fills own Roche-lobe mass transfer becomes
00935 // inconservative.
00936 real single_star::accretion_limit(const real mdot, const real dt) {
00937 
00938   // Conservative mass transfer.
00939   // return mdot;
00940 
00941   // Non-conservative mass transfer.
00942   real r_rl = get_binary()->roche_radius(this);
00943   real mdot_kh = dt*relative_mass/kelvin_helmholds_timescale();
00944   real accretion = log10(r_rl/effective_radius)
00945                  / pow(10, expansionB(relative_mass));
00946 
00947   accretion = max(accretion, 0.);
00948   real mdot_max = mdot_kh*pow(accretion, 1./expansionA(relative_mass));
00949   mdot_max = max(mdot_max, 0.); 
00950 
00951   return min(mdot, mdot_max);
00952 
00953   // (SPZ+GN: 26 Jul 2000) Test Kelvin Helmholtz accretion
00954   // (GN Jul 28 1999) test non conservative Algol evolution
00955   // return min(mdot, mdot_kh);
00956 
00957 }
00958 
00959 void single_star::adjust_donor_radius(const real delta_m) {
00960 
00961 
00962   real zeta_th = zeta_thermal();
00963 
00964   // -1 because delta_m is defined positive and star loses mass.
00965   real delta_r = -1 * effective_radius * zeta_th * delta_m/relative_mass;
00966 
00967   effective_radius += delta_r;
00968   
00969   // Effective radius return to equilibrium radius when mass transfer
00970   // is on nuclear timescale
00971   // (SPZ+GN:30 Sep 1998)
00972   if (is_binary_component() &&
00973       get_binary()->get_current_mass_transfer_type()==Nuclear) {
00974     effective_radius = radius;
00975   }
00976 
00977 
00978 }
00979 
00980 
00981 // Adding mass to a star causes it to expand.
00982 void single_star::adjust_accretor_radius(const real mdot, const real dt) {
00983 
00984   // function returns directly: effective radius is used to determine RLOF.
00985   // Allowing accretor to grow in size results in contact systems.
00986   // do not allow bloating
00987   // (SPZ+GN:28 Sep 1998)
00988 //(GN+SPZ Apr 28 1999) star do bloat however... bloating on again
00989 //  return;
00990   
00991   //cerr<<"void star::adjust_accretor_radius()"<<endl;
00992   //cerr<<"pre radius: "<<radius<<" "<<effective_radius<<endl;
00993 
00994   if (mdot>0) {
00995     real mdot_kh = relative_mass*dt/kelvin_helmholds_timescale();
00996 
00997     real r_fr = expansionA(relative_mass)*log10(mdot/mdot_kh)
00998       + expansionB(relative_mass);
00999     if (r_fr>0.5) // (GN+SPZ Apr 28 1999) was 1 
01000       r_fr = 0.5;
01001 // (GN+SPZ Apr 28 1999) radius is equilibrium radius
01002 //    effective_radaius = radius = radius*pow(10, pow(10, r_fr));
01003 
01004     real r_l = get_binary()->roche_radius(this);
01005     effective_radius = max(min(r_l, effective_radius), 
01006                            radius*pow(10, pow(10, r_fr)));
01007              
01008   }
01009 }
01010 
01011 real single_star::expansionA(const real m) {
01012 
01013   // Lineair interpolation.
01014   real rc, inc;
01015   if (m<=3) {
01016     rc = 0.120;         //base on:      m1 = 2; A1 = 0.599;
01017     inc = 0.359;        //              m2 = 3; A2 = 0.719;
01018   }
01019   else if (m<=5) {
01020     rc = 0.144;         //based on:     m1 = 3; A1 = 0.719;
01021     inc = 0.289;        //              m2 = 5; A2 = 1.006;
01022   }
01023   else if (m<=10) {
01024     rc = 0.123;         //based on:     m1 = 5; A1 = 1.006;
01025     inc = 0.393;        //              m2 = 10; A2 = 1.619;
01026   }
01027   else {
01028     rc = 0.085;         //based on:     m1 = 10; A1 = 1.619;
01029     inc = 0.772;        //              m2 = 17; A2 = 2.212;
01030   }
01031      
01032   return inc + rc*m;
01033 }
01034 
01035 real single_star::expansionB(const real m) {
01036 
01037 //              Lineair interpolation.
01038   real rc, inc;
01039   if (m<=3) {
01040     rc = -0.273;     //base on:      m1 = 2; B1 = -1.374;
01041     inc = -0.828;    //              m2 = 3; B2 = -1.647;
01042   }
01043   else if (m<=5) {
01044     rc = -0.192;     //based on:     m1 = 3; B1 = -1.647;
01045     inc = -1.071;    //              m2 = 5; B2 = -2.030;
01046   }
01047   else if (m<=10) {
01048     rc = -0.106;    //based on:     m1 = 5; B1 = -2.030;
01049     inc = -1.50;    //              m2 = 10; B2 = -2.560;
01050   }
01051   else {
01052     rc = -7.08e-2;   //based on:     m1 = 10; B1 = -2.560;
01053     inc = -1.852;    //              m2 = 17; B2 = -3.056;
01054   }
01055 
01056   real value = inc + rc*m;
01057 
01058   return min(1., value);
01059 }
01060 
01061 // Merges cores and envelopes of two stars.
01062 // Star is updated.
01063 star* single_star::merge_elements(star* str) {
01064 
01065   star* merged_star = this;
01066 
01067   real m_conserved = get_total_mass() + str->get_total_mass();
01068 
01069   if (str->get_element_type()!=Main_Sequence) {
01070 
01071       // adding two cores of giants together should not result in
01072       // rejuvenation.
01073       // previous method appeared to make mergers too old.
01074       // (SPZ+GN:11 Oct 1998)
01075       
01076       add_mass_to_core(str->get_core_mass());
01077 
01078     if ((str->get_element_type()==Neutron_Star ||
01079          str->get_element_type()==Black_Hole)   &&
01080         core_mass < cnsts.parameters(helium2neutron_star)) {
01081       real dm = cnsts.parameters(helium2neutron_star) - core_mass;
01082       core_mass = cnsts.parameters(helium2neutron_star);
01083       if (envelope_mass<dm)
01084         envelope_mass = 0;
01085       else
01086         envelope_mass -= dm;
01087     }
01088 
01089     //          What to do here is put in SPH!
01090     if (str->get_envelope_mass()>0) 
01091       add_mass_to_accretor(0.5*str->get_envelope_mass());
01092 
01093   }
01094   else {
01095 
01096     add_mass_to_accretor(str->get_total_mass());
01097   }
01098 
01099   if (get_total_mass()-m_conserved > 1.e-11) {
01100     cerr.precision(HIGH_PRECISION);
01101     cerr << "ERROR: Mass is not conserved in single_star::merge elements()"
01102          << endl;
01103 
01104     PRC(get_total_mass());PRC(m_conserved);
01105     PRL(get_total_mass()-m_conserved);
01106     
01107     exit(-1);
01108   }
01109 
01110   spec_type[Merger]=Merger;
01111   adjust_next_update_age();
01112 
01113   
01114   // Redundant: in core mass addition star is no rejuvenated but aged.
01115   // addition of envelope mass causes rejuvenation.
01116   // (SPZ+GN:27 Sep 1998)
01117   //if (str->get_element_type()!=Main_Sequence) {
01118   //real aged = 0.01*(core_mass/agb_core_mass(relative_mass));
01119   //relative_age = (1+aged)*next_update_age;
01120   //}
01121 
01122 
01123   if (get_relative_mass() >= cnsts.parameters(massive_star_mass_limit) &&
01124         hydrogen_envelope_star()) 
01125       merged_star =  reduce_mass(envelope_mass);
01126   else {
01127 
01128     instantaneous_element();
01129     // calling evolve element may cause segmentation fault if star changes.
01130       //evolve_element(current_time);
01131   }
01132 
01133   cerr << "Merged star: "<<endl;
01134   merged_star->dump(cerr, false);
01135 
01136   return merged_star;
01137 }
01138 
01139 // Determine mass transfer stability according to
01140 // `zeta' discription.
01141 real single_star::mass_transfer_timescale(mass_transfer_type &type) {
01142 
01143   type = Unknown;
01144   
01145   real z_l=0, mass_ratio = 1;
01146   if (is_binary_component()) {
01147     mass_ratio = get_companion()->get_total_mass()/get_total_mass();
01148     z_l = get_binary()->zeta(this, get_companion());
01149   }
01150 
01151   real z_ad = zeta_adiabatic();
01152   real z_th = zeta_thermal();
01153 
01154   real mtt;
01155   if (z_ad>z_l && z_th>z_l) {
01156     //         mtt = 11.*kelvin_helmholds_timescale();
01157     mtt = nucleair_evolution_timescale();
01158     type = Nuclear;
01159   }
01160   else if (z_ad>z_l && z_l>z_th) {
01161     mtt = kelvin_helmholds_timescale();
01162 
01163     type = Thermal;
01164   }
01165   else if (z_l>z_ad) {
01166     mtt = sqrt(kelvin_helmholds_timescale()*dynamic_timescale());
01167     //if (medium_mass_star())
01168     //  mtt = 0.09*kelvin_helmholds_timescale();
01169     //else
01170     //  mtt = sqrt(kelvin_helmholds_timescale()*dynamic_timescale());
01171     type = Dynamic;
01172   }
01173   else {
01174     cerr << "No clear indication for mass transfer timescale: "
01175          << "Kelvin-Helmholds time-scale assumed."<<endl;
01176 
01177     mtt = kelvin_helmholds_timescale();
01178     type = Unknown;
01179   }
01180 
01181   if (low_mass_star()) {
01182 
01183     real mdot = get_binary()
01184               ->mdot_according_to_roche_radius_change(this,
01185                                                       get_companion());
01186     if (mdot>0) {
01187       real mtt_rl = get_relative_mass()/mdot;
01188       if(mtt>mtt_rl) {
01189         mtt = mtt_rl;
01190         type = AML_driven;
01191       }
01192       
01193     }
01194   }
01195 
01196   if (REPORT_MASS_TRANSFER_TIMESCALE) {
01197     cerr << "single_star::mass_transfer_timescale()" << endl;
01198     cerr << "    star id = " << identity
01199          << "  Zeta (lobe, ad, th) = ("
01200          << z_l <<", "<<z_ad<<", "<<z_th<<") : " << endl;
01201     cerr << type_string(type);
01202     cerr<<":    dm/dt=" <<get_relative_mass()/(mtt*1.e+6)
01203         << " [Msun/yr]" << endl;
01204   }
01205 
01206   return mtt;
01207 }
01208 
01209 //              Stellar stability functions.
01210 real single_star::zeta_adiabatic() {
01211 
01212 // (GN+SPZ Apr 28 1999) this is used by sub_giant: all stars with HW87
01213 // all stars should have their own actually...(when we have time)
01214 
01215 // (GN+SPZ Apr 28 1999) fit from Lev Yungelson private communication
01216 // for giants with not too convective envelope = radiative envelope
01217 
01218   real r_dconv = 2.4*pow(relative_mass,1.56);
01219   if (relative_mass > 10 )
01220     r_dconv = 5.24*pow(relative_mass,1.32);
01221   else if (relative_mass > 5)
01222     r_dconv = 1.33*pow(relative_mass,1.93);
01223     
01224   if (radius < r_dconv) {
01225     return 12.25;
01226 //    cerr << "radius < r_dconv" << endl;
01227   }
01228   else {
01229 //              Hjellming and Webbink 1987 ApJ, 318, 804
01230     real x = core_mass/get_total_mass();
01231     real A = -0.220823;
01232     real B = -2.84699;
01233     real C = 32.0344;
01234     real D = -75.6863;
01235     real E = 57.8109;
01236 
01237 // (GN+SPZ Apr 28 1999) not for (sub) giants    
01238 //  if (low_mass_star())
01239 //    z = -cnsts.mathematics(one_third);
01240 //  else 
01241     return A + x*(B + x*(C + x*(D + x*E)));
01242 
01243   }
01244 
01245 }
01246 
01247 // Values of zeta are changed (SPZ+GN:28 Sep 1998)
01248 real single_star::zeta_thermal() {
01249   //cerr<<"real single_star::zeta_thermal()"<<endl;
01250 
01251   real z;
01252   if (low_mass_star())
01253     z = 0;
01254   else 
01255     z = 0; // (GN+SPZ Apr 28 1999) radius determined by core only (was -1) 
01256 
01257   return z;
01258 }
01259 
01260 // add two cores. Is performed in ::merge_elements();
01261 void single_star::add_mass_to_core(const real mdot) {
01262 
01263   if (mdot<=0) {
01264     cerr << "single_star::add_mass_to_core(mdot=" << mdot << ")"<<endl;
01265     cerr << "mdot (" << mdot << ") smaller than zero!" << endl;
01266     
01267   }
01268   else {
01269     adjust_accretor_age(mdot, false);
01270     core_mass += mdot;
01271     accreted_mass += mdot;
01272     
01273     if (relative_mass<get_total_mass()) 
01274       update_relative_mass(get_total_mass());
01275     
01276   }
01277 
01278 }
01279 
01280 
01281 //              general mass transfer utilities.
01282 // Increase donor mass and possibly relative_mass of donor.
01283 // Check mass-transfer timescales before use.
01284 real single_star::add_mass_to_accretor(const real mdot) {
01285 
01286 //  cerr << "add_mass_to_accretor"<<endl;
01287 //  PRL(mdot);
01288 //  dump(cerr, false);
01289   
01290   if (mdot<=0) {
01291     cerr << "single_star::add_mass_to_accretor(mdot=" << mdot << ")"<<endl;
01292     cerr << "mdot (" << mdot << ") smaller than zero!" << endl;
01293 
01294     set_spec_type(Accreting, false);
01295     
01296     return 0;
01297   }
01298   else {
01299     adjust_accretor_age(mdot);
01300     envelope_mass += mdot;
01301     accreted_mass += mdot;
01302     
01303     if (relative_mass<get_total_mass()) 
01304       update_relative_mass(get_total_mass());
01305     
01306     set_spec_type(Accreting);
01307     
01308   }
01309 
01310   
01311   return mdot;
01312 }
01313 
01314 real single_star::add_mass_to_accretor(real mdot, const real dt) {
01315 
01316 //  cerr << "add_mass_to_accretor"<<endl;
01317 //  PRL(mdot);
01318 //  dump(cerr, false);
01319 
01320   if (mdot<0) {
01321     cerr << "single_star::add_mass_to_accretor(mdot=" << mdot 
01322          << ", dt=" << dt << ")"<<endl;
01323     cerr << "mdot (" << mdot << ") smaller than zero!" << endl;
01324     return 0;
01325   }
01326 
01327   mdot = accretion_limit(mdot, dt);
01328 
01329   adjust_accretor_age(mdot);
01330   envelope_mass += mdot;
01331   accreted_mass += mdot;
01332 
01333   if (relative_mass<get_total_mass()) 
01334     update_relative_mass(get_total_mass());
01335 
01336   adjust_accretor_radius(mdot, dt);
01337   
01338   set_spec_type(Accreting);
01339 
01340   return mdot;
01341 }
01342 
01343 // Post-evolution stellar update.
01344 // Makes sure age and radius are updated.
01345 void single_star::update() {
01346 
01347   // New core mass determination occurs in ::evolve_element.
01348   // (SPZ+GN:09/1998)
01349   // real m_tot = get_total_mass();
01350   // core_mass = helium_core_mass();
01351   // envelope_mass = m_tot - core_mass;
01352 
01353   core_radius = helium_core_radius();
01354 
01355 // (GN+SPZ Apr 28 1999)
01356 // effective_radius can be larger than  radius
01357   effective_radius = max(radius,effective_radius);
01358 
01359 
01360   // last update age is set after stellar expansion timescale is set.
01361 // (GN+SPZ May  4 1999) last_update_age now used as time of last type change
01362 //  last_update_age = relative_age;
01363 
01364   detect_spectral_features();
01365 
01366 }
01367 
01368 
01369 void single_star::detect_spectral_features() {
01370 
01371   //            Clean old spectral specifications.
01372   set_spec_type(Emission, false);
01373   set_spec_type(Blue_Straggler, false);
01374   set_spec_type(Barium, false);
01375 
01376   // set new
01377   if (is_binary_component())
01378     if (!remnant() && 
01379         !get_companion()->hydrogen_envelope_star() &&
01380         accreted_mass >= cnsts.parameters(Barium_star_mass_limit)
01381                        * relative_mass)
01382       set_spec_type(Barium);
01383 }
01384 
01385 // In the case of a binary, the companion star might accrete from a
01386 // stellar wind or post-AGB mass-shell.
01387 // Bondi, H., and Hoyle, F., 1944, MNRAS 104, 273 (wind accretion.
01388 // Livio, M., Warner, B., 1984, The Observatory 104, 152.
01389 real single_star::accrete_from_stellar_wind(const real mdot, const real dt) {
01390 
01391 //  PRC(mdot);PRL(dt);
01392 
01393   real alpha_wind = 0.5;
01394   real v_wind = get_companion()->wind_velocity();
01395 
01396   real acc_radius = pow(cnsts.physics(G)*cnsts.parameters(solar_mass)
01397                         * get_total_mass()
01398                         / pow(v_wind*cnsts.physics(km_per_s), 2),2)
01399                   / cnsts.parameters(solar_radius);
01400   real wind_acc = alpha_wind/(sqrt(1-pow(get_binary()->get_eccentricity(), 2))
01401                               * pow(cnsts.parameters(solar_radius)
01402                                     * get_binary()->get_semi(),2));
01403   real v_factor = 1/pow(1+pow(velocity/v_wind, 2), 3./2.);
01404 
01405   real mass_fraction = acc_radius*wind_acc*v_factor;
01406 // (GN+SPZ May  4 1999) Do not multiply with dt*cnsts.physics(Myear)!
01407 
01408 //  PRC(v_wind);PRC(acc_radius);PRC(wind_acc);PRL(v_factor);
01409 //  PRL(mass_fraction);PRL(mdot);
01410 
01411   mass_fraction = min(0.9, mass_fraction);
01412 
01413   return add_mass_to_accretor(mass_fraction*mdot, dt);
01414 }
01415 
01416 // Tidal energy dissipation during close encounter.
01417 // Portegies Zwart, SF & Meinen AT, 1992, AA 280, 174.
01418 // for polytrope n=1.5
01419 real single_star::tf2_energy_diss(const real eta) {
01420 
01421   const real coeff2[] = {-0.397, 1.678, 1.277, -12.42, 9.446, -5.550};
01422 
01423   real y = log10(eta);
01424   real logT = ((((coeff2[5]*y + coeff2[4])*y + coeff2[3])*y 
01425                 + coeff2[2])*y + coeff2[1])*y + coeff2[0];
01426 
01427   return pow(10., logT);
01428 }
01429 
01430 // Tidal energy dissipation during close encounter.
01431 // Portegies Zwart, SF & Meinen AT, 1992, AA 280, 174.
01432 // for polytrope n=1.5
01433 real single_star::tf3_energy_diss(const real eta) {
01434 
01435   const real coeff3[] = {-0.909, 1.574, 12.37, -57.40, 80.10, -46.43};
01436 
01437   real y = log10(eta);
01438   real logT = ((((coeff3[5]*y + coeff3[4])*y + coeff3[3])*y  
01439                 + coeff3[2])*y + coeff3[1])*y + coeff3[0];
01440 
01441   return pow(10., logT);
01442 }
01443 
01444 //      pretty-print
01445 void single_star::print_status() {
01446   
01447   star_state str;
01448   str.init_star_state((single_star*)this);
01449   str.make_star_state((single_star*)this);
01450   
01451   cout << " [M = " << get_total_mass() 
01452        << ", R = " << effective_radius 
01453        << ", v = " << velocity << "] "
01454        << type_string(get_element_type()) << " ";
01455   str.put_star_state();
01456 
01457 }
01458 
01459 //      print data for EPJ Roche program.
01460 void single_star::print_roche() {
01461 
01462   real r = effective_radius;
01463   if (effective_radius<radius) r = 1.e6;
01464 
01465   cerr << get_total_mass() << " " << r << " ";
01466 
01467 }
01468 
01469 void  single_star::set_spec_type(star_type_spec s,
01470                                  bool on) {     // default =true
01471 
01472   if (on) spec_type[s] = s;
01473   else    spec_type[s] = NAC;
01474 }
01475 
01476 
01477 // Angular momentum of homogeneous sphere.
01478 real single_star::angular_momentum() {
01479        
01480   real m = get_total_mass()*cnsts.parameters(solar_mass);
01481   real r = effective_radius*cnsts.parameters(solar_radius);
01482 
01483 // (GN+SPZ May  5 1999) effective_radius may increase when rl shrinks
01484   if (is_binary_component()) {
01485     r = min(r, 
01486             get_binary()->roche_radius(this)*cnsts.parameters(solar_radius));
01487   }
01488 
01489   real o = 0;                            // default rotation.
01490   if(rotation_period>0)
01491     o = 2*PI/rotation_period;
01492   else if (is_binary_component()) 
01493     o = 2*PI/(get_binary()->get_period()*cnsts.physics(days));
01494 
01495   return gyration_radius_sq()*m*o*pow(r, 2);
01496         
01497 }
01498 
01499 real single_star::rejuvenation_fraction(const real mdot_fr) {
01500 
01501       real rejuvenation = (1-pow(mdot_fr,
01502                                  cnsts.parameters(rejuvenation_exponent)));
01503 
01504       // no rejuvenation if companion has no hydrogen envelope.
01505       if(is_binary_component() &&
01506          !get_companion()->hydrogen_envelope_star()) 
01507         rejuvenation = 1;
01508 
01509       return rejuvenation;
01510 }
01511 
01512 void single_star::stellar_wind(const real dt) {
01513 //cerr << "void single_star::stellar_wind(const real dt=" << dt << ")" << endl;
01514 
01515 //  PRL(last_update_age);
01516 //  PRL(next_update_age);
01517 //  PRL(relative_age);
01518 // (GN+SPZ Apr 28 1999) wind for low mass stars per phase
01519     real end_time = next_update_age - last_update_age;
01520 //    real prev_rel_time = max(0.,previous.relative_age - last_update_age);
01521 //    real relative_time = min(relative_age - last_update_age, end_time);
01522     real relative_time = relative_age - last_update_age;
01523 
01524 //    PRL(end_time);
01525 //    PRL(prev_rel_time);
01526 //    PRL(relative_time);
01527 //    PRL(wind_constant);
01528 
01529 // for high mass stars over whole evolution
01530 // (GN May 12 1999)
01531 // except for stars more massive than 85 that become WR after ms immediately
01532     if (relative_mass >= cnsts.parameters(super_giant2neutron_star) &&
01533         relative_mass < 85.) {
01534       end_time = nucleair_evolution_time();
01535 //      prev_rel_time = previous.relative_age;
01536       relative_time = relative_age;
01537     }
01538 
01539 //    PRC(end_time);
01540 //    PRC(dt);
01541 //    PRC(prev_rel_time);
01542 //    PRC(relative_time);
01543 //    PRL(wind_constant);
01544 
01545     real wind_mass = wind_constant 
01546                    * (pow(relative_time/end_time,
01547                         cnsts.parameters(massive_star_mass_loss_law))
01548                    -  pow((relative_time-dt)/end_time,
01549                         cnsts.parameters(massive_star_mass_loss_law)));
01550 
01551     // Previous second term according to GN.
01552 //                 -  pow((prev_rel_time)/end_time,
01553 //                      cnsts.parameters(massive_star_mass_loss_law)));
01554 // (GN+SPZ Apr 28 1999) wind induced helium star formation can happen
01555 // because stellar_wind is last function in evolve_element
01556   if (wind_mass>=envelope_mass) {
01557     wind_mass = envelope_mass;
01558     radius = core_radius;
01559   }
01560   
01561 //  PRL(wind_mass);
01562 //  dump(cerr, false);
01563   if (is_binary_component())
01564     get_binary()->adjust_binary_after_wind_loss(this, wind_mass, dt);
01565   else {
01566 // (GN Oct 11 1999) for single stars: previous used for stellar wind! (?)
01567     // refresh_memory();
01568 
01569     reduce_mass(wind_mass);
01570   }
01571 
01572   return;
01573 }
01574 
01575 void single_star::update_relative_mass(const real new_relative_mass) {
01576 
01577   relative_mass = new_relative_mass;
01578   adjust_next_update_age();
01579   update_wind_constant();
01580 
01581 }
01582 
01583 void single_star::lose_envelope_decent() {
01584 
01585   //  cerr << "single_star::lose_envelope_decent" << endl;
01586   //  dump(cerr, false);
01587   if (envelope_mass>0) {
01588     if (is_binary_component()) {
01589       get_binary()->adjust_binary_after_wind_loss(
01590                     this, envelope_mass, POST_AGB_TIME);
01591     } 
01592     else 
01593       reduce_mass(envelope_mass);
01594   }
01595 
01596   if (is_binary_component()) {
01597     get_companion()->set_effective_radius(get_companion()->get_radius());
01598     get_companion()->set_spec_type(Accreting, false);
01599   }
01600 }
01601 
01602 // wind_constant is fraction of envelope lost in lifetime
01603 // of stars. Should be updated after mass accretion
01604 // (SPZ+GN: 3 Oct 1998)
01605 void single_star::update_wind_constant() {
01606   
01607 #if 0
01608   if (relative_mass >= cnsts.parameters(massive_star_mass_limit))
01609     wind_constant = (get_relative_mass()-core_mass)
01610                   * cnsts.parameters(massive_star_envelope_fraction_lost);
01611   else 
01612     wind_constant = get_relative_mass()
01613                   * cnsts.parameters(non_massive_star_envelope_fraction_lost);
01614     
01615 #endif
01616 // (GN+SPZ Apr 28 1999) new fits to Maeder, de Koter and common sense
01617 
01618 //  cerr << "update_wind_constant"<<endl;
01619 
01620   if (relative_mass >= cnsts.parameters(super_giant2neutron_star)) {
01621 
01622     real meader_fit_dm = 0.01*pow(relative_mass,2.);
01623     
01624     if (relative_mass < 85)
01625       wind_constant = meader_fit_dm;
01626     else {// constant
01627       real final_mass = 43; // final mass after ms
01628       wind_constant = relative_mass - final_mass;
01629     }
01630 
01631   } 
01632   else { // no wind for low mass ms stars
01633     wind_constant = 0;
01634   }
01635 
01636   wind_constant = max(wind_constant, 0.0);
01637 
01638 
01639 }
01640 
01641 
01642 real single_star::potential_energy() {
01643   
01644      real GM2_R = cnsts.physics(G)*pow(cnsts.parameters(solar_mass), 2)
01645                 / cnsts.parameters(solar_radius);
01646      real p = GM2_R*get_total_mass()*get_total_mass()
01647             / get_effective_radius();
01648      
01649      return -p;
01650 }
01651 
01652 real single_star::kinetic_energy() {
01653   
01654      real Mkm_s2 = cnsts.parameters(solar_mass)
01655                  * pow(cnsts.physics(km_per_s), 2);
01656      real k = 0.5*Mkm_s2*get_total_mass()*pow(velocity, 2);
01657      
01658      return k;
01659 }
01660 
01661 real single_star::total_energy() {
01662      return kinetic_energy() + potential_energy();
01663 }
01664 
01665 real single_star::get_evolve_timestep() {
01666 
01667 // (GN+SPZ Apr 28 1999) was a bit too small
01668 //  return max(next_update_age - relative_age
01669 //           -0.5*cnsts.safety(minimum_timestep),
01670 //           cnsts.safety(minimum_timestep));
01671 
01672 // (GN+SPZ May  5 1999) type change time must be small because of rapid
01673 // growth of giants at end phase 0.0001 seems to be OK (?)
01674 //  return max(next_update_age - relative_age - (0.5*0.001), 0.001);
01675 
01676   return max(next_update_age - relative_age, 0.0001);
01677 
01678 }
01679 
01680 // Groenewegen & de Jong 1993, A&A 267,410 
01681 real single_star::final_core_mass() {
01682 
01683   if (maximum_luminosity() < 15725) {                     // Mc < 0.73
01684     return sqrt(maximum_luminosity()/47488. + 0.18) + 0.015;
01685   }
01686   else {
01687     // (SPZ+GN: 26 Jul 2000) was: pow(relative_mass,0.19), but makes
01688     //                       white dwarfs too massive.
01689     //                       see Nelemans, Y.PZ.V. 2000 A&A (submitted)
01690     return  0.46 + maximum_luminosity()/(46818*pow(relative_mass,0.25));
01691   }
01692 
01693 }

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