00001
00002
00003
00004
00005
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
00020
00021
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;
00038 static real m_unit;
00039
00040
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)
00083 {
00084 return get_quantity(m, r_int);
00085 }
00086
00087
00088 local real helium(real m)
00089 {
00090 return get_quantity(m, y_int);
00091 }
00092
00093
00094
00095
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
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
00141
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) {
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) {
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) {
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) {
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
00230
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;
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;
00364 real v_inf = 10.0;
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);
00385 break;
00386 case 'C': snap_cube_size = atof(poptarg);
00387 break;
00388 case 'd': max_trial_density = atof(poptarg);
00389 break;
00390 case 'D': dt_snap = atof(poptarg);
00391 scatter_summary_level = 2;
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
00435
00436
00437
00438
00439
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
00461
00462 for (int i = 0; i < n_sigma3; i++) {
00463
00464
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
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
00499
00500
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
00510
00511
00512 normalize_and_store_counts(out, 1.0/n_sigma3);
00513
00514
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 }