Main Page   Class Hierarchy   Data Structures   File List   Data Fields   Globals  

main_sequence.C

Go to the documentation of this file.
00001 //
00002 // main_sequence.C
00003 //
00004 // derived class of class star.
00005 // class main_sequence describes stellar evolution
00006 // for a main sequence star.
00007 // Class main_sequence will automatically create the following 
00008 // base classes: star, single star and starbase.
00009 
00010 #include "main_sequence.h"
00011 #include "brown_dwarf.h"
00012 #include "proto_star.h"
00013 
00014 // Default (empty) constructor in main_sequence.h
00015 
00016 #if 0
00017 void main_sequence::adjust_initial_star() {
00018   
00019   if(relative_age<=0)
00020     relative_age = max(current_time, 0.0);
00021 
00022   core_mass = main_sequence_core_mass();
00023   core_radius = main_sequence_core_radius();
00024   update_wind_constant();
00025   
00026   instantaneous_element();
00027 
00028   update();
00029 
00030 }
00031 #endif
00032 
00033 main_sequence::main_sequence(proto_star & p) : single_star(p) {
00034 
00035        delete &p; 
00036 
00037        last_update_age = 0;
00038        relative_age = 0;
00039        relative_mass = envelope_mass + core_mass;
00040        envelope_mass = relative_mass - 0.01;
00041        core_mass = 0.01;
00042 
00043        adjust_next_update_age();
00044        update_wind_constant();
00045 
00046        instantaneous_element();
00047        update();
00048 
00049        post_constructor();
00050 }
00051 
00052 void main_sequence::update() {
00053 
00054   // last update age is set after stellar expansion timescale is set.
00055 // (GN+SPZ May  4 1999) last_update_age now used as time of last type change
00056 //  last_update_age = relative_age;
00057 
00058   detect_spectral_features();
00059 
00060 }
00061 
00062 // wind_constant is fraction of envelope lost in nuclear lifetime
00063 // of stars. Should be updated after mass accretion
00064 // (SPZ+GN: 1 Oct 1998)
00065 void main_sequence::update_wind_constant() {
00066   
00067 #if 0
00068   if (relative_mass >= cnsts.parameters(massive_star_mass_limit)) {
00069 
00070     real m_core = 0.073 * (1 + cnsts.parameters(core_overshoot))
00071                         * pow(relative_mass, 1.42);
00072     m_core = min(m_core, cnsts.parameters(massive_star_mass_limit));
00073     
00074     // extra enhanced mass loss for stars with M>80 Msun.
00075     // to make low-mass compact objects. (SPZ+GN:24 Sep 1998)
00076     if (m_core>=35) {
00077       if (m_core<=55)
00078         m_core = 35 - 1.25 * (m_core -35); 
00079       else
00080         m_core = 10 + 0.75 * (m_core-55);
00081     }
00082     
00083     if (m_core>get_total_mass())
00084       m_core = get_total_mass();
00085 
00086     wind_constant = (get_relative_mass()-m_core)
00087                   * cnsts.parameters(massive_star_envelope_fraction_lost);
00088 
00089     cerr << "Main_sequence wind treatment for stars with M >= "
00090          << cnsts.parameters(massive_star_mass_limit)
00091          << " for " << identity << endl
00092          << "   M = " << get_total_mass() << " [Msun] "
00093          << "   Mdot = " << wind_constant
00094          << " t^" << cnsts.parameters(massive_star_mass_loss_law) 
00095          << " [Msun/Myr] "
00096          << endl;
00097   }
00098   else {
00099 
00100     wind_constant = relative_mass
00101                   * cnsts.parameters(non_massive_star_envelope_fraction_lost);
00102   }
00103 #endif
00104 
00105 // (GN+SPZ Apr 28 1999) new fits to Maeder, de Koter and common sense
00106 
00107   if (relative_mass >= cnsts.parameters(super_giant2neutron_star)) {
00108 
00109     real meader_fit_dm = 0.01*pow(relative_mass,2.);
00110     
00111     if (relative_mass < 85)
00112       wind_constant = meader_fit_dm;
00113     else {// constant
00114       real final_mass = 43 + (relative_mass-85); // final mass after ms
00115       wind_constant = relative_mass - final_mass;
00116     }
00117 
00118   } 
00119   else { // no wind for low mass ms stars
00120     wind_constant = 0;
00121   }
00122 
00123   wind_constant = max(wind_constant, 0.0);
00124 
00125 }
00126 
00127 // Adjust radius & luminosity at relative_age
00128 void main_sequence::instantaneous_element() {
00129 
00130     real alpha, beta, gamma, delta, kappa, lambda;
00131 
00132     real log_mass = log10(relative_mass);
00133 
00134     if (relative_mass > 1.334) {
00135 
00136         alpha = 0.1509 + 0.1709*log_mass;
00137         beta  = 0.06656 - 0.4805*log_mass;
00138         gamma = 0.007395 + 0.5083*log_mass;
00139         delta = (0.7388*pow(relative_mass, 1.679)
00140                          - 1.968*pow(relative_mass, 2.887))
00141                      / (1.0 - 1.821*pow(relative_mass, 2.337));
00142 
00143     } else {
00144       
00145         alpha = 0.08353 + 0.0565*log_mass;
00146         beta  = 0.01291 + 0.2226*log_mass;
00147         gamma = 0.1151 + 0.06267*log_mass;
00148         delta = pow(relative_mass, 1.25)
00149                         * (0.1148 + 0.8604*relative_mass*relative_mass)
00150                     / (0.04651 + relative_mass*relative_mass);
00151     }
00152 
00153     if (relative_mass < 1.334) {
00154         kappa  = 0.2594 + 0.1348*log_mass;
00155         lambda = 0.144 - 0.8333*log_mass;
00156     } else {
00157         kappa  = 0.092088 + 0.059338*log_mass;
00158         lambda = -0.05713 + log_mass*(0.3756 -0.1744*log_mass);
00159     }
00160         
00161     real ff    = relative_age/main_sequence_time();
00162     luminosity = base_main_sequence_luminosity()
00163       * pow(10., (ff*(ff*lambda + kappa)));
00164 
00165     radius = delta*pow(10., (ff*(ff*(ff*gamma + beta) + alpha)));
00166     effective_radius = max(effective_radius, radius);
00167 
00168 }
00169 
00170 // Evolve a main_sequence star upto time argument according to
00171 // the model described by Eggleton et al. 1989.
00172 void main_sequence::evolve_element(const real end_time) {
00173 
00174 // cerr << "void main_sequence::evolve_element(T="<<end_time<<")"<<endl;
00175 // cerr << identity<<" "<<luminosity<<" "<<radius<<endl;
00176 
00177     real alpha, beta, gamma, delta, kappa, lambda;
00178 
00179     real dt = end_time - current_time;
00180     current_time = end_time;
00181     relative_age += dt;
00182 
00183     real log_mass = log10(relative_mass);
00184 
00185     if (relative_mass > 1.334) {
00186 
00187         alpha = 0.1509 + 0.1709*log_mass;
00188         beta  = 0.06656 - 0.4805*log_mass;
00189         gamma = 0.007395 + 0.5083*log_mass;
00190         delta = (0.7388*pow(relative_mass, 1.679)
00191                          - 1.968*pow(relative_mass, 2.887))
00192                      / (1.0 - 1.821*pow(relative_mass, 2.337));
00193 
00194     } else if (relative_mass >= cnsts.parameters(minimum_main_sequence)) {
00195 
00196         alpha = 0.08353 + 0.0565*log_mass;
00197         beta  = 0.01291 + 0.2226*log_mass;
00198         gamma = 0.1151 + 0.06267*log_mass;
00199         delta = pow(relative_mass, 1.25)
00200                         * (0.1148 + 0.8604*relative_mass*relative_mass)
00201                     / (0.04651 + relative_mass*relative_mass);
00202 
00203     } else {
00204 
00205         // Main_sequence star will not ignite core hydrogen.
00206 
00207         star_transformation_story(Brown_Dwarf);
00208         new brown_dwarf(*this);
00209         return;
00210     }
00211 
00212     if (relative_mass < 1.334) {
00213         kappa  = 0.2594 + 0.1348*log_mass;
00214         lambda = 0.144 - 0.8333*log_mass;
00215     } else {
00216         kappa  = 0.092088 + 0.059338*log_mass;
00217         lambda = -0.05713 + log_mass*(0.3756 -0.1744*log_mass);
00218     }
00219         
00220     if (relative_age <= next_update_age) {
00221 
00222         real ff    = relative_age/main_sequence_time();
00223         luminosity = base_main_sequence_luminosity()
00224                         * pow(10., (ff*(ff*lambda + kappa)));
00225         radius     = delta*pow(10., (ff*(ff*(ff*gamma + beta) + alpha)));
00226 
00227         effective_radius = max(effective_radius, radius);
00228 
00229     } else {
00230 
00231         // Main sequence star's age exceeds hydrogen core burning
00232         // lifetime.
00233 
00234         if (relative_mass < cnsts.parameters(massive_star_mass_limit)) {
00235             star_transformation_story(Hertzsprung_Gap);
00236             new hertzsprung_gap(*this);
00237             return;
00238         } else {
00239             star_transformation_story(Hyper_Giant);
00240             new hyper_giant(*this);
00241             return;
00242         }
00243     }
00244 
00245     update();
00246     stellar_wind(dt);
00247 }
00248 
00249 real main_sequence::bolometric_correction()
00250 {
00251   // temperature() is defined in Kelvin.
00252   // here we should use old 10^3K implementation 
00253   // (SPZ+GN: 1 Oct 1998)
00254   real temp_in_kK = 0.001 * temperature();
00255 
00256   real bc;
00257   if (temp_in_kK < 4.452)
00258     bc = 2.5*log10((6.859e-6*pow(temp_in_kK,8) + 9.316e-3)
00259                    / (1. + 5.975e-10*pow(temp_in_kK,14)));
00260   else if (temp_in_kK < 10.84)
00261     bc = 2.5*log10((3.407e-2*pow(temp_in_kK,2.))
00262                    / (1. + 1.043e-4*pow(temp_in_kK, 4.5)));
00263   else
00264     bc = 2.5*log10((2728./pow(temp_in_kK, 3.5) 
00265                     + 1.878e-2*temp_in_kK)
00266                    / (1. + 5.362e-5*pow(temp_in_kK,3.5)));
00267 
00268   return bc;
00269 }
00270 
00271 // main_sequence stars do not have a compact core.
00272 // for convenience the core is set to a small value.
00273 real main_sequence::main_sequence_core_mass()
00274 {
00275     real m_core = 0.01;
00276     m_core = max(core_mass, m_core);
00277     if (m_core > get_total_mass()) m_core = get_total_mass();
00278    
00279     return m_core;
00280 }
00281 
00282 real main_sequence::main_sequence_core_radius()
00283 {
00284     return min(0.01, radius);
00285 }
00286 
00287 #if 0
00288 // add mass to accretor
00289 // is a separate function (see single_star.C) because of the variable
00290 // stellar wind. The wind_constant must be reset.
00291 real main_sequence::add_mass_to_accretor(const real mdot) {
00292 
00293   if (mdot<=0) {
00294     cerr << "main_sequence::add_mass_to_accretor(mdot=" << mdot << ")"<<endl;
00295     cerr << "mdot (" << mdot << ") smaller than zero!" << endl;
00296     cerr << "Action: No action!" << endl;
00297 
00298     return 0;
00299   }
00300  
00301     adjust_accretor_age(mdot);
00302     envelope_mass += mdot;
00303     accreted_mass += mdot;
00304     if (relative_mass<get_total_mass()) 
00305       relative_mass = get_total_mass();
00306 
00307     update_wind_constant();
00308     
00309     set_spec_type(Accreting);
00310   
00311     return mdot;
00312 }
00313 
00314 // Proper accretion routine.
00315 // inpended and consistent.
00316 
00317 real main_sequence::add_mass_to_accretor(real mdot, const real dt) {
00318   //    error checking is just for safety and debugging purposes.
00319   //cerr<<"real single_star::add_mass_to_accretor(mdot="<<mdot<<", dt="<<dt<<")"<<endl;
00320 
00321   if (mdot<0) {
00322     cerr << "single_star::add_mass_to_accretor(mdot=" << mdot 
00323          << ", dt=" << dt << ")"<<endl;
00324     cerr << "mdot (" << mdot << ") smaller than zero!" << endl;
00325     cerr << "Action: put mdot to zero!" << endl;
00326     return 0;
00327   }
00328 
00329   mdot = accretion_limit(mdot, dt);
00330   adjust_accretor_age(mdot);
00331   if (relative_mass<get_total_mass() + mdot) 
00332     relative_mass = get_total_mass() + mdot;
00333 
00334   update_wind_constant();
00335 
00336   envelope_mass += mdot;
00337   accreted_mass += mdot;
00338 
00339   adjust_accretor_radius(mdot, dt);
00340 
00341   set_spec_type(Accreting);
00342 
00343   //cerr<<relative_age<<" "<<next_update_age<<" "<<main_sequence_time()<<endl;
00344   //cerr<<"accretor radius adjusted "<<effective_radius<<endl;
00345 
00346   //cerr<<"leave add_mass"<<endl;
00347   
00348   return mdot;
00349 }
00350 #endif
00351 
00352 // used for RLOF
00353 star* main_sequence::subtrac_mass_from_donor(const real dt, real& mdot)
00354 {
00355   //  cerr << " main_sequence::subtrac_mass_from_donor"<<endl;
00356 
00357   mdot = relative_mass*dt/get_binary()->get_donor_timescale();
00358 
00359   mdot = mass_ratio_mdot_limit(mdot);
00360 
00361   if (envelope_mass <= mdot) {
00362     mdot = envelope_mass;
00363     envelope_mass = 0;
00364     star_transformation_story(Helium_Star);
00365     return dynamic_cast(star*, new helium_star(*this));
00366   }
00367 
00368   if (low_mass_star()) { // only when mass transfer timescale = nuc?
00369     // after mass is subtracted star becomes lower mass star
00370     // (SPZ+GN:24 Sep 1998)
00371     adjust_donor_age(mdot);
00372     update_relative_mass(relative_mass-mdot);
00373   }
00374 
00375   adjust_donor_radius(mdot);
00376     
00377   envelope_mass -= mdot;
00378   return this;
00379   
00380 }
00381 
00382 star* main_sequence::merge_elements(star* str) {
00383 
00384       star* merged_star = this;
00385 
00386       add_mass_to_core(str->get_core_mass());
00387 
00388       //core_mass += str->get_core_mass();
00389       //if (relative_mass<get_total_mass())
00390       //   update_relative_mass(get_total_mass());
00391 
00392       if (str->get_envelope_mass()>0) 
00393          add_mass_to_accretor(str->get_envelope_mass());
00394 
00395       spec_type[Merger]=Merger;
00396 
00397       switch(str->get_element_type()) {
00398          case Hyper_Giant:
00399          case Hertzsprung_Gap:  
00400          case Sub_Giant:        
00401          case Horizontal_Branch: 
00402          case Super_Giant: 
00403          case Carbon_Star: 
00404          case Helium_Star: 
00405          case Helium_Giant: 
00406          case Carbon_Dwarf: 
00407          case Oxygen_Dwarf:
00408          case Helium_Dwarf: 
00409               if (relative_mass <
00410                   cnsts.parameters(massive_star_mass_limit)) {
00411                 star_transformation_story(Hertzsprung_Gap);
00412 
00413                 // (GN+SPZ May  4 1999) should return now
00414                 //  merged_star = dynamic_cast(star*, 
00415                 //  new hertzsprung_gap(*this));
00416                 //  dump(cerr, false);
00417 
00418                 // Chose relative_age to be next update age!
00419                 // otherwise sub_giants become unhappy.
00420 cerr << "Merge MS+wd"<<endl;            
00421 PRC(relative_age);PRC(next_update_age);
00422 //              relative_age = next_update_age;
00423                 
00424                 return dynamic_cast(star*, new hertzsprung_gap(*this));
00425               }
00426               else {
00427                 star_transformation_story(Hyper_Giant);
00428                 //  merged_star = dynamic_cast(star*, 
00429                 //  new wolf_rayet(*this));
00430                 return dynamic_cast(star*, new hyper_giant(*this));
00431               }
00432          case Thorn_Zytkow :
00433          case Xray_Pulsar:
00434          case Radio_Pulsar:
00435          case Neutron_Star :
00436          case Black_Hole   : 
00437               star_transformation_story(Thorn_Zytkow);
00438               // merged_star = dynamic_cast(star*, 
00439               // new thorne_zytkow(*this));
00440               return dynamic_cast(star*, new thorne_zytkow(*this));
00441               default:     instantaneous_element();
00442       }
00443       
00444       return merged_star;
00445 
00446    }
00447            
00448 // Star is rejuvenated by accretion.
00449 void main_sequence::adjust_accretor_age(const real mdot,
00450                                         const bool rejuvenate=true) {
00451     
00452   //  cerr << "main_sequence::adjust_accretor_age(mdot = " << mdot<<")"<<endl;
00453   
00454       real m_rel_new;
00455       real m_tot_new = get_total_mass() + mdot;
00456       if (m_tot_new>relative_mass)
00457          m_rel_new = m_tot_new;
00458       else m_rel_new = relative_mass;
00459 
00460       real t_ms_old = main_sequence_time();
00461       real t_ms_new = main_sequence_time(m_rel_new);
00462 
00463       relative_age *= (t_ms_new/t_ms_old);
00464       if (rejuvenate)
00465          relative_age *= rejuvenation_fraction(mdot/m_tot_new); 
00466     
00467       // next_update_age should not be reset here,
00468       // is done in add_mass_to_accretor, where also relative_mass
00469       // is updated (SPZ+GN: 1 Oct 1998)
00470       // next_update_age = t_ms_new; 
00471 
00472    }
00473 
00474 // Low-mass main-sequence donor lifetimes are expanded by
00475 // reducing relative_mass
00476 // (SPZ+GN:25 Sep 1998)
00477 void main_sequence::adjust_donor_age(const real mdot) { 
00478 
00479       real m_rel_new = get_relative_mass() - mdot;
00480 
00481       relative_age *= main_sequence_time(m_rel_new)
00482                     / main_sequence_time();
00483 
00484 }
00485 
00486 
00487 // Adiabatic responce function for main_sequence star.
00488 // Used for determining mass_transfer_timescale.
00489 // Increasing zeta stabilizes binary.
00490 real main_sequence::zeta_adiabatic() {
00491 
00492       real z;
00493 
00494       if (get_relative_mass()<=0.4)         // convective envelope
00495         z = -cnsts.mathematics(one_third);
00496       else if(low_mass_star()) {
00497         z = 2; // was 0.55 but this causes cv's to transfer on a dynamicall
00498                // timescale where aml-driven is expected.
00499       }
00500       else if(medium_mass_star()) {
00501         z = 4; // Eggleton's book 
00502       } 
00503       else
00504         z = 4; // somewhare between -100 and 100?
00505 
00506       return z;
00507    }
00508 
00509 // Thermal responce function for main_sequence star.
00510 // Used for determining mass_transfer_timescale.
00511 // (SPZ+GN: 1 Oct 1998)
00512 real main_sequence::zeta_thermal() {
00513 
00514       real z = -1;
00515 
00516       if (get_relative_mass()<=0.4)
00517          z = 0;                         // Unknown
00518       else if (low_mass_star())
00519         z = 0.9;                        // Pols & Marinus 1995
00520                                         // (GN+SPZ Apr 29 1999) was -0.5
00521       else 
00522         z = 0.55;                       //  (GN+SPZ Apr 29 1999) was -1
00523 
00524       return z;
00525    }
00526 
00527 star* main_sequence::reduce_mass(const real mdot) {
00528 
00529       if (envelope_mass<=mdot) {
00530          envelope_mass = 0;
00531          star_transformation_story(Helium_Star);
00532          return dynamic_cast(star*, new helium_star(*this));
00533       }
00534 
00535       envelope_mass -= mdot;
00536       return this;
00537    }
00538 
00539 void main_sequence::adjust_next_update_age() {
00540 
00541 // (GN+SPZ May  4 1999) last update age is time of previous type change
00542       last_update_age = 0;
00543       next_update_age = main_sequence_time();
00544    }
00545 
00546 void main_sequence::detect_spectral_features() {
00547 
00548       single_star::detect_spectral_features();
00549 
00550       if (accreted_mass>=cnsts.parameters(B_emission_star_mass_limit))
00551         spec_type[Emission]=Emission;
00552       if (get_relative_mass() > turn_off_mass(current_time)
00553                            * (1+cnsts.parameters(Blue_straggler_mass_limit)))
00554         spec_type[Blue_Straggler]=Blue_Straggler;
00555    }
00556 
00557 #if 0
00558 real main_sequence::stellar_radius(const real mass, const real age) {
00559 
00560       real alpha, beta, gamma, delta, kappa, lambda;
00561 
00562       real log_mass = log10(mass);
00563 
00564       if (mass>1.334) {
00565          alpha = 0.1509 + 0.1709*log_mass;
00566          beta  = 0.06656 - 0.4805*log_mass;
00567          gamma = 0.007395 + 0.5083*log_mass;
00568          delta = (0.7388*pow(mass, 1.679)
00569                - 1.968*pow(mass, 2.887))
00570                / (1.0 - 1.821*pow(mass, 2.337));
00571       }
00572       else {
00573          alpha = 0.08353 + 0.0565*log_mass;
00574          beta  = 0.01291 + 0.2226*log_mass;
00575          gamma = 0.1151 + 0.06267*log_mass;
00576          delta = pow(mass, 1.25)
00577                * (0.1148 + 0.8604*mass*mass)
00578                / (0.04651 + mass*mass);
00579       }
00580 
00581       if (mass<1.334) {
00582          kappa  = 0.2594 + 0.1348*log_mass;
00583          lambda = 0.144 - 0.8333*log_mass;
00584       }
00585       else {
00586          kappa  = 0.092088 + 0.059338*log_mass;
00587          lambda = -0.05713 + log_mass*(0.3756 -0.1744);
00588       }
00589 
00590       real t_ms = main_sequence_time(mass);
00591       real ff    = age/t_ms;
00592       real r_ms  = delta*pow(10., (ff*(ff*(ff*gamma + beta) + alpha)));
00593 
00594       return r_ms;
00595    }
00596 #endif
00597 
00598 // Fit to Claret & Gimenez 1990, ApSS 196,215, (SPZ+GN:24 Sep 1998)
00599 real main_sequence::gyration_radius_sq() {
00600 
00601   real m = get_total_mass();
00602 
00603   // gravitational acceleration at surface.
00604   real g = cnsts.physics(G)
00605          * m*cnsts.parameters(solar_mass)
00606          / pow(get_effective_radius() * cnsts.parameters(solar_radius), 2);
00607 
00608   // constant part
00609   real A = -1.5;
00610   real B = 0.2;
00611   
00612   // linear interpolation
00613   if (low_mass_star()) {
00614     A = -3.8 + 1.8*m;
00615     B = 0.77 - 0.44*m;
00616   }
00617 
00618   real k = pow(10., (A + B*log10(g)));
00619 
00620   return k*k;
00621 
00622 }
00623 
00624 real main_sequence::nucleair_evolution_timescale() {
00625   // t_nuc = 10^10 [years] Msun/Lsun.
00626   // Assumed that 0.1 Msun is thermalized.
00627 
00628   real fused_mass = 0.1*relative_mass;
00629 
00630   return cnsts.parameters(energy_to_mass_in_internal_units)
00631        * fused_mass/luminosity;
00632 }
00633 
00634 
00635 
00636 
00637 
00638 
00639 
00640 
00641 
00642 
00643 
00644 

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