Main Page   Class Hierarchy   Data Structures   File List   Data Fields   Globals  

scatt_stats_2.C

Go to the documentation of this file.
00001 
00002 // scatt_stats_2.C: Determine merger cross-sections for 3-body scattering.
00003 //                  Steve McMillan, Piet Hut, Charles Bailyn (May/Sep 1994)
00004 
00005 // Starlab application:  get_sigma3.
00006 
00007 #include "sigma3.h"
00008 #define DEBUG 0
00009 
00010 #define Grav    6.673e-8
00011 #define Msun    1.989e33
00012 #define AU      1.486e13
00013 #define Rsun    6.960e10
00014 
00015 #define Kms     1e5
00016 #define SECONDS_IN_YEAR 3.16e7
00017 #define CM_IN_PC 3.086e18
00018 
00019 // Bin final results in:
00020 //      (1) total mass and helium abundance
00021 //      (2) total mass and helium mass.
00022 
00023 #define N_MASS 24
00024 #define M_MIN  0.0      // M_MIN and M_MAX determine limits on mass for binning
00025 #define M_MAX  2.4      // purposes only.  Actual limits are m_lower, m_upper.
00026 
00027 #define N_HE   10
00028 #define MIN_HE 0.24     // MIN_HE and MAX_HE determine limits on mass for
00029 #define MAX_HE 0.39     // binning purposes only.
00030 
00031 #define N_HEMASS 10
00032 #define M_HEMIN  0.0    // M_HEMIN and M_HEMAX determine limits on helium mass
00033 #define M_HEMAX  1.0    // for binning purposes only.
00034 
00035 static real m_lower  = 0.1;
00036 static real m_upper  = 0.8;
00037 static real exponent = 1.35;    // Convention: Salpeter = +1.35!
00038 static real m_unit;
00039 
00040 // Interpolation from real stellar models:
00041 
00042 #define N_INT 9
00043 static real m_int[N_INT] = {0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.75, 0.8};
00044 static real r_int[N_INT] = {0.1, 0.2, 0.3, 0.4, 0.51, 0.63, 0.75, 1.09, 1.87};
00045 static real y_int[N_INT] = {0.240, 0.240, 0.243, 0.248, 0.254,
00046                             0.273, 0.313, 0.347, 0.385};
00047 
00048 static int n_scatt = 0;
00049 static int n_merge = 0;
00050 
00051 static int temp_counter_1[N_MASS][N_HE][N_RHO_ZONE_MAX];
00052 static int total_counter_1[N_MASS][N_HE][N_RHO_ZONE_MAX];
00053 static real sigma_1[N_MASS][N_HE];
00054 static real sigma_err_sq_1[N_MASS][N_HE];
00055 
00056 static int temp_counter_2[N_MASS][N_HEMASS][N_RHO_ZONE_MAX];
00057 static int total_counter_2[N_MASS][N_HEMASS][N_RHO_ZONE_MAX];
00058 static real sigma_2[N_MASS][N_HEMASS];
00059 static real sigma_err_sq_2[N_MASS][N_HEMASS];
00060 
00061 
00062 local int get_index(real m)
00063 {
00064     for (int i = 0; i < N_INT; i++) if (m_int[i] > m) return i-1;
00065     return N_INT - 1;
00066 }
00067 
00068 
00069 local real get_quantity(real m, real* q)
00070 {
00071     int i = get_index(m);
00072 
00073     if (i < 0)
00074         return q[0];
00075     else if (i >= N_INT-1)
00076         return q[N_INT-1];
00077 
00078     return q[i] + (m - m_int[i]) * (q[i+1] - q[i]) / (m_int[i+1] - m_int[i]);
00079 }
00080 
00081 
00082 local real radius(real m)       // Mass-radius relation (units: solar)
00083 {
00084     return get_quantity(m, r_int);
00085 }
00086 
00087 
00088 local real helium(real m)       // Helium fraction (mass unit = solar mass)
00089 {
00090     return get_quantity(m, y_int);
00091 }
00092 
00093 
00094 // get_mass: Return a random mass between ml and mu, distributed as a
00095 //           power law with exponent x (i.e. dN/dm \propto m^x).
00096 
00097 local real get_mass(real ml, real mu, real x)
00098 {
00099     real r = randinter(0,1);
00100 
00101     if (x == -1) 
00102         return ml * exp( r*log(mu/ml) );
00103     else
00104         return ml * pow( 1 + r * (pow(mu/ml, 1+x) - 1), 1.0/(1+x));
00105 }
00106 
00107 // ------------------------------------------------------------------------
00108 
00109 // Zero out accumulators:
00110 
00111 local void zero_temp_counter()
00112 {
00113     for (int i = 0; i < N_MASS; i++) {
00114         int j, k;
00115         for (j = 0; j < N_HE; j++)
00116             for (k = 0; k < N_RHO_ZONE_MAX; k++) temp_counter_1[i][j][k] = 0;
00117         for (j = 0; j < N_HEMASS; j++)
00118             for (k = 0; k < N_RHO_ZONE_MAX; k++)        temp_counter_2[i][j][k] = 0;
00119     }
00120 }
00121 
00122 
00123 local void initialize_stats()
00124 {
00125     for (int i = 0; i < N_MASS; i++) {
00126         int j, k;
00127         for (j = 0; j < N_HE; j++) {
00128             sigma_1[i][j] = sigma_err_sq_1[i][j] = 0;
00129             for (k = 0; k < N_RHO_ZONE_MAX; k++) total_counter_1[i][j][k] = 0;
00130         }
00131         for (j = 0; j < N_HEMASS; j++) {
00132             sigma_1[i][j] = sigma_err_sq_1[i][j] = 0;
00133             for (k = 0; k < N_RHO_ZONE_MAX; k++)        total_counter_2[i][j][k] = 0;
00134         }
00135     }
00136 }
00137 
00138 // ------------------------------------------------------------------------
00139 
00140 // accumulate_stats: Gather statistics supplied by get_sigma3. Customize here
00141 //                   to the specific application at hand.
00142 
00143 local void accumulate_stats(scatter_profile& prof,
00144                             initial_state3& init,
00145                             intermediate_state3& inter,
00146                             final_state3& final,
00147                             int rho_bin,
00148                             sigma_out& out)
00149 {
00150 
00151     n_scatt++;
00152 
00153     real mmerge = 0, mhemerge = 0;
00154     real ymerge;
00155 
00156     if (final.descriptor == merger_binary_1
00157         || final.descriptor == merger_escape_1) {        // 2 and 3 merged
00158 
00159         mmerge = prof.m2 + prof.m3;
00160         ymerge = (prof.m2 * helium(prof.m2*m_unit)
00161                   + prof.m3 * helium(prof.m3*m_unit)) / mmerge;
00162 
00163     } else if (final.descriptor == merger_binary_2
00164                || final.descriptor == merger_escape_2) { // 1 and 3 merged
00165 
00166         real m1 = 1 - prof.m2;
00167         mmerge = m1 + prof.m3;
00168         ymerge = (m1 * helium(m1*m_unit)
00169                   + prof.m3 * helium(prof.m3*m_unit)) / mmerge;
00170 
00171     } else if (final.descriptor == merger_binary_3
00172                || final.descriptor == merger_escape_3) { // 1 and 2 merged
00173 
00174         real m1 = 1 - prof.m2;
00175         mmerge = 1;
00176         ymerge = m1 * helium(m1*m_unit) + prof.m2 * helium(prof.m2*m_unit);
00177 
00178     } else if (final.descriptor == triple_merger) {      // 1, 2 and 3 merged
00179 
00180         real m2 = prof.m2;
00181         real m1 = 1 - m2;
00182         mmerge = 1 + prof.m3;
00183         ymerge = (m1 * helium(m1*m_unit) + m2 * helium(m2*m_unit)
00184                   + prof.m3 * helium(prof.m3*m_unit)) / mmerge;
00185     }
00186 
00187     if (mmerge > 0) {
00188         mmerge *= m_unit;
00189 
00190         int i = (int) (N_MASS * (mmerge - M_MIN) / (M_MAX - M_MIN));
00191         if (i < 0) i = 0;
00192         if (i >= N_MASS) i = N_MASS - 1;
00193 
00194         int j = (int) (N_HE * (ymerge - MIN_HE) / (MAX_HE - MIN_HE));
00195         if (j < 0) j = 0;
00196         if (j >= N_HE) j = N_HE - 1;
00197 
00198         temp_counter_1[i][j][rho_bin]++;
00199 
00200         mhemerge = mmerge * ymerge;
00201 
00202         j = (int) (N_HEMASS * (mhemerge - M_HEMIN) / (M_HEMAX - M_HEMIN));
00203         if (j < 0) j = 0;
00204         if (j >= N_HEMASS) j = N_HEMASS - 1;
00205 
00206         temp_counter_2[i][j][rho_bin]++;
00207 
00208         n_merge++;
00209 
00210 #if DEBUG
00211         cerr << "\nacc_stats: " << state_string(inter.descriptor)
00212              << " " << state_string(final.descriptor) << endl;
00213 
00214         int p = cerr.precision(STD_PRECISION);
00215         cerr << "m1, m2, m3 = " << 1 - prof.m2 << " " << prof.m2
00216              << " " << prof.m3 << endl;
00217         cerr << "m_unit = " << m_unit << endl;
00218         cerr << "He: " << helium(m_unit*(1 - prof.m2)) << " "
00219                        << helium(m_unit*prof.m2) << " "
00220                        << helium(m_unit*prof.m3) << endl;
00221         cerr << "M, Y = " << mmerge << " " << ymerge << endl;
00222         cerr << "n, i, j, rho_bin = "
00223              << n_merge << " " << i << " " << j << " " << rho_bin <<endl;
00224         cerr.precision(p);
00225 #endif
00226     }
00227 }
00228 
00229 // normalize_and_store_counts: convert raw counts into cross-sections and
00230 //                             errors, and add them into the total
00231 
00232 local void normalize_and_store_counts(sigma_out& out, real weight)
00233 {
00234     int j;
00235     for (int i = 0; i < N_MASS; i++) {
00236         for (j = 0; j < N_HE; j++) {
00237             real rho_sq_min, rho_sq_max;
00238             int k;
00239             for (k = 0, rho_sq_min = 0, rho_sq_max = out.rho_sq_init;
00240                  k <= out.i_max;
00241                  k++, rho_sq_min = rho_sq_max, rho_sq_max *= RHO_SQ_FACTOR) {
00242 
00243                 real factor = weight * (rho_sq_max - rho_sq_min)
00244                                      / out.trials_per_zone;
00245                 sigma_1[i][j] += factor * temp_counter_1[i][j][k];
00246                 sigma_err_sq_1[i][j] += factor * factor 
00247                                                * temp_counter_1[i][j][k];
00248                 total_counter_1[i][j][k] += temp_counter_1[i][j][k];
00249             }
00250         }
00251         for (j = 0; j < N_HEMASS; j++) {
00252             real rho_sq_min, rho_sq_max;
00253             int k;
00254             for (k = 0, rho_sq_min = 0, rho_sq_max = out.rho_sq_init;
00255                  k <= out.i_max;
00256                  k++, rho_sq_min = rho_sq_max, rho_sq_max *= RHO_SQ_FACTOR) {
00257 
00258                 real factor = weight * (rho_sq_max - rho_sq_min)
00259                                      / out.trials_per_zone;
00260                 sigma_2[i][j] += factor * temp_counter_2[i][j][k];
00261                 sigma_err_sq_2[i][j] += factor * factor
00262                                                * temp_counter_2[i][j][k];
00263                 total_counter_2[i][j][k] += temp_counter_2[i][j][k];
00264             }
00265         }
00266     }
00267 } 
00268 
00269 #define SCALE 100
00270 
00271 local void normalize_and_print_stats(sigma_out& out)
00272 {
00273     if (n_merge <= 0) {
00274         cerr << "\nn_merge = 0!\n";
00275         return;
00276     }
00277     int i, j;
00278 
00279     cerr << "\nNormalized differential cross sections (n_scatt = " << n_scatt << "):\n";
00280 
00281     cerr << "\nRaw counts (row = 10*mass, column = scaled He,"
00282          << " total = " << n_merge << "):\n\n";
00283 
00284     for (i = 0; i < N_MASS; i++) {
00285         for (j = 0; j < N_HE; j++) {
00286             int total = 0;
00287             for (int k = 0; k <= out.i_max; k++) 
00288                 total += total_counter_1[i][j][k];
00289             fprintf(stderr, " %7d", total);
00290         }
00291         cerr << endl;
00292     }
00293     cerr << endl;
00294     for (i = 0; i < N_MASS; i++) {
00295         for (j = 0; j < N_HEMASS; j++) {
00296             int total = 0;
00297             for (int k = 0; k <= out.i_max; k++) 
00298                 total += total_counter_2[i][j][k];
00299             fprintf(stderr, " %7d", total);
00300         }
00301         cerr << endl;
00302     }
00303 
00304     real sum1 = 0, sum2 = 0;
00305     for (i = 0; i < N_MASS; i++) {
00306         for (j = 0; j < N_HE;     j++) sum1 += sigma_1[i][j];
00307         for (j = 0; j < N_HEMASS; j++) sum2 += sigma_2[i][j];
00308     }
00309 
00310     cerr << endl << SCALE << " sigma_1 (total = " << sum1/n_scatt
00311          << " pi a^2):\n\n";
00312 
00313     sum1 /= SCALE;
00314 
00315     for (i = 0; i < N_MASS; i++) {
00316         for (j = 0; j < N_HE; j++)
00317             fprintf(stderr, " %7.3f", sigma_1[i][j]/sum1);
00318         cerr << endl;
00319     }
00320 
00321     cerr << endl << SCALE << " sigma_2 (total = " << sum2/n_scatt
00322          << " pi a^2):\n\n";
00323 
00324     sum2 /= SCALE;
00325 
00326     for (i = 0; i < N_MASS; i++) {
00327         for (j = 0; j < N_HEMASS; j++)
00328             fprintf(stderr, " %7.3f", sigma_2[i][j]/sum2);
00329         cerr << endl;
00330     }
00331 
00332     cerr << "\nsigma_1 error:\n\n";
00333 
00334     for (i = 0; i < N_MASS; i++) {
00335         for (j = 0; j < N_HE; j++)
00336             fprintf(stderr, " %7.3f", sqrt(sigma_err_sq_1[i][j])/sum1);
00337         cerr << endl;
00338     }
00339 
00340     cerr << "\nsigma_2 error:\n\n";
00341 
00342     for (i = 0; i < N_MASS; i++) {
00343         for (j = 0; j < N_HEMASS; j++)
00344             fprintf(stderr, " %7.3f", sqrt(sigma_err_sq_2[i][j])/sum2);
00345         cerr << endl;
00346     }
00347 }
00348 
00349 // ------------------------------------------------------------------------
00350 
00351 main(int argc, char **argv)
00352     {
00353     int  debug  = 0;
00354     int  seed   = 0;
00355     int  n_rand = 0;
00356     real max_trial_density = 1.0;
00357 
00358     real cpu_time_check = 3600; // One check per CPU hour!
00359     real dt_snap = VERY_LARGE_NUMBER;
00360     real snap_cube_size = 10;
00361     int scatter_summary_level = 0;
00362 
00363     real sma = 1.0;     // Binary semi-major axis in A.U.
00364     real v_inf = 10.0;  // Relative velocity at infinity in km/s
00365 
00366     int n_sigma3 = 1;
00367     bool sig_print = FALSE;
00368     bool stat_print = 0;
00369 
00370     scatter_profile prof;
00371     make_standard_profile(prof);
00372 
00373     extern char *poptarg;
00374     int c;
00375     char* param_string = "a:A:c:C:D:d:e:l:L:n:N:p:PqQs:u:U:v:V:x:";
00376 
00377     while ((c = pgetopt(argc, argv, param_string)) != -1)
00378         switch(c)
00379             {
00380             case 'a': sma = atof(poptarg);
00381                       break;
00382             case 'A': prof.eta = atof(poptarg);
00383                       break;
00384             case 'c': cpu_time_check = 3600*atof(poptarg);// (Specify in hours)
00385                       break;
00386             case 'C': snap_cube_size = atof(poptarg);
00387                       break;
00388             case 'd': max_trial_density = atof(poptarg);  // Max density for a
00389                       break;                              // single experiment
00390             case 'D': dt_snap = atof(poptarg);
00391                       scatter_summary_level = 2;  // Undo with later "-q/Q"
00392                       break;
00393             case 'e': prof.ecc = atof(poptarg);
00394                       prof.ecc_flag = 1;
00395                       break;
00396             case 'l':
00397             case 'L': m_lower = atof(poptarg);
00398                       break;
00399             case 'n': n_sigma3 = atoi(poptarg);
00400                       break;
00401             case 'N': n_rand = atoi(poptarg);
00402                       break;
00403             case 'p': stat_print = atoi(poptarg);
00404                       if (stat_print <= 0) stat_print = 1;
00405                       break;
00406             case 'P': sig_print = 1 - sig_print;
00407                       stat_print = 1;
00408                       break;
00409             case 'q': if (scatter_summary_level > 0)
00410                           scatter_summary_level = 0;
00411                       else
00412                           scatter_summary_level = 1;
00413                       break;
00414             case 'Q': if (scatter_summary_level > 0)
00415                           scatter_summary_level = 0;
00416                       else
00417                           scatter_summary_level = 2;
00418                       break;
00419             case 's': seed = atoi(poptarg);
00420                       break;
00421             case 'u':
00422             case 'U': m_upper = atof(poptarg);
00423                       break;
00424             case 'v': v_inf = atof(poptarg);
00425                       break;
00426             case 'V': debug = atoi(poptarg);
00427                       break;
00428             case 'x': exponent = atof(poptarg);
00429                       break;
00430             case '?': params_to_usage(cerr, argv[0], param_string);
00431                       exit(1);
00432             }
00433 
00434     // Debugging:    |debug| = 0 ==> no debugging output
00435     //               |debug| = 1 ==> output only at end (default)
00436     //               |debug| = 2 ==> output at end of each top-level iteration
00437     //               |debug| = 3 ==> output after each sub-trial
00438     //
00439     //                debug  < 0 ==> simple statistics also (default: off)
00440 
00441     cpu_init();
00442 
00443     cerr << "\n\t*** "
00444          << "Binary/single-star scattering with stellar collisions."
00445          << " ***\n\n";
00446     cerr << "Binary semi-major-axis a = " << sma
00447          << " A.U.  Velocity at infinity = " << v_inf << " km/s.\n";
00448     cerr << "Mass range = " << m_lower << "-" << m_upper
00449          << " solar masses,  power-law exponent = " << exponent
00450          << " (Salpeter = 1.35)\n";
00451     cerr << "Target trial density = " << max_trial_density
00452          << ",  total number of mass combinations = " << n_sigma3 << endl;
00453 
00454     int first_seed = srandinter(seed, n_rand);
00455     cerr << "Random seed = " << first_seed << endl;
00456 
00457     sigma_out out;
00458     initialize_stats();
00459 
00460     // Loop over mass combinations, obtaining cross-sections for each.
00461 
00462     for (int i = 0; i < n_sigma3; i++) {
00463 
00464         // Get masses in solar masses, randomly from the mass function.
00465 
00466         real m1 = get_mass(m_lower, m_upper, -exponent - 1);
00467         real m2 = get_mass(m_lower, m_upper, -exponent - 1);
00468         real m3 = get_mass(m_lower, m_upper, -exponent - 1);
00469 
00470         // Scale masses, v_inf and radii:
00471 
00472         m_unit = m1 + m2;
00473         real r_unit = sma;
00474         real v_unit = sqrt( (Grav * Msun / AU)
00475                            * m1 * m2 * (m1 + m2 + m3) / ((m1 + m2) * m3)
00476                            / sma ) / Kms;
00477 
00478         prof.m2 = m2 / m_unit;
00479         prof.m3 = m3 / m_unit;
00480         prof.v_inf = v_inf / v_unit;
00481 
00482         prof.r1 = radius(m1) * Rsun / (sma * AU);
00483         prof.r2 = radius(m2) * Rsun / (sma * AU);
00484         prof.r3 = radius(m3) * Rsun / (sma * AU);
00485 
00486         int p = cerr.precision(STD_PRECISION);
00487         cerr << "\nMass combination #" << i+1 << ":\n";
00488         cerr << "    m1 = " << m1 << "  m2 = " << m2
00489              << "  m3 = " << m3 << " solar\n";
00490         cerr << "    r1 = " << radius(m1) << "  r2 = " << radius(m2)
00491              << "  r3 = " << radius(m3) << " solar\n";
00492         cerr << "    a = " << sma << " A.U. = "
00493              << sma * AU / Rsun << " solar,";
00494         cerr << "  v_inf = " << v_inf << " km/s = "
00495              << prof.v_inf << " scaled\n";
00496         cerr.precision(p);
00497 
00498         // Get cross-sections. Note that the primary use of get_sigma3
00499         // here is to ensure that properly sampled data are sent to
00500         // routine accumulate_stats.
00501 
00502         zero_temp_counter();
00503         get_sigma3(max_trial_density, prof, out,
00504                    debug, cpu_time_check,
00505                    dt_snap, snap_cube_size,
00506                    scatter_summary_level,
00507                    accumulate_stats);
00508 
00509         // We are assuming here that all mass combinations carry
00510         // equal statistical weight.
00511 
00512         normalize_and_store_counts(out, 1.0/n_sigma3);
00513 
00514         // Optional diagnostic/intermediate output:
00515 
00516         if (sig_print) print_sigma3(out, prof.v_inf * prof.v_inf);
00517         if (stat_print > 0 && (i+1)%stat_print == 0)
00518             normalize_and_print_stats(out);
00519     }
00520 
00521     normalize_and_print_stats(out);
00522 }

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