Main Page   Class Hierarchy   Data Structures   File List   Data Fields   Globals  

coagulation.C

Go to the documentation of this file.
00001 //  coagulation.C: SPZ:May 1998
00002 //                 the dynamical evolution of the mass spectrum is computed 
00003 //                 due to collisional evolution in a semi-analytic
00004 //                 fashion.
00005 //                 In first instance only a single step is performed
00006 //                 with time T 
00007 
00008 #include "dyn.h"
00009 
00010 #ifdef TOOLBOX
00011 
00012 // cerr << "    [R]: " << Rsun_pc / r_conv_star_to_dyn << " pc\n";
00013 
00014 #define Rsun_pc 2.255e-8                 // R_sun/parsec = 6.960e+10/3.086e+18
00015 
00016 
00017 #define ALL_i ni = n->get_oldest_daughter(); ni != NULL; \
00018                                              ni = ni->get_younger_sister()
00019 #define j_ABOVE_i nj = ni->get_younger_sister(); nj != NULL; \
00020                                              nj = nj->get_younger_sister()
00021 
00022 
00023 local real conv_v_dyn_to_star(real v, real rf, real tf) {
00024 
00025 //              Internal velocity is km/s
00026 //              Internal size is solar raii
00027 //              Internal time is Myr.
00028 //              km/s to Rsun/Myr
00029 //      real to_Rsun_Myr = cnsts.physics(km_per_s) * cnsts.physics(Myear)
00030 //                     / cnsts.parameters(solar_radius);
00031 
00032       real myear = 3.15e+13;
00033       real km_s = 1.0e+5;
00034       real R_sun = 6.960e+10;
00035       real to_Rsun_Myr = km_s * myear / R_sun;
00036       real to_dyn      = rf/tf;
00037       
00038       return v/(to_Rsun_Myr * to_dyn);
00039    }
00040 
00041 
00042 typedef  struct
00043 {
00044     real  radius;
00045     real  mass;
00046 } rm_pair, *rm_pair_ptr;
00047 
00048 //-----------------------------------------------------------------------------
00049 //  compare_radii  --  compare the radii of two particles
00050 //-----------------------------------------------------------------------------
00051 
00052 local int compare_radii(const void * pi, const void * pj)
00053 {
00054     if (((rm_pair_ptr) pi)->radius > ((rm_pair_ptr) pj)->radius)
00055         return(1);
00056     else if (((rm_pair_ptr)pi)->radius < ((rm_pair_ptr)pj)->radius)
00057         return(-1);
00058     else
00059         return(0);
00060 }
00061 
00062 //-----------------------------------------------------------------------------
00063 //  compute_general_mass_radii  --  Get the massradii for all particles.
00064 //-----------------------------------------------------------------------------
00065 
00066 static real nonlin_masses[9] = {0.005, 0.01, 0.02, 0.05, 0.1,
00067                                 0.25, 0.5, 0.75, 0.9};
00068 
00069 local void compute_general_mass_radii(dyn * b, vector dc_pos, int nzones,
00070                                       real r_lagr[],
00071                                       real m_cutoff, real M_cutoff,
00072                                       bool nonlin = false, 
00073                                       boolfn bf=NULL)
00074 {
00075     if (nzones < 2) return;
00076     if (nonlin && nzones != 10) return;         // Special case
00077 
00078     // Note: nzones specifies the number of radial zones to consider.
00079     //       However, we only store radii corresponding to the nzones-1 
00080     //       interior zone boundaries.
00081 
00082     real* mass_percent = new real[nzones-1];
00083     if (mass_percent == NULL) {
00084         cerr << "compute_general_mass_radii: "
00085              << "not enough memory left for mass_percent\n";
00086         return;
00087     }
00088 
00089     int n = 0;
00090     if (bf == NULL) {
00091       for_all_daughters(dyn, b, bb)
00092         if (bb->get_mass()>=m_cutoff && bb->get_mass()<=M_cutoff)
00093           n++;
00094     }
00095     else {
00096         for_all_daughters(dyn, b, bb)
00097           if (bb->get_mass()>=m_cutoff && bb->get_mass()<=M_cutoff)
00098             if ((*bf)(bb))
00099               n++;
00100     }
00101 
00102     rm_pair_ptr rm_table = new rm_pair[n];
00103 
00104     if (rm_table == NULL) {
00105         cerr << "compute_general_mass_radii: "
00106              << "not enough memory left for rm_table\n" << flush;
00107         return;
00108     }
00109 
00110     // Use the geometric center if the density center is unknown.
00111 
00112     //vector dc_pos = 0;
00113     //if (find_qmatch(b->get_dyn_story(), "density_center_pos")) 
00114     //dc_pos = getvq(b->get_dyn_story(), "density_center_pos");
00115 
00116     // Set up an array of (radius, mass) pairs.  Also find the total
00117     // mass of all nodes under consideration.
00118 
00119     real total_mass = 0;
00120 
00121     int i = 0;
00122     for_all_daughters(dyn, b, bi) {
00123       if (bf == NULL || (*bf)(bi)) {
00124         if (bi->get_mass()>=m_cutoff && bi->get_mass()<=M_cutoff) {
00125           total_mass += bi->get_mass();
00126           rm_table[i].radius = abs(bi->get_pos() - dc_pos);
00127           rm_table[i].mass = bi->get_mass();
00128           i++;
00129 //          PRL(i);
00130         }
00131       }
00132     }   
00133 
00134     // Sort the array by radius.
00135 
00136     qsort((void *)rm_table, (size_t)n, sizeof(rm_pair), compare_radii);
00137 
00138     // Determine Lagrangian radii.
00139 
00140     //    cerr << "Determine Lagrangian radii" << endl;
00141     int k;
00142     for (k = 0; k < nzones-1; k++) {
00143         if (!nonlin) 
00144             mass_percent[k] = ((k + 1) / (real)nzones) * total_mass;
00145         else
00146             mass_percent[k] = nonlin_masses[k] * total_mass;
00147     }
00148 
00149     //    real *rlagr = new real[nzones-1];
00150     real cumulative_mass = 0.0;
00151     i = 0;
00152 
00153 
00154     for (k = 0; k < nzones-1; k++) {
00155 
00156       while (cumulative_mass < mass_percent[k]) {
00157         cumulative_mass += rm_table[i++].mass;
00158       }
00159 
00160       r_lagr[k] = rm_table[i-1].radius;
00161     }
00162 
00163 
00164     // Place the data in the root dyn story.
00165 
00166 #if 0
00167     if (bf == NULL)
00168         putiq(b->get_dyn_story(), "boolfn", 0);
00169     else
00170         putiq(b->get_dyn_story(), "boolfn", 1);
00171 
00172     putiq(b->get_dyn_story(), "n_nodes", n);
00173 
00174     putiq(b->get_dyn_story(), "n_lagr", nzones-1);
00175     putra(b->get_dyn_story(), "r_lagr", rlagr, nzones-1);
00176 #endif
00177 
00178     delete mass_percent;
00179     delete rm_table;
00180 //    delete rlagr;
00181     
00182     for (k = 0; k < nzones-1; k ++) 
00183       cerr << " " << b->get_starbase()->conv_r_dyn_to_star(r_lagr[k])
00184                      * Rsun_pc;
00185     cerr << " [pc]" << endl;
00186     
00187 }
00188 
00189 // Convenient synonyms:
00190 
00191 local void  compute_mass_radii_quartiles(dyn * b, vector dc_pos,
00192                                          real m_cutoff, real M_cutoff)
00193 {
00194   int nl = 4;
00195   real *r_lagr = new real[nl-1];
00196   for (int i=0; i<nl-1; i++)
00197     r_lagr[i] = 0;
00198 
00199     compute_general_mass_radii(b, dc_pos, nl, r_lagr, m_cutoff, M_cutoff);
00200 }
00201 
00202 local void  compute_mass_radii_percentiles(dyn * b, vector dc_pos,
00203                                            real m_cutoff, real M_cutoff)
00204 {
00205   int nl = 10;
00206   real *r_lagr = new real[nl-1];
00207   for (int i=0; i<nl-1; i++)
00208     r_lagr[i] = 0;
00209   
00210     compute_general_mass_radii(b, dc_pos, nl, r_lagr, m_cutoff, M_cutoff);
00211 }
00212 
00213 local bool single_fn(dyn * b)
00214 {
00215 
00216   //  int test = getiq(b->get_log_story(), "mass_doubled");
00217   //  PRL(test);
00218   if (getiq(b->get_log_story(), "mass_doubled") == 0 )
00219     return true;
00220   else
00221     return false;
00222 }
00223 
00224 local bool double_fn(dyn * b)
00225 {
00226   if (getiq(b->get_log_story(), "mass_doubled") == 1 )
00227     return true;
00228   else
00229     return false;
00230 }  
00231 
00232 local void print_lagrangian_radii(dyn* b, vector dc_pos, int which_lagr,
00233                                   real m_cutoff, real M_cutoff,
00234                                   int which = 0)
00235 {
00236     bool nonlin = false;
00237 
00238     int nl=0, indent=0;
00239     if (which_lagr == 0) {
00240         nl = 4;
00241         indent = 15;
00242         PRI(4); cerr << "quartiles: ";
00243     } else if (which_lagr == 1) {
00244         nl = 10;
00245         indent = 20;
00246         PRI(4); cerr << "10-percentiles: ";
00247     } else {
00248         nl = 10;
00249         indent = 26;
00250         PRI(4); cerr << "selected percentiles: ";
00251         nonlin = true;
00252     }
00253     
00254     //cerr << "before testnode call" << endl;
00255     //    if (which != 2 || 3) compute_general_mass_radii(b, nl, nonlin, testnode);
00256 
00257     real* r_lagr = new real[nl-1];
00258     if (r_lagr==NULL) {
00259       cerr << "print_lagrangian_radii not enough memory to allocate "
00260            << "r_lagr[" << nl-1<< "]" << endl;
00261       return;
00262     }
00263     for (int i=0; i<nl-1; i++)
00264       r_lagr[i] = 0;
00265     
00266     if (which == 0) compute_general_mass_radii(b, dc_pos, nl, r_lagr,
00267                                                m_cutoff, M_cutoff, nonlin); 
00268 
00269     //    cerr << "before single_fn call" << endl;
00270     //    PRL(which);
00271     if (which == 2) compute_general_mass_radii(b, dc_pos, nl, r_lagr,
00272                                                m_cutoff, M_cutoff, nonlin, single_fn);
00273 
00274     //     cerr << "before double_fn call" << endl;
00275     //    PRL(which);
00276     if (which == 3) compute_general_mass_radii(b, dc_pos, nl, r_lagr,
00277                                                m_cutoff, M_cutoff, nonlin, double_fn);
00278 
00279     //    PRC(dc_pos);PRC(m_cutoff);PRC(M_cutoff);PRL(which);
00280 
00281     //for (int k = 0; k < nl; k ++) 
00282     // cerr << " " << r_lagr[k];
00283     //cerr <<endl;
00284 
00285 #if 0
00286     if (find_qmatch(b->get_dyn_story(), "n_lagr")) {
00287         int n_lagr = getiq(b->get_dyn_story(), "n_lagr");
00288         getra(b->get_dyn_story(), "r_lagr", r_lagr, n_lagr);
00289 
00290         for (int k = 0; k < n_lagr; k += 5) {
00291           if (k > 0) {
00292             cerr << endl;
00293             for (int kk = 0; kk < indent; kk++) cerr << " ";
00294           }
00295           for (int i = k; i < k+5 && i < n_lagr; i++)
00296             cerr << " " << r_lagr[i];
00297         }
00298         cerr << endl;
00299     }
00300 #endif
00301     
00302     delete r_lagr;
00303 }
00304 
00305 /*-----------------------------------------------------------------------------
00306  *  compute_density  --  Get the density for all particles.
00307  *               note:
00308  *                    the neighbor_dist_sq[q] array will contain the distances
00309  *                    to the q-th nearest neighbor (in the form of the squares 
00310  *                    thereof); therefore  neighbor_dist_sq[0] = 0.0  since
00311  *                    this indicates the distance of a particle to itself.
00312  *                    Including this trivial case simplifies the algorithm
00313  *                    below by making it more homogeneous.
00314  *-----------------------------------------------------------------------------
00315  *              Litt.:
00316  *                    Stefano Casertano and Piet Hut: Astroph.J. 298,80 (1985).
00317  *                    To use their recipe, k >= 2 is required.
00318  *-----------------------------------------------------------------------------
00319  */
00320 local void  compute_density(dyn * b,    /* pointer to an Nbody system */
00321                             int k,      /* use kth nearest neighbor */
00322                             int n,
00323                             real local_density[],
00324                             real m_cutoff,
00325                             real M_cutoff)
00326 {
00327     int  q, r, is = 0;
00328     real *neighbor_dist_sq;
00329     real  volume;
00330     real  delr_sq;
00331     
00332     if (k >= n)                           /* no k-th nearest neighbor exists */
00333         cerr << "compute_density: k = " << k << " >= n = " << n << endl;
00334     if (k <= 1)
00335         cerr << "compute_density: k = " << k << " <= 1" << endl;
00336 
00337     neighbor_dist_sq = new real[k+1];
00338 
00339     //  for_all_leaves(dyn, b, d)               // The density is now defined
00340     for_all_daughters(dyn, b, d)        // ONLY for top-level nodes.
00341       if (d->get_mass()>=m_cutoff && d->get_mass()<=M_cutoff)
00342         {
00343         neighbor_dist_sq[0] = 0.0;
00344         for (q = 1; q <= k; q++)
00345             neighbor_dist_sq[q] = VERY_LARGE_NUMBER;
00346 
00347         //      for_all_leaves(dyn, b, dd)
00348         for_all_daughters(dyn, b, dd)
00349           if (dd->get_mass()>=m_cutoff && dd->get_mass()<=M_cutoff)
00350             {
00351             if (d == dd)
00352                 continue;
00353 
00354             delr_sq = square(something_relative_to_root(d, &dyn::get_pos)
00355                              - something_relative_to_root(dd, &dyn::get_pos));
00356 
00357             if (delr_sq < neighbor_dist_sq[k])
00358                 for (q = k-1; q >= 0; q--)
00359                     {
00360                     if (delr_sq > neighbor_dist_sq[q])
00361                         {
00362                         for (r = k; r > q+1; r--)
00363                             neighbor_dist_sq[r] = neighbor_dist_sq[r-1];
00364                         neighbor_dist_sq[q+1] = delr_sq;
00365                         break;
00366                         }
00367                     }
00368             }
00369             
00370         volume = (4.0/3.0) * PI * pow(neighbor_dist_sq[k], 1.5);
00371 
00372         real density =  (k - 1) / volume;           /* Ap. J. 298, 80 (1985) */
00373         story * s = d->get_dyn_story();
00374         //        putiq(s, "density_k_level", k);
00375         //        putrq(s, "density", density);
00376         local_density[is] = density;
00377         is++;
00378         }
00379 
00380     delete neighbor_dist_sq;
00381 }
00382 
00383 
00384 
00385 /*-----------------------------------------------------------------------------
00386  *  compute_mean_cod -- Returns the position and velocity of the density
00387  *                      center of an N-body system.
00388  *-----------------------------------------------------------------------------
00389  */
00390 local void compute_mean_cod(dyn *b,
00391                             real local_density[],
00392                             vector& pos, vector& vel, real m_cutoff,
00393                             real M_cutoff)
00394 {
00395     real total_weight = 0;
00396     pos = 0;
00397     vel = 0;
00398     int is=0;
00399     
00400     for_all_daughters(dyn, b, d) 
00401       if (d->get_mass()>=m_cutoff && d->get_mass()<=M_cutoff) {
00402             
00403         //      real density = getrq(d->get_dyn_story(), "density");
00404         real density = local_density[is++];
00405         real dens2 = density * density;        // weight factor
00406 
00407         total_weight += dens2;
00408         pos += dens2 * d->get_pos();
00409         vel += dens2 * d->get_vel();
00410     }   
00411 
00412     pos /= total_weight;
00413     vel /= total_weight;
00414 }
00415 
00416 /*===========================================================================*/
00417 
00418 local void compute_core_parameters(dyn* b, int k, vector& center,
00419                                    real& rcore, int& ncore, real& mcore,
00420                                    real & vcore, int n,
00421                                    real local_density[], 
00422                                    real m_cutoff, real M_cutoff)
00423 {
00424     vector vel;
00425     int is=0;
00426 
00427     real rcore2 = 0;
00428     if (rcore<=0) {
00429       compute_density(b, k, n, local_density, m_cutoff, M_cutoff);
00430       compute_mean_cod(b, local_density, center, vel, m_cutoff, M_cutoff);
00431 
00432       real total_weight = 0;
00433       real sum = 0;
00434       for_all_daughters(dyn, b, bi) 
00435         if (bi->get_mass()>=m_cutoff && bi->get_mass()<=M_cutoff) {
00436           real density = local_density[is++];
00437           real dens2 = density * density;        // weight factor
00438           //real density = getrq(bi->get_dyn_story(), "density");
00439           //real dens2 = density * density;              // weight factor
00440 
00441           total_weight += dens2;
00442           sum += dens2 * square(bi->get_pos() - center);
00443         }
00444 
00445       rcore2 = sum/total_weight;
00446       rcore = sqrt(rcore2);
00447     }
00448     else
00449       rcore2 = square(rcore);
00450 
00451     ncore = 0;
00452     mcore = 0;
00453     vcore = 0;
00454 
00455     for_all_daughters(dyn, b, bj)
00456       if (bj->get_mass()>=m_cutoff && bj->get_mass()<=M_cutoff) 
00457         if (square(bj->get_pos() - center) <= rcore2) {
00458             ncore++;
00459             mcore += bj->get_mass();
00460             vcore += bj->get_vel()*bj->get_vel();
00461         }
00462     mcore = mcore/(1.0*ncore);
00463     vcore = sqrt(vcore)/(1.0*ncore);
00464 }
00465 
00466 local void print_core_parameters(dyn* b, vector& density_center, real& rcore,
00467                                  int & ncore, real & vcore,
00468                                  int n, real local_density[],
00469                                  real m_cutoff, real M_cutoff,
00470                                  bool verbose)
00471   {
00472     real mcore;
00473 
00474     compute_core_parameters(b, 6, density_center, rcore, ncore, mcore,
00475                             vcore, n, local_density,
00476                             m_cutoff, M_cutoff);
00477 
00478     real r_density_center = sqrt(density_center*density_center);
00479 
00480     vcore = conv_v_dyn_to_star(vcore,
00481                                b->get_starbase()->conv_r_star_to_dyn(1),
00482                                b->get_starbase()->conv_t_star_to_dyn(1));
00483     if (verbose) {
00484 
00485       real M_lower = b->get_starbase()->conv_m_dyn_to_star(m_cutoff);
00486       real M_upper = b->get_starbase()->conv_m_dyn_to_star(M_cutoff);
00487 
00488       cerr << "n = " << n << ", M (lower/upper) = ( "
00489                           << M_lower << ",  " << M_upper << " ) [Msun]\n";
00490       cerr << "     Core: (N, R, m, v) = ( " << ncore << ", "
00491            << Rsun_pc * b->get_starbase()->conv_r_dyn_to_star(rcore)
00492            << ", "  
00493            << b->get_starbase()->conv_m_dyn_to_star(mcore) <<", "
00494            << vcore
00495            << " ) [solar/km/s]\n";
00496       cerr << "     R_to_density_center = "
00497            << Rsun_pc *
00498               b->get_starbase()->conv_r_dyn_to_star(r_density_center)
00499            << " [pc]\n";
00500       
00501 
00502       /*
00503       //place the data in the root dyn-story.
00504       putiq(b->get_dyn_story(), "n_cutoff", n);
00505       putrq(b->get_dyn_story(), "m_cutoff", m_cutoff);
00506       putrq(b->get_dyn_story(), "M_cutoff", M_cutoff);
00507       putvq(b->get_dyn_story(), "density_center_pos", density_center);
00508       putrq(b->get_dyn_story(), "core_radius", rcore);
00509       putiq(b->get_dyn_story(), "n_core", ncore);
00510       putrq(b->get_dyn_story(), "m_core", mcore);
00511       */
00512     }
00513     else {
00514               PRC(n); PRC(m_cutoff); PRL(M_cutoff);
00515       PRI(4); PRC(rcore); PRC(ncore); PRL(mcore);
00516       PRI(4); PRL(r_density_center);
00517     }
00518         
00519 }
00520 
00521 local real system_energy(dyn* b, real m_cutoff, real M_cutoff)
00522 {
00523     real kin = 0;
00524     for_all_leaves(dyn, b, bj)
00525       if (bj->get_mass()>=m_cutoff && bj->get_mass()<=M_cutoff)
00526         kin += bj->get_mass()
00527              * square(something_relative_to_root(bj, &dyn::get_vel));
00528     kin *= 0.5;
00529 
00530     real pot = 0.0;
00531     for_all_leaves(dyn, b, bi) 
00532       if (bi->get_mass()>=m_cutoff && bi->get_mass()<=M_cutoff) {
00533         real dpot = 0.0;
00534         for_all_leaves(dyn, b, bj) 
00535           if (bj->get_mass()>=m_cutoff && bj->get_mass()<=M_cutoff) {
00536             if (bj == bi) break;
00537             vector dx = something_relative_to_root(bi, &dyn::get_pos)
00538                           - something_relative_to_root(bj, &dyn::get_pos);
00539             dpot += bj->get_mass() / abs(dx);
00540         }
00541         pot -= bi->get_mass() * dpot;
00542     }
00543 
00544     return kin + pot;
00545 }
00546 
00547 local void get_energies(dyn * n, real eps2, 
00548                   real& kinetic_energy, real& potential_energy,
00549                   real m_cutoff, real M_cutoff)
00550 {
00551     dyn  * ni, *nj;
00552 
00553     kinetic_energy = 0;
00554     for (ALL_i) 
00555       if (ni->get_mass()>=m_cutoff && ni->get_mass()<=M_cutoff) {
00556       
00557         vector v = ni->get_vel();
00558         kinetic_energy += ni->get_mass() * v * v;
00559     }
00560     kinetic_energy *= 0.5;
00561 
00562     potential_energy = 0;
00563     for (ALL_i) 
00564       if (ni->get_mass()>=m_cutoff && ni->get_mass()<=M_cutoff) {
00565         real dphi = 0;
00566         vector xi = ni->get_pos();
00567         for (j_ABOVE_i) 
00568           if (nj->get_mass()>=m_cutoff && nj->get_mass()<=M_cutoff) {
00569             vector xij = nj->get_pos() - xi;
00570             dphi += nj->get_mass()/sqrt(xij*xij + eps2);
00571         }
00572         potential_energy -= ni->get_mass() * dphi;
00573     }
00574 }
00575 
00576 
00577 local void print_energies(dyn* b, real& kT, real m_cutoff, real M_cutoff, bool verbose)
00578 {
00579     // Energies (top-level nodes):
00580 
00581     real kinetic_energy, potential_energy;
00582     get_energies(b, 0.0, kinetic_energy, potential_energy, m_cutoff, M_cutoff);
00583 
00584     real total_energy = kinetic_energy + potential_energy;
00585     real virial_ratio = -kinetic_energy / potential_energy;
00586     kT = -total_energy / (1.5*b->n_daughters());
00587 
00588     if (verbose) {
00589       PRI(4); cerr << "top-level nodes:\n";
00590       PRI(8); PRC(kinetic_energy); PRL(potential_energy);
00591       PRI(8); PRC(total_energy); PRC(kT); PRL(virial_ratio);
00592 
00593       PRI(4); cerr << "total energy (full system) = "
00594                    << system_energy(b, m_cutoff, M_cutoff) << endl;
00595     }
00596     else
00597       cerr <<"\t"<< kinetic_energy <<" "<< potential_energy
00598            <<" "<< total_energy <<" "<< kT
00599            <<" "<< virial_ratio <<" "<< system_energy(b, m_cutoff, M_cutoff) << endl;
00600 }
00601 
00602 local void print_relaxation_time(dyn* b, real m_cutoff, real M_cutoff, bool verbose)
00603 {
00604     // Print the relaxation time
00605 
00606     real potential_energy, kinetic_energy;
00607     real r_virial, t_relax;
00608     real total_mass = 0;
00609 
00610     int n=0;
00611     for_all_leaves(dyn, b, bj) 
00612       if (bj->get_mass()>=m_cutoff && bj->get_mass()<=M_cutoff) {
00613         n++;
00614         total_mass += bj->get_mass();
00615     }
00616 
00617     get_energies(b, 0.0, kinetic_energy, potential_energy, m_cutoff, M_cutoff);
00618 
00619     r_virial = -0.5 * total_mass * total_mass / potential_energy;
00620 
00621     t_relax = 9.62e-2 * sqrt(r_virial * r_virial * r_virial / total_mass)
00622               * n / log10(0.4 * n);
00623 
00624     if (verbose) {
00625       PRI(4); cerr << "r_virial = "
00626                    << Rsun_pc *
00627                       b->get_starbase()->conv_r_dyn_to_star(r_virial) << endl;
00628       PRI(4); cerr << "t_relax = "
00629                    <<  b->get_starbase()->conv_t_dyn_to_star(t_relax)  << endl;
00630     }
00631     else
00632       cerr <<"\t"<< r_virial <<" "<< t_relax << endl;
00633 }
00634 
00635 local void get_composition(dyn* b,
00636                            real m_cutoff, real M_cutoff,
00637                            int& n, real& mmean,
00638                            real& rmean,
00639                            real& vdisp) {
00640   
00641   n=0;
00642   real T_eff, L_eff, R_eff;
00643   real m_total=0, v2_disp=0, r_total=0;
00644   
00645   for_all_daughters(dyn, b, bi)
00646     if (bi->get_mass()>=m_cutoff && bi->get_mass()<=M_cutoff) {
00647       n++;
00648       m_total += bi->get_mass();
00649       v2_disp += bi->get_vel()*bi->get_vel();
00650       //R_eff = getrq(bi->get_star_story(), "R_eff");
00651       //if (R_eff<=0) {
00652 
00653       T_eff = getrq(bi->get_star_story(), "T_eff");
00654       L_eff = getrq(bi->get_star_story(), "L_eff");
00655       R_eff = sqrt(max(0.1, (1130.*L_eff)/pow(T_eff, 4)));
00656             
00657       r_total += R_eff;
00658     }
00659 
00660   if (n>0) {
00661     mmean = b->get_starbase()->conv_m_dyn_to_star(m_total)/(1.0*n);
00662     rmean = r_total/(1.0*n);
00663 
00664     vdisp = sqrt(v2_disp)/(1.0*n);
00665     vdisp = conv_v_dyn_to_star(vdisp,
00666                                b->get_starbase()->conv_r_star_to_dyn(1),
00667                                b->get_starbase()->conv_t_star_to_dyn(1));
00668   }
00669 }
00670 
00671 local real encounter_rate(int im, real ni, real mi, real ri, real vi, 
00672                           real rci,
00673                           int jm, real nj, real mj, real rj, real vj, 
00674                           real rcj) 
00675 {
00676           
00677     real to_volume = 4*PI/3.;
00678 
00679     //PRC(im);PRC(ni);PRC(mi);PRC(ri);PRC(vi);PRL(rci);
00680     //PRC(jm);PRC(nj);PRC(mj);PRC(rj);PRC(vj);PRL(rcj);
00681   
00682     real n_rhoi = 1./(to_volume * pow(rci, 3));
00683     real n_rhoj = 1./(to_volume * pow(rcj, 3));
00684     real r_tot  = ri + rj;
00685     real m_tot  = mi + mj;
00686     real v_rel  = sqrt(pow(vi, 2) + pow(vj, 2));
00687     real rcore = min(rci, rcj);
00688 
00689     real geometric = 6.31e-15 * v_rel * pow(r_tot, 2);
00690     real grav_foc = 3.61e-9 * m_tot * r_tot / v_rel;
00691 
00692     real rate = 0;
00693         
00694     if (im==jm) {
00695 
00696       if (ni>1)
00697         rate = 0.5 * ((ni-1) * n_rhoi)
00698                    *  (nj * n_rhoj)
00699                    * pow(rcore, 3)
00700                    * (grav_foc + geometric);
00701     }
00702     else
00703       rate = (ni * n_rhoi)
00704            * (nj * n_rhoj)
00705            * pow(rcore, 3)
00706            * (grav_foc + geometric);
00707     
00708 #if 0
00709     if(rate>0)
00710       cerr << jm <<" "<< im <<" "
00711            << mj <<" "<< mi <<" "
00712            << nj <<" "<< ni <<" "
00713            << rate << endl;
00714 #endif
00715 
00716     return rate;
00717 }
00718 
00719 
00720 
00721 //#else
00722 
00723 main(int argc, char **argv)
00724 {
00725     bool binaries = true, verbose = true, out = false,
00726          calc_e = true, Mcut=true, mcut=true;
00727     int nzones = 10, nstep = 1;
00728     bool auto_detect = false;
00729     real mmin = 0.1, m_min = 0.1;
00730     real mmax = 1000, m_max = 1000;
00731     real dt = 0;
00732 
00733     extern char *poptarg;
00734     int c;
00735     char* param_string = "N:n:MmeoT:v"; // Note: "v" removed because only the
00736                                         // "verbose" option currently works.
00737 
00738     while ((c = pgetopt(argc, argv, param_string)) != -1)
00739         switch(c) {
00740 
00741             case 'e': calc_e = !calc_e;
00742                       break;
00743             case 'n': nzones = atoi(poptarg);
00744                       break;
00745             case 'N': nstep = atoi(poptarg);
00746                       break;
00747             case 'M': Mcut = !Mcut;
00748                       break;
00749             case 'm': mcut = !mcut;
00750                       break;
00751             case 'a': auto_detect = !auto_detect;
00752                       break;
00753             case 'T': dt = atof(poptarg);
00754                       break;
00755             case 'o': out = !out;
00756                       break;
00757             case 'v': verbose = !verbose;
00758                       break;
00759             case '?': params_to_usage(cerr, argv[0], param_string);
00760                       exit(1);
00761         }
00762 
00763     // Loop over input until no more data remain.
00764 
00765     dyn *b;
00766 
00767     real to_volume = 4*PI/3.;
00768     real n_rho1, n_rhoi, n_rhoj;
00769     real r_tot, m_tot, v_rel;      
00770     int n, ncore;
00771     real mass_int;
00772     vector density_center;
00773     real rcore=0, vcore=0;
00774     real kT;
00775     real M_cutoff, m_cutoff;
00776     real m_total;
00777 
00778     //    real dmass  = log10(mmax-mmin)/(1.*nzones);
00779         real dmass  = (mmax-mmin)/(1.*nzones);
00780 
00781     real mmean, rmean, vdisp;
00782     //     real *core_radius = (real *) calloc(nzones+1, 8);
00783     //     int  *nstars = (int *) calloc(nzones+1, 4);
00784     //     real *m_mean = (real *) calloc(nzones+1, 8);
00785     //     real *v_disp = (real *) calloc(nzones+1, 8);
00786     //     real *r_mean = (real *) calloc(nzones+1, 8);
00787     
00788     real *core_radius = new real[nzones+1];
00789     real  *ncstars = new real[nzones+1];
00790     real  *nstars = new real[nzones+1];
00791     real *m_mean = new real[nzones+1];
00792     real *v_disp = new real[nzones+1];
00793     real *vc_disp = new real[nzones+1];
00794     real *r_mean = new real[nzones+1];
00795 
00796     real  *new_nstars = new real[nzones+1];
00797     real  *old_nstars = new real[nzones+1];
00798     real  *loss = new real[2*nzones+1];
00799     real  *gain = new real[2*nzones+1];
00800     real   new_mass;
00801     int    km;
00802         
00803     real geometric, grav_foc, rate, total_rate;
00804     
00805     while (b = get_dyn(cin)) {
00806 
00807       total_rate = rcore = vcore=0;
00808       
00809       for (int i=0; i<=nzones; i++) {
00810         core_radius[i] = m_mean[i] = v_disp[i] = vc_disp[i] = r_mean[i] = 0;
00811         ncstars[i] = nstars[i] = 0;
00812         old_nstars[i] = new_nstars[i] = 0;
00813       }
00814       for (int i=0; i<=2*nzones; i++)
00815         loss[i]=gain[i]=0;
00816 
00817       b->get_starbase()->print_stellar_evolution_scaling(cerr);
00818       cerr << "Time = " << b->get_system_time() << endl;
00819       
00820       // Count stars and find mass extremes.
00821       n=0;
00822       if (auto_detect) {
00823         m_min = VERY_LARGE_NUMBER;
00824         m_max = -m_min;
00825         for_all_daughters(dyn, b, bi) {
00826           n++;
00827           m_min = min(m_min, bi->get_mass());
00828           m_max = max(m_max, bi->get_mass());
00829         }
00830       }
00831       else {
00832         for_all_daughters(dyn, b, bi) 
00833           n++;
00834         m_min = b->get_starbase()->conv_m_star_to_dyn(m_min);
00835         m_max = b->get_starbase()->conv_m_star_to_dyn(m_max);
00836       }
00837       //      mass_int = (log10(m_max)-log10(m_min))/(1.0*nzones-1);
00838       mass_int = (m_max-m_min)/(1.0*nzones-1);
00839 
00840       //rcore = getrq(b->get_dyn_story(), "core_radius");
00841       //density_center = getrq(b->get_dyn_story(), "density_center_pos");
00842       
00843       real* local_density = new real[n+1];
00844       if(local_density==NULL) {
00845         cerr << "Not enough memory to allocate local_density[" << n << "].\n";
00846         exit(1);
00847       }
00848       for(int i=0; i<n; i++)
00849         local_density[i] = 0;
00850 
00851       print_core_parameters(b, density_center, rcore, ncore, vcore,
00852                             n, local_density, m_min, m_max, verbose);
00853       print_energies(b, kT, m_min, m_max, verbose);
00854       print_relaxation_time(b, m_min, m_max, verbose);
00855       print_lagrangian_radii(b, density_center, 0, m_min, m_max, 0);
00856 
00857       core_radius[0] = Rsun_pc * b->get_starbase()->conv_r_dyn_to_star(rcore);
00858       nstars[0] = n;
00859       ncstars[0] = ncore;
00860       vc_disp[0] = vcore;
00861 
00862       get_composition(b, m_min, m_max, n, mmean, rmean, vdisp);
00863       m_mean[0] = mmean;
00864       v_disp[0] = vdisp;
00865       r_mean[0] = rmean;
00866       
00867       //PRC(nstars[0]);PRC(m_min);PRC(m_max);PRL(mass_int);
00868       //PRC(rcore);PRC(m_mean[0]);PRC(r_mean[0]);PRC(v_disp[0]);
00869 
00870       for (int i=0; i<nzones; i++) {
00871 
00872         //      m_cutoff = pow(10., log10(m_min)+i*mass_int);
00873         //      M_cutoff = pow(10., log10(m_min)+(i+1)*mass_int);
00874         m_cutoff = (m_min)+i*mass_int;
00875         M_cutoff = (m_min)+(i+1)*mass_int;
00876 
00877         if (!Mcut) M_cutoff = m_max;
00878         if (!mcut) m_cutoff = m_min;
00879 
00880         for(int is=0; is<nstars[0]; is++)
00881           local_density[is] = 0;
00882 
00883         mmean = vdisp = rmean = 0;
00884         get_composition(b, m_cutoff, M_cutoff, n, mmean, rmean, vdisp); 
00885         nstars[i+1] = n;
00886         //      m_mean[i+1] = mmean;
00887         m_mean[i+1] = M_cutoff;
00888         v_disp[i+1] = vdisp;
00889         r_mean[i+1] = rmean;
00890         
00891         if (n > 6 &&
00892             !(n==nstars[i] && (!Mcut || !mcut))) {
00893 
00894           rcore = 0;
00895           print_core_parameters(b, density_center, rcore, ncore, vcore,
00896                                 n, local_density, m_cutoff, M_cutoff, verbose);
00897           core_radius[i+1] = Rsun_pc * b->get_starbase()
00898                                         ->conv_r_dyn_to_star(rcore);
00899           ncstars[i+1] = ncore;
00900           vc_disp[i+1] = vcore;
00901 
00902           print_energies(b, kT, m_cutoff, M_cutoff, verbose);
00903           print_relaxation_time(b, m_cutoff, M_cutoff, verbose);
00904           print_lagrangian_radii(b, density_center, 0, m_cutoff, M_cutoff, 0);
00905 
00906           //PRC(n);PRC(core_radius[0]);PRL(core_radius[i+1]);
00907 
00908           n_rho1 = 1./(to_volume * pow(core_radius[0], 3));
00909           n_rhoi = ncstars[i+1]/(to_volume * pow(core_radius[i+1], 3));
00910           r_tot  = r_mean[0] + r_mean[i+1];
00911           m_tot  = m_mean[0] + m_mean[i+1];
00912           v_rel  = sqrt(pow(vc_disp[0], 2) + pow(vc_disp[i+1], 2));
00913 
00914           //PRC(vc_disp[0]);PRC(vc_disp[i+1]);PRL(v_rel);
00915           
00916           geometric = 6.31e-9 * v_rel * pow(r_tot, 2);
00917           grav_foc = 3.61e-3 * m_tot * r_tot / v_rel;
00918           rate = (n_rho1/1000.) * (n_rhoi/1000)
00919                          * pow(core_radius[0], 3)
00920                          * (grav_foc + geometric);
00921 
00922           if (verbose) {
00923             cerr << "     Stars: (N, r, m, v) = ( "
00924                  << nstars[i+1] <<", "
00925                  << r_mean[i+1] <<", "
00926                  << m_mean[i+1] <<", "
00927                  << v_disp[i+1] <<" ) [solar/km/s]\n";
00928             cerr << "     rate = "
00929                  << rate << " [per Myr]\n"
00930                  << "          (geo, gf) = ( "
00931                  << 100 * geometric/(geometric+grav_foc)
00932                  << ", " << 100 * grav_foc/(geometric+grav_foc)
00933                  << " ) [\%]\n\n";
00934           }
00935           else {
00936             PRI(4); PRC(m_mean[i+1]);PRC(v_disp[i+1]);PRL(r_mean[i+1]);
00937             PRI(4);PRC(geometric); PRL(grav_foc);
00938             PRI(4);PRL(rate);
00939             cerr << endl;
00940 
00941           }
00942 
00943         }
00944       }
00945       
00946       // Now print the encounter probability in a mass-mass plane.
00947       cerr << log10(b->get_starbase()
00948                      ->conv_m_dyn_to_star(m_min)) <<" "
00949            << log10(b->get_starbase()
00950                      ->conv_m_dyn_to_star(m_max)) << " "
00951            << nzones << endl;
00952       cerr << log10(b->get_starbase()
00953                      ->conv_m_dyn_to_star(m_min)) <<" "
00954            << log10(b->get_starbase()
00955                      ->conv_m_dyn_to_star(m_max)) << " "
00956            << nzones << endl;
00957       
00958       for (int im=1; im<nzones+1; im++) {
00959         for (int jm=im; jm<nzones+1; jm++) {
00960 
00961           //PRC(im);PRC(ncstars[im]);PRC(m_mean[im]);PRL(core_radius[im]);
00962           //PRC(jm);PRC(ncstars[jm]);PRC(m_mean[jm]);PRL(core_radius[jm]);
00963 
00964           rate = 0;
00965           
00966           if (core_radius[im]>0) {
00967             if(core_radius[jm]>0) 
00968               
00969             rate = encounter_rate(im,  ncstars[im], m_mean[im], r_mean[im], 
00970                            vc_disp[im], core_radius[im], 
00971                            jm, ncstars[jm], m_mean[jm], r_mean[jm],
00972                            vc_disp[jm], core_radius[jm]);
00973             else 
00974               
00975             rate = encounter_rate(im, ncstars[im], m_mean[im], r_mean[im], 
00976                            vc_disp[im], core_radius[im], 
00977                            jm, nstars[jm]*core_radius[0], 
00978                            m_mean[jm], r_mean[jm],
00979                            vc_disp[0], core_radius[0]);
00980           }
00981           else if(core_radius[jm]>0) 
00982               
00983             rate = encounter_rate(im, nstars[im]*core_radius[0], 
00984                            m_mean[im], r_mean[im], 
00985                            vc_disp[0], core_radius[0], 
00986                            jm, ncstars[jm], m_mean[jm], r_mean[jm],
00987                            vc_disp[jm], core_radius[jm]);         
00988 
00989           total_rate += rate;
00990           }
00991 
00992         }
00993     }
00994     //rmtree(b);
00995       cerr << 0 << " " << 0 << " "
00996            << 0 << " " << 0 << " "
00997            << 0 << " " << 0 << " "
00998            << 0 << endl;
00999       cerr << "     Total encounter rate = "
01000            << total_rate << " [per Myr]" << endl;
01001       
01002 
01003 
01004       //Fill in the Gaps.
01005       real mc_tot = 0;
01006       real new_mc_tot = 0;
01007       for (km=1; km<nzones+1; km++) {
01008         //PRC(km);PRC(ncstars[km]);PRC(m_mean[km]);PRL(core_radius[km]);
01009         
01010         if (core_radius[km]<=0) {
01011             core_radius[km] = core_radius[0];
01012             new_nstars[km] = pow(1.0*nstars[km], 1./3.);
01013             //m_mean[km] = pow(10, (km-1)*dmass) -1 + mmin;
01014             r_mean[km] = pow(m_mean[km], 0.7);
01015             vc_disp[km] = vc_disp[0];
01016         }
01017         else 
01018           new_nstars[km] = ncstars[km];
01019         
01020         m_mean[km] = km*dmass;
01021         nstars[km] -= new_nstars[km];
01022         mc_tot += new_nstars[km] * m_mean[km];
01023 
01024         //PRC(km);PRC(new_nstars[km]);PRC(m_mean[km]);PRL(core_radius[km]);
01025       }
01026       for (km=1; km<nzones+1; km++) {
01027         old_nstars[km] = new_nstars[km];
01028       }
01029 
01030       real nstar_loss = 0;
01031       for(int ii=1; ii<nstep; ii++) {
01032       for (int im=1; im<nzones+1; im++) {
01033         for (int jm=im; jm<nzones+1; jm++) {
01034 
01035           rate = encounter_rate(im,  new_nstars[im], m_mean[im], r_mean[im], 
01036                                 vc_disp[im], core_radius[im], 
01037                                 jm, new_nstars[jm], m_mean[jm], r_mean[jm],
01038                                 vc_disp[jm], core_radius[jm]);
01039 
01040       
01041           //PRC(im);PRC(jm);PRC(m_mean[im]);PRC(m_mean[jm]);
01042           //PRC(new_nstars[im]);PRL(rate);
01043             new_mass = m_mean[im] + m_mean[jm];
01044             //      km = int((log10(new_mass)+log10(mmin))/dmass);
01045             //      km = int((log10(new_mass) - log10(mmin))/dmass);
01046             //km = int(1 + log(new_mass - mmin + 1)/dmass);
01047             //km = 1 + int(new_mass - mmin/dmass);
01048             km = min(2*nzones, im + jm);
01049             //m_mean[km] = pow(10, (km-1)*dmass) -1 + mmin;
01050             
01051             real ncoll = max(0., min(rate * dt,
01052                                  min(new_nstars[im]-loss[im],
01053                                      new_nstars[jm]-loss[im])));
01054 
01055             //PRC(new_mass);PRC(km);PRC(rate);PRL(ncoll);
01056             loss[im] += ncoll;
01057             loss[jm] += ncoll;
01058             gain[km] += ncoll;
01059         }
01060       }
01061 
01062       real total_loss = 0;
01063       real total_gain = 0;
01064       for (int im=1; im<nzones+1; im++) {
01065         total_loss += loss[im] * m_mean[im];
01066         total_gain += gain[im] * m_mean[im];
01067         new_nstars[im] = new_nstars[im] - loss[im] + gain[im];
01068         nstar_loss = nstar_loss + gain[im] - loss[im];
01069         
01070       }
01071       for (int im=0; im<=2*nzones; im++)
01072         loss[im]=gain[im]=0;
01073 
01074       cerr << "Total loss = " << total_loss
01075            << " total gain = " << total_gain << endl;
01076       }
01077 
01078       cerr << "Old and new mass function: "<<endl;
01079       for (km=1; km<nzones+1; km++) {
01080         new_mc_tot += new_nstars[km] * m_mean[km];
01081         if(old_nstars[km]<=1.e-7)
01082           old_nstars[km]=0;
01083         if(new_nstars[km]<=1.e-7)
01084           new_nstars[km]=0;
01085         if(old_nstars[km]>0 || new_nstars[km]>0)
01086           cerr << km <<" "<< m_mean[km] <<" "
01087                << old_nstars[km] << " " << new_nstars[km] << endl;
01088       }
01089 
01090       cerr << " N star lost = " << nstar_loss << endl;
01091       cerr << "Total mass goes from: "<< mc_tot << " to " << new_mc_tot <<endl;
01092       //          new_nstars[km] = nstars[km] + rate * dt;
01093 
01094     // Now evolvefor one timestep and compute the
01095     // new mass spectrum
01096 
01097 }
01098 
01099 #endif

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