Main Page   Class Hierarchy   Data Structures   File List   Data Fields   Globals  

makeking.C

Go to the documentation of this file.
00001 
00002        //=======================================================//    _\|/_
00003       //  __  _____           ___                    ___       //      /|\ ~
00004      //  /      |      ^     |   \  |         ^     |   \     //          _\|/_
00005     //   \__    |     / \    |___/  |        / \    |___/    //            /|\ ~
00006    //       \   |    /___\   |  \   |       /___\   |   \   // _\|/_
00007   //     ___/   |   /     \  |   \  |____  /     \  |___/  //   /|\ ~
00008  //                                                       //            _\|/_
00009 //=======================================================//              /|\ ~
00010 
00032 
00033 // version 1:  June 1997    Kimberly Engle
00034 //                          email: kim@galileo.physics.drexel.edu
00035 //                          Physics Dept., Drexel University, Phila PA USA
00036 //
00037 //             Adapted from S. McMillan's FORTRAN version to the new
00038 //             C++-based Starlab.
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 // Global stuff:
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 // FORTRAN common blocks...
00064 
00065 // parameter
00066 #define  NM     2500
00067 
00068 // profile
00069 real rr[NM+1], d[NM+1], v2[NM+1], psi[NM+1], zm[NM+1];
00070 
00071 // Convenient to keep these global (for now):
00072 
00073 // Array indx is used in setpos and mkking
00074 //              [indexes the mass distribution of the initial model],
00075 //    "    g  is used in gg and setvel
00076 //              [contains the indefinite integral of y^2 exp(-y^2) dy].
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 // Rescaling factors:
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 // Integrate func from a to b in n steps, using the trapezoid rule.
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 // Trapezoid Rule for integration. Tricky code from Numerical Recipes...
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 // Array g contains the indefinite integral (from 0) of y^2 exp(-y^2) dy,
00171 // up to a maximum value of YMAX, i.e.
00172 //
00173 //      g[i]  =  integral{0 to Y} y^2 exp(-y^2) dy,
00174 //
00175 // where Y  =  i*YMAX/NG (i = 0,...,NG).
00176 //
00177 // Function computes  g2  =  integral{0 to y} y^2 exp(-y^2) dy
00178 //               and  g4  =  integral{0 to y} y^4 exp(-y^2) dy.
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 // Return density d and local velocity dispersion v2,
00199 // given scaled potential psi (< 0).
00200 
00201 {
00202   dens = 0;
00203   if (psi >= -beta_w0) return;
00204 
00205   // Distribution function is
00206   //
00207   //    f(r,v) = A exp(-psi) (exp(-v^2 / 2 sig^2) - exp(psi - beta*psi0)),
00208   //
00209   // where psi = phi/sig^2 and psi0 = -w0.
00210   //
00211   // Density is the integral of 4 pi v^2 f, velocity dispersion v2
00212   // is (integral of 4 pi v^4 f) / density.
00213 
00214   real g2, g4 = v2;
00215 
00216   real p_max = -psi - beta_w0;          // v_max^2 / (2 sig^2)
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   // Note that this expression for dens excludes an overall factor
00226   // of 8 pi sqrt(2) sig^3 A.  Scaling to the central density
00227   // is handled elsewhere (in rhs).
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   // The unit of v2 is sig^2.
00233 
00234 }
00235 
00236 real dc_inverse;        // Convenient to keep this global, for now.
00237                         // Set in poisson, used for scaling in rhs.
00238 
00239 void rhs(real y[], real x, real ypr[])
00240 
00241 //  Define RHS of ODE, for use by rk4.
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);        // d is rho/rho_0
00255                                                 // zero suppresses vel
00256       d = d * dc_inverse;
00257   }
00258 
00259   ypr[1] = 9 * x * d;
00260 
00261 }
00262 
00263 //  Runge-Kutta-4 method 
00264 
00265 void step(real y[], real& x, real dx, int N)
00266 
00267 // Runge-Kutta-4 integrator.
00268 
00269 { 
00270     int i;
00271 
00272     // DEC C++ doesn't like these declarations with variable N:
00273 
00274     // real dydx[N], dy1[N], dy2[N], dy3[N], dy4[N],
00275     //               y1[N],  y2[N],  y3[N],  y4[N];
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)              // NOTE!!  Beware of rounding error!
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 // Integrate the y(x) from x to x_next, using an integration step of dx.
00323 // On entry y is y at the initial x.  On exit, x is replaced by x_next
00324 // and y is y(x).
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 //       Self-contained 1-D (spherical) Poisson's equation solver.
00338 //       Currently knows about normal and lowered King models.
00339 //
00340 //        Input:  nmax is the maximum number of points allowed
00341 //                w0 is the dimensionless central potential
00342 //                iout allows messages if nonzero
00343 
00344 //        Output: x   is scaled radius (r/rc)
00345 //                d   is scaled density (1 at center)
00346 //                v2  is scaled velocity dispersion (1 at center)
00347 //                psi is scaled potential (-W0 at center)
00348 //                zm  is cumulative mass (scaling from x, d scalings)
00349 //                nprof is the actual number of points generated
00350 //                v20 is the central 3-D velocity dispersion (unit = sig^2)
00351 
00352 {
00353 
00354   int i, iflag2; 
00355   real psi0, xn, xo, fac;
00356   real y[2];
00357 
00358   psi0 = - abs(w0);
00359 
00360   // Initialize at center of cluster.
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   // Establish density scaling factor.
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 //      Poisson's equation is:
00378 //
00379 //              (1/r^2) d/dr (r^2 dphi/dr)  =  4 pi G rho,
00380 //
00381 //      where r is radius, phi is potential, and rho is density, given
00382 //      (for equal-mass stars) by
00383 //
00384 //              rho     =  {integral (v < ve)} 4 pi v^2 f(v) dv,
00385 //
00386 //      where ve is the escape velocity,
00387 //
00388 //              ve^2    =  -2 phi.
00389 //
00390 //      The (3-D) velocity distribution is
00391 //
00392 //              f(v)    =  A (exp(-v^2 / 2 sig^2)
00393 //                                       - exp(-ve^2 / 2 sig^2)),
00394 //
00395 //      where sig^2 is a 1-D velocity dispersion (not quite the
00396 //      central velocity dispersion, except in the limit of infinite
00397 //      central potential).  In King's (1966) paper, he uses
00398 //      j^2 = 1 / (2 sig^2).
00399 //
00400 //      Following King, we define the core radius rc by
00401 //
00402 //              rc^2    =  9 sig^2 / (4 pi G rho0)
00403 //
00404 //      and the dimensionless depth as
00405 //
00406 //              W0      =  -phi0 / sig^2,
00407 //
00408 //      where rho0 and phi0 are the central density and potential,
00409 //      respectively.
00410 //
00411 //      We then scale as follows:
00412 //
00413 //              x       =  r / rc
00414 //
00415 //              d       =  rho / rho0
00416 //
00417 //              psi     =  phi / sig^2,
00418 //
00419 //      to obtain
00420 //
00421 //              (x psi)''  =  9 x d,
00422 //
00423 //      where ' = d/dx.
00424 //
00425 //      We integrate this ODE from the cluster center (x = 0, d = 1,
00426 //      psi = -W0) to the tidal radius (d = 0) by defining
00427 //
00428 //              y(0)    =  (x psi)
00429 //              y(1)    =  y(0)'
00430 //
00431 //      We cover the first RLIN core radii linearly with NLIN points;
00432 //      the remaining coverage is logarithmic, out to RMAX core radii,
00433 //      if necessary.  We stop when d <= 0.
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       //  N.B. Remember that y(1) is x*psi and xo is updated by step.
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         // Density is negative, calculation is over.
00462         // Interpolate to the tidal radius.
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           // Strange syntax because d = NaN (because of earlier error)
00475           // will test FALSE in "if (d < 0)".
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   // Scale d and v2 to their central values.  Save v20 (unit = sig^2).
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 // Obtain a random position for body b from the King profile
00506 // and return the scaled potential at that location.
00507 
00508 {
00509   //  Choose radius randomly from the mass distribution.
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   //  Angular position random.
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 // Obtain a random velocity for body b from the King profile
00543 // given its scaled potential p.
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     // Array v33[] contains the second term in the integral for the density,
00556     // namely exp(beta*W0) * v_esc^3 / 3 (scaling v^2 by 2 sig^2, as usual).
00557     // As with g[], the array indices run from 0 to NG, spanning a range 0 to
00558     // YMAX, i.e. the cumulative distribution function for v is
00559     //
00560     //          exp(-p) * g[i] - v33[i],
00561     //
00562     // where y = i*YMAX/NG (i = 0,...,NG) and v = sqrt(2)*sig*y (sig = 1 here).
00563 
00564     //  Choose speed randomly from the distribution at this radius.
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         // Will obtain v by bisection.  Determine maximum possible
00574         // range in the index i.
00575 
00576         int il = 0; 
00577         int iu = (int)((NG/YMAX) * sqrt(-p));   // Binning OK for W0 < 16,
00578                                                 // *only* if beta >= 0.
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         // Maximum possible range of il here (for beta = 0) is
00599         //      0 to NG*sqrt(-p)/YMAX.
00600         // Maximum possible value of v (for beta = 0) is the local
00601         //      escape speed, sqrt(-2*p).
00602 
00603         v = (YMAX/NG) * sqrt(2.0) * (il + (rno - rl)/(ru - rl));
00604     }
00605 
00606     //  Direction is random.
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;              // zm is scaled to unit mass
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 // Create a King model, and optionally initialize an N-body system
00641 // with total mass = n, core radius = 1.
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     // Compute the cluster density/velocity/potential profile
00656     
00657     poisson(rr, NM, w0, nprof, v20);
00658 
00659     if (test == 1)
00660         dump_model_and_exit(nprof);
00661 
00662     // Determine statistics and characteristic scales of the King model.
00663 
00664     rho0 = 1 / zm[nprof];                // Central density for total mass = 1
00665 
00666     // Unit of velocity = sig, where rc^2 = 9 sig^2 / (4 pi G rho0)
00667 
00668     real sig = sqrt(four3pi * rho0 / 3); // This 3 was v20 in the f77 version...
00669                                          // v20 is central vel. disp. / sig^2
00670 
00671     // Scale the zm array to unit total mass.
00672 
00673     for (i = 0; i <= nprof; i++)
00674         zm[i] = zm[i] / zm[nprof];
00675 
00676     // Index the mass distribution, and determine the core mass and
00677     // the half-mass radius.
00678 
00679     // By construction, rr[indx[j]] and rr[indx[j+1]] bracket the
00680     // radius containing a fraction j / NINDX of the total mass.
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     // Compute the kinetic and potential energies, and determine the
00706     // virial radius and ratio.
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 // << "  -T/U = " << -kin/pot
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         // Scaling factors are for Mtotal = 1, Rvir = 1:
00734 
00735         dump_model_and_exit(nprof, rho0, 1/rvirial);
00736     }
00737 
00738     if (b == NULL || n < 1) return;
00739 
00740     // Initialize the N-body system.
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     // Write essential model information to root dyn story.
00748 
00749     putrq(b->get_log_story(), "initial_mass", 1.0);
00750 
00751     // putrq(b->get_log_story(), "initial_rvirial", 0.25/kin); // assumes a lot!
00752                                                                // -- too much...
00753 
00754     putrq(b->get_log_story(), "initial_rtidal_over_rvirial",
00755           rr[nprof] / (0.25/kin));
00756 
00757     // Assign positions and velocities. Note that it may actually
00758     // be preferable to do this in layers instead.
00759 
00760     for_all_daughters(dyn, b, bi) {
00761 
00762         if (test == 3) {
00763 
00764             // Test: For a pure King model, getvel should generate a
00765             //       distribution of velocities with maximum speed
00766             //       sqrt(-2*p) and <v^2> = v2*v20, where p and v2
00767             //       are the scaled potential and mean-square
00768             //       velocity at any given radius.
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         // Unit of length = rc.
00800         // Unit of velocity = sig.
00801 
00802         bi->scale_vel(sig);
00803 
00804     }
00805 
00806     // System is in virial equilibrium in a consistent set of units
00807     // with G, core radius, and total mass = 1.
00808 
00809     // Transform to center-of-mass coordinates and optionally
00810     // scale to standard parameters.
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);      // scales kinetic
00820         real energy = kinetic + potential;
00821         scale_energy(b, -0.25, energy);                 // scales 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;                  // global variables!
00894     scale_fac = exp(beta_w0);
00895 
00896 //    if (!n_flag && test != 1 && test != 2) {
00897 //        cerr << "mkking: please specify the number # of";
00898 //        cerr << " particles with -n #\n";
00899 //        exit(1);
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);                // add comment to story
00942     b->log_history(argc, argv);
00943     
00944     if (s_flag == false) input_seed = 0;        // default
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 /* end of: mkking.C */  

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