00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00032
00033
00034
00035
00036
00037
00038
00039
00040 #include "dyn.h"
00041
00042 #ifdef TOOLBOX
00043
00044 #define SEED_STRING_LENGTH 256
00045 char tmp_string[SEED_STRING_LENGTH];
00046
00047 #define NMAX 50000
00048
00049
00050
00051
00052
00053
00054 real pi = M_PI;
00055 real twopi = 2.0 * pi;
00056 real four3pi = 4.0 * pi / 3.0;
00057 real fourpi = 4.0 * pi;
00058 real zero = 0.0;
00059 real one = 1.0;
00060 real quarter = 0.25;
00061 real four3 = 4.0 / 3;
00062
00063
00064
00065
00066 #define NM 2500
00067
00068
00069 real rr[NM+1], d[NM+1], v2[NM+1], psi[NM+1], zm[NM+1];
00070
00071
00072
00073
00074
00075
00076
00077
00078 #define NINDX 100
00079 #define NG 1000
00080 #define YMAX 4.0
00081
00082 int indx[NINDX+1];
00083 real g[NG+1];
00084
00085
00086
00087 real beta = 0.0;
00088 real beta_w0 = 0.0;
00089 real scale_fac = 1.0;
00090
00091
00092
00093 #define FUNC(x) ((*func)(x))
00094
00095 real trapint(real (*func)(real), real a, real b, int n)
00096
00097
00098
00099 {
00100 static real s;
00101 int i, j;
00102 real x, base, sum, dx;
00103
00104 if (n == 1) {
00105
00106 return (s = 0.5 * (b - a) * (FUNC(a) + FUNC(b)));
00107
00108 } else {
00109
00110 for (i = 1, j = 1; j < n - 1; j++) i <<= 1;
00111 base = i;
00112 dx = (b - a) / base;
00113 x = a + 0.5 * dx;
00114 for (sum = 0.0, j = 1; j <= i; j++, x += dx) sum += FUNC(x);
00115 s = 0.5 * (s + (b - a)/base * sum);
00116 return s;
00117 }
00118 }
00119 #undef FUNC
00120
00121 #define MAX_STEPS 50
00122
00123 real trapzd(real (*func)(real), real a, real b, real eps)
00124
00125
00126
00127 {
00128 int i;
00129 real sum, previous_sum;
00130 real diff, cond;
00131
00132 previous_sum = -1.0e30;
00133 for (i = 1; i <= MAX_STEPS; i++) {
00134
00135 sum = trapint(func, a, b, i);
00136 if (fabs(sum - previous_sum) < eps * fabs(previous_sum)) return sum;
00137 previous_sum = sum;
00138 }
00139
00140 return 0.0;
00141
00142 }
00143 #undef MAX_STEPS
00144
00145
00146 real gaus2(real y)
00147 {
00148 return y * y * exp(-y*y);
00149 }
00150
00151
00152 #define EPS 1.e-10
00153
00154 void initialize_global()
00155 {
00156 real yo = 0;
00157 real dy = YMAX/NG;
00158
00159 g[0] = 0;
00160 for (int i = 1; i <= NG; i++) {
00161 real y = yo + dy;
00162 g[i] = g[i-1] + trapzd(gaus2, yo, y, EPS);
00163 yo = y;
00164 }
00165 }
00166
00167
00168 void gg(real y, real& g2, real& g4)
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180 {
00181 real yindx = NG * y / YMAX;
00182 int iy = (int)yindx;
00183
00184 if (iy >= NG)
00185 g2 = g[NG];
00186 else
00187 g2 = g[iy] + (yindx - iy) * (g[iy+1] - g[iy]);
00188
00189 if (g4 > 0) {
00190 real y2 = y * y;
00191 g4 = 1.5 * g2 - 0.5 * y * y2 * exp(-y2);
00192 }
00193 }
00194
00195
00196 void get_dens_and_vel(real psi, real& dens, real& v2)
00197
00198
00199
00200
00201 {
00202 dens = 0;
00203 if (psi >= -beta_w0) return;
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214 real g2, g4 = v2;
00215
00216 real p_max = -psi - beta_w0;
00217
00218 real y_max = sqrt(p_max);
00219 real ep = exp(-psi);
00220
00221 gg(y_max, g2, g4);
00222
00223 dens = ep * g2 - scale_fac * y_max * p_max / 3;
00224
00225
00226
00227
00228
00229 if (v2 > 0 && dens > 0)
00230 v2 = 2 * (ep * g4 - 0.2 * scale_fac * y_max * p_max * p_max) / dens;
00231
00232
00233
00234 }
00235
00236 real dc_inverse;
00237
00238
00239 void rhs(real y[], real x, real ypr[])
00240
00241
00242
00243 {
00244 real d;
00245
00246 ypr[0] = y[1];
00247
00248 if (x <= 0) {
00249
00250 d = 1;
00251
00252 } else {
00253
00254 get_dens_and_vel(y[0]/x, d, zero);
00255
00256 d = d * dc_inverse;
00257 }
00258
00259 ypr[1] = 9 * x * d;
00260
00261 }
00262
00263
00264
00265 void step(real y[], real& x, real dx, int N)
00266
00267
00268
00269 {
00270 int i;
00271
00272
00273
00274
00275
00276
00277 real dydx[4], dy1[4], dy2[4], dy3[4], dy4[4],
00278 y1[4], y2[4], y3[4], y4[4];
00279
00280 rhs(y, x, dydx);
00281
00282 for (i = 0; i < N; i++) {
00283 dy1[i] = dx*dydx[i];
00284 y1[i] = y[i] + 0.5*dy1[i];
00285 }
00286
00287 rhs(y1, x+0.5*dx, dydx);
00288
00289 for (i = 0; i < N; i++) {
00290 dy2[i] = dx*dydx[i];
00291 y2[i] = y[i] + 0.5*dy2[i];
00292 }
00293
00294 rhs(y2, x+0.5*dx, dydx);
00295
00296 for (i = 0; i < N; i++) {
00297 dy3[i] = dx*dydx[i];
00298 y3[i] = y[i] + dy3[i];
00299 }
00300
00301 rhs(y3, x+dx, dydx);
00302
00303 for (i = 0; i < N; i++) {
00304 dy4[i] = dx*dydx[i];
00305 y[i] += (dy1[i] + 2*dy2[i] + 2*dy3[i] + dy4[i])/6.0;
00306 }
00307
00308 x += dx;
00309 }
00310
00311 int time_to_stop(real y[], real x, real x_end, real dx)
00312 {
00313 if (x < x_end - .5*dx)
00314 return 0;
00315 else
00316 return 1;
00317 }
00318
00319
00320 void rk4(real& x, real x_next, real y[], int N, real dx)
00321
00322
00323
00324
00325
00326 {
00327 while (!time_to_stop(y, x, x_next, dx))
00328 step(y, x, dx, N);
00329 }
00330
00331 #define RLIN 0.25
00332 #define NLIN 105
00333 #define RMAX 1e4
00334
00335 void poisson(real x[], int nmax, real w0, int& nprof, real& v20)
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352 {
00353
00354 int i, iflag2;
00355 real psi0, xn, xo, fac;
00356 real y[2];
00357
00358 psi0 = - abs(w0);
00359
00360
00361
00362 xn = 0;
00363 y[0] = 0;
00364 y[1] = psi0;
00365 x[0] = 0;
00366 psi[0] = psi0;
00367 v2[0] = 1;
00368 zm[0] = 0;
00369
00370
00371
00372 get_dens_and_vel(psi0, d[0], v2[0]);
00373 dc_inverse = 1./d[0];
00374
00375 fac = pow(10, (log10(RMAX/RLIN) / (nmax-NLIN)));
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435 iflag2 = 0;
00436
00437 for (i = 1; i <= nmax; i++) {
00438
00439 xo = xn;
00440 if (i <= NLIN)
00441 xn = (RLIN * i) / NLIN;
00442 else
00443 xn = fac * xo;
00444
00445 real dx = 0.051*(xn-xo);
00446
00447 rk4(xo, xn, y, 2, dx);
00448
00449
00450
00451 xn = xo;
00452
00453 x[i] = xn;
00454 psi[i] = y[0] / xn;
00455
00456 v2[i] = 1;
00457 get_dens_and_vel(psi[i], d[i], v2[i]);
00458
00459 if (d[i] < 0) {
00460
00461
00462
00463
00464 x[i] = x[i-1] + (x[i] - x[i-1]) / (0.1 - d[i]/d[i-1]);
00465 d[i] = 0;
00466 v2[i] = 0;
00467
00468 }
00469
00470 zm[i] = x[i] * y[1] - y[0];
00471
00472 if (d[i] > 0) {
00473
00474
00475
00476
00477 } else {
00478
00479 iflag2 = 1;
00480 break;
00481
00482 }
00483 }
00484
00485 if (iflag2 == 0) i = nmax;
00486
00487 nprof = i;
00488
00489
00490
00491 v20 = v2[0];
00492 for (i = nprof; i >= 0; i--) {
00493 d[i] = d[i] / d[0];
00494 v2[i] = v2[i] / v2[0];
00495 zm[i] = (fourpi/9) * zm[i];
00496 }
00497
00498 }
00499 #undef RLIN
00500 #undef NLIN
00501 #undef RMAX
00502
00503 void setpos(dyn * b, real& p)
00504
00505
00506
00507
00508 {
00509
00510
00511 real rno = randinter(0.0, 1.0);
00512
00513 int i = (int)(NINDX * rno);
00514 int i1, iflag = 0;
00515
00516 for (i1 = indx[i]; i1 <= indx[i+1]+1; i1++)
00517 if (zm[i1] > rno) {
00518 iflag = 1;
00519 break;
00520 }
00521
00522 if (iflag == 0) err_exit("mkking: error in getpos");
00523
00524 real rfac = (rno - zm[i1-1]) / (zm[i1] - zm[i1-1]);
00525 real r = rr[i1-1] + rfac * (rr[i1] - rr[i1-1]);
00526
00527 p = psi[i1-1] + rfac * (psi[i1] - psi[i1-1]);
00528
00529
00530
00531 real cth = 2 * randinter(0.0, 1.0) - 1;
00532 real sth = sqrt(1 - cth*cth);
00533 real ph = twopi * randinter(0.0, 1.0);
00534 real cph = cos(ph);
00535 real sph = sin(ph);
00536
00537 b->set_pos(vector(r * sth * cph, r * sth * sph, r * cth));
00538 }
00539
00540 void setvel(dyn * b, real p)
00541
00542
00543
00544
00545 {
00546 static bool init_v33 = false;
00547 static real v33[NG+1];
00548
00549 if (!init_v33) {
00550 for (int i = 0; i <= NG; i++)
00551 v33[i] = scale_fac * pow(((YMAX/NG) * i), 3) / 3;
00552 init_v33 = true;
00553 }
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566 real v = 0;
00567
00568 if (p < -beta_w0) {
00569
00570 real pfac = exp(-p);
00571 real ymax = sqrt(-p-beta_w0);
00572
00573
00574
00575
00576 int il = 0;
00577 int iu = (int)((NG/YMAX) * sqrt(-p));
00578
00579 if (iu > NG) iu = NG;
00580
00581 real rl = 0;
00582 real ru = pfac * g[iu] - v33[iu];
00583
00584 real rno = randinter(0.0, 1.0) * ru;
00585
00586 while (iu - il > 1) {
00587 int im = (il + iu) / 2;
00588 real rm = pfac * g[im] - v33[im];
00589 if (rm > rno) {
00590 iu = im;
00591 ru = rm;
00592 } else {
00593 il = im;
00594 rl = rm;
00595 }
00596 }
00597
00598
00599
00600
00601
00602
00603 v = (YMAX/NG) * sqrt(2.0) * (il + (rno - rl)/(ru - rl));
00604 }
00605
00606
00607
00608 real cth = 2 * randinter(0.0,1.0) - 1;
00609 real sth = sqrt(1 - cth * cth);
00610 real ph = twopi * randinter(0.0, 1.0);
00611 real cph = cos(ph);
00612 real sph = sin(ph);
00613
00614 b->set_vel(vector(v * sth * cph, v * sth * sph, v * cth));
00615 }
00616
00617
00618 local void dump_model_and_exit(int nprof, real mfac = 1, real rfac = 1)
00619 {
00620 real rhofac = mfac/pow(rfac,3);
00621 real pfac = mfac/rfac;
00622 for (int i = 0; i <= nprof; i++)
00623 if (rr[i] > 0 && d[i] > 0)
00624 cerr << i << " "
00625 << log10(rr[i]*rfac) << " "
00626 << log10(d[i]*rhofac) << " "
00627 << log10(-psi[i]*pfac) << " "
00628 << log10(v2[i]*pfac) << " "
00629 << rr[i]*rfac << " "
00630 << d[i]*rhofac << " "
00631 << -psi[i]*pfac << " "
00632 << v2[i]*pfac << " "
00633 << zm[i] << endl;
00634 exit(0);
00635 }
00636
00637
00638 void mkking(dyn * b, int n, real w0, bool n_flag, bool u_flag, int test)
00639
00640
00641
00642
00643 {
00644 int i, iz, j, jcore, jhalf;
00645 real dz, z, rho0;
00646 real rhalf, zmcore;
00647
00648 int nprof;
00649 real v20;
00650
00651 if (w0 > 16) err_exit("mkking: must specify w0 < 16");
00652
00653 initialize_global();
00654
00655
00656
00657 poisson(rr, NM, w0, nprof, v20);
00658
00659 if (test == 1)
00660 dump_model_and_exit(nprof);
00661
00662
00663
00664 rho0 = 1 / zm[nprof];
00665
00666
00667
00668 real sig = sqrt(four3pi * rho0 / 3);
00669
00670
00671
00672
00673 for (i = 0; i <= nprof; i++)
00674 zm[i] = zm[i] / zm[nprof];
00675
00676
00677
00678
00679
00680
00681
00682 indx[0] = 0;
00683 indx[NINDX] = nprof;
00684
00685 dz = 1.0/NINDX;
00686 z = dz;
00687 iz = 1;
00688 for (j = 1; j <= nprof - 1; j++) {
00689 if (rr[j] < 1) jcore = j;
00690 if (zm[j] < 0.5) jhalf = j;
00691 if (zm[j] > z) {
00692 indx[iz] = j - 1;
00693 z = z + dz;
00694 iz = iz + 1;
00695 }
00696 }
00697
00698 zmcore = zm[jcore] + (zm[jcore+1] - zm[jcore]) * (1 - rr[jcore])
00699 / (rr[jcore+1] - rr[jcore]);
00700
00701 rhalf = rr[jhalf] + (rr[jhalf+1] - rr[jhalf])
00702 * (0.5 - zm[jhalf])
00703 / (zm[jhalf+1] - zm[jhalf]);
00704
00705
00706
00707
00708 real kin = 0, pot =0;
00709
00710 for (i = 1; i <= nprof; i++) {
00711 kin += (zm[i] - zm[i-1]) * (v2[i-1] + v2[i]);
00712 pot -= (zm[i] - zm[i-1]) * (zm[i] + zm[i-1]) / (rr[i-1] + rr[i]);
00713 }
00714 kin *= 0.25*sig*sig*v20;
00715
00716 real rvirial = -0.5/pot;
00717
00718 cerr << endl << "King model";
00719 cerr << "\n w0 = " << w0 << " beta = " << beta << " nprof =" << nprof
00720 << " V20/sig2 = " << v20
00721 << " Mc/M = " << zmcore << endl
00722 << " Rt/Rc = " << rr[nprof] << " (c = " << log10(rr[nprof])
00723 << ") Rh/Rc = " << rhalf
00724 << " Rvir/Rc = " << rvirial
00725 << endl
00726 << " Rc/Rvir = " << 1/rvirial
00727 << " Rh/Rvir = " << rhalf/rvirial
00728 << " Rt/Rvir = " << rr[nprof]/rvirial
00729 << "\n\n";
00730
00731 if (test == 2) {
00732
00733
00734
00735 dump_model_and_exit(nprof, rho0, 1/rvirial);
00736 }
00737
00738 if (b == NULL || n < 1) return;
00739
00740
00741
00742 sprintf(tmp_string,
00743 " King model, w0 = %.2f, Rt/Rc = %.3f, Rh/Rc = %.3f, Mc/M = %.3f",
00744 w0, rr[nprof], rhalf, zmcore);
00745 b->log_comment(tmp_string);
00746
00747
00748
00749 putrq(b->get_log_story(), "initial_mass", 1.0);
00750
00751
00752
00753
00754 putrq(b->get_log_story(), "initial_rtidal_over_rvirial",
00755 rr[nprof] / (0.25/kin));
00756
00757
00758
00759
00760 for_all_daughters(dyn, b, bi) {
00761
00762 if (test == 3) {
00763
00764
00765
00766
00767
00768
00769
00770 real nsum = 10000;
00771
00772 for (int zone = 0; zone < 0.95*nprof; zone += nprof/15) {
00773 real v2sum = 0;
00774 real v2max = 0;
00775 for (int jj = 0; jj < nsum; jj++) {
00776 setvel(bi, psi[zone]);
00777 real vsq = bi->get_vel()*bi->get_vel();
00778 v2sum += vsq;
00779 v2max = max(v2max, vsq);
00780 }
00781
00782 cerr << "zone " << zone << " r = " << rr[zone]
00783 << " v2max = " << v2max<< " ?= " << -2*psi[zone]
00784 << " v2mean = " << v2sum/nsum << " ?= " << v2[zone]*v20
00785 << endl;
00786 }
00787
00788 exit(0);
00789
00790 }
00791
00792 if (n_flag)
00793 bi->set_mass(1.0/n);
00794
00795 real p;
00796 setpos(bi, p);
00797 setvel(bi, p);
00798
00799
00800
00801
00802 bi->scale_vel(sig);
00803
00804 }
00805
00806
00807
00808
00809
00810
00811
00812 b->to_com();
00813
00814 if (!u_flag && n > 1) {
00815
00816 real kinetic, potential;
00817
00818 get_top_level_energies(b, 0.0, potential, kinetic);
00819 scale_virial(b, -0.5, potential, kinetic);
00820 real energy = kinetic + potential;
00821 scale_energy(b, -0.25, energy);
00822
00823 putrq(b->get_dyn_story(), "initial_total_energy", -0.25);
00824 putrq(b->get_log_story(), "initial_rvirial", 1.0);
00825
00826 }
00827 }
00828
00829 main(int argc, char ** argv)
00830 {
00831 int n;
00832 int input_seed, actual_seed;
00833
00834 bool c_flag = false;
00835 bool i_flag = false;
00836 bool n_flag = false;
00837 bool o_flag = false;
00838 bool s_flag = false;
00839 bool w_flag = false;
00840 bool u_flag = false;
00841
00842 check_help();
00843
00844 int test = 0;
00845
00846 real w0;
00847
00848 char *comment;
00849
00850 extern char *poptarg;
00851 int c;
00852 char* param_string = "b:c:in:os:T:uw:";
00853
00854 while ((c = pgetopt(argc, argv, param_string)) != -1)
00855 switch(c) {
00856 case 'b': beta = atof(poptarg);
00857 break;
00858 case 'c': c_flag = true;
00859 comment = poptarg;
00860 break;
00861 case 'i': i_flag = true;
00862 break;
00863 case 'n': n_flag = true;
00864 n = atoi(poptarg);
00865 break;
00866 case 'o': o_flag = true;
00867 break;
00868 case 's': s_flag = true;
00869 input_seed = atoi(poptarg);
00870 break;
00871 case 'T': test = atoi(poptarg);
00872 break;
00873 case 'u': u_flag = true;
00874 break;
00875 case 'w': w_flag = true;
00876 w0 = atof(poptarg);
00877 break;
00878 case '?': params_to_usage(cerr, argv[0], param_string);
00879 get_help();
00880 }
00881
00882 if (!w_flag) {
00883 cerr << "mkking: please specify the dimensionless depth";
00884 cerr << " with -w #\n";
00885 exit(1);
00886 }
00887
00888 if (beta >= 1) {
00889 cerr << "mkking: beta < 1 required\n";
00890 exit(1);
00891 }
00892
00893 beta_w0 = beta*w0;
00894 scale_fac = exp(beta_w0);
00895
00896
00897
00898
00899
00900
00901
00902 dyn *b = NULL;
00903
00904 if (!n_flag) {
00905
00906 b = get_dyn(cin);
00907 n = b->n_leaves();
00908
00909 if (n < 1)
00910 err_exit("mkking: n > 0 required");
00911
00912 cerr << "mkking: read " << n << " masses from input snapshot with"
00913 << endl;
00914 }
00915 else {
00916
00917 if (n < 1)
00918 err_exit("mkking: n > 0 required");
00919
00920 b = new dyn();
00921 dyn *by, *bo;
00922
00923 bo = new dyn();
00924 if (i_flag)
00925 bo->set_label(1);
00926 b->set_oldest_daughter(bo);
00927 bo->set_parent(b);
00928
00929 for (int i = 1; i < n; i++) {
00930 by = new dyn();
00931 if (i_flag)
00932 by->set_label(i+1);
00933 by->set_parent(b);
00934 bo->set_younger_sister(by);
00935 by->set_elder_sister(bo);
00936 bo = by;
00937 }
00938
00939 }
00940 if (c_flag)
00941 b->log_comment(comment);
00942 b->log_history(argc, argv);
00943
00944 if (s_flag == false) input_seed = 0;
00945 actual_seed = srandinter(input_seed);
00946
00947 if (o_flag)
00948 cerr << "mkking: random seed = " << actual_seed << endl;
00949
00950 sprintf(tmp_string,
00951 " random number generator seed = %d",
00952 actual_seed);
00953 b->log_comment(tmp_string);
00954
00955 mkking(b, n, w0, n_flag, u_flag, test);
00956
00957 put_node(cout, *b);
00958 }
00959
00960 #endif
00961
00962