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