Main Page   Class Hierarchy   Data Structures   File List   Data Fields   Globals  

refine_mass2.C

Go to the documentation of this file.
00001 
00002        //=======================================================//    _\|/_
00003       //  __  _____           ___                    ___       //      /|\ ~
00004      //  /      |      ^     |   \  |         ^     |   \     //          _\|/_
00005     //   \__    |     / \    |___/  |        / \    |___/    //            /|\ ~
00006    //       \   |    /___\   |  \   |       /___\   |   \   // _\|/_
00007   //     ___/   |   /     \  |   \  |____  /     \  |___/  //   /|\ ~
00008  //                                                       //            _\|/_
00009 //=======================================================//              /|\ ~
00010 
00011 // refine_mass2.C:  More careful determination of cluster mass and center,
00012 //                  for use with an external non-tidal field.
00013 //                  Also flag escapers.
00014 //
00015 // Externally visible functions:
00016 //
00017 //      void refine_cluster_mass2
00018 
00019 #include "dyn.h"
00020 
00021 local inline vector ext_acc(dyn *b, vector pos)
00022 {
00023     vector v = 0, acc, j;
00024     real p;
00025     get_external_acc(b, pos, v, p, acc, j);             // (discard p and j)
00026     return acc;
00027 }
00028 
00029 local inline real ext_pot(dyn *b, vector pos)
00030 {
00031     vector v = 0, a, j;
00032     real pot;
00033     get_external_acc(b, pos, v, pot, a, j, true);       // (discard a and j)
00034     return pot;
00035 }
00036 
00037 // Handy, for now...
00038 
00039 static vector ext_center, Rhat, acc_CM;
00040 static real R;
00041 
00042 local real g1(dyn *b, real r)
00043 {
00044     vector pos = ext_center + r*Rhat;
00045     return (ext_acc(b, pos) - acc_CM) * Rhat + pow(r-R, -2);
00046 }
00047 
00048 local real g2(dyn *b, real r)
00049 {
00050     vector pos = ext_center + r*Rhat;
00051     return (ext_acc(b, pos) - acc_CM) * Rhat - pow(r-R, -2);
00052 }
00053 
00054 #define EPS_R 1.e-4
00055 
00056 local inline real solve(real (*g)(dyn*, real), dyn *b, real r1, real r2)
00057 {
00058     // Return the root of g(r) = 0 (if any) between r1 and r2.
00059     // Avoid evaluation of g at r1 or r2.  Start the search at r2,
00060     // proceed toward r1 (could have r1 > r2), and return the first
00061     // zero found.
00062 
00063     int fac = (r1 < r2);
00064     fac = 2*fac - 1;            // = +1 if r1 < r2, -1 otherwise
00065     r1 *= 1 + fac*EPS_R;
00066     r2 *= 1 - fac*EPS_R;
00067 
00068     real dr = 0.01 * (r2 - r1);
00069 
00070     // Search for a zero, starting at r2.
00071 
00072     real g2 = g(b, r2);
00073     real r = r2 - dr;
00074     while (fac*(r - r1) >= 0 && g(b, r)*g2 > 0) r -= dr;
00075 
00076     if (fac*(r - r1) < 0) return r;
00077 
00078     // Refine by bisection.
00079 
00080     r1 = r;
00081     r2 = r + dr;
00082     real g1 = g(b, r1);
00083     g2 = g(b, r2);
00084 
00085     while (abs(r2/r1 - 1) < EPS_R) {
00086         r = 0.5*(r1+r2);
00087         real gr = g(b, r);
00088         if (gr == 0) return r;
00089         if (gr*g1 > 0) {
00090             r1 = r;
00091             g1 = gr;
00092         } else {
00093             r2 = r;
00094             g2 = gr;
00095         }
00096     }
00097 
00098     // Final refinement by linear interpolation.
00099 
00100     r = r1 + (r2-r1)*(0-g1)/(g2-g1);
00101 
00102     return r;
00103 }
00104 
00105 local void get_rL(dyn *b,               // root node
00106                   real M,               // current mass estimate
00107                   vector center,        // current center estimate
00108                   real& r_L1,
00109                   real& r_L2)
00110 {
00111     // Find the inner Lagrangian point in the external field.
00112     // Construction of the external field functions is such that
00113     // it is just as easy to work directly with 3-D vectors...
00114 
00115     ext_center = b->get_external_center();
00116     R = abs(center - ext_center);
00117     Rhat = (center - ext_center)/(R*M); // factor of M avoids passing M to g
00118     acc_CM = ext_acc(b, center);
00119 
00120     r_L1 = solve(g1, b, sqrt(b->get_external_scale_sq()), R);
00121     r_L2 = solve(g2, b, R, 10*R);
00122 }
00123 
00124 local int bitcount(unsigned int i)
00125 {
00126     // Count nonzero bits.  From K&R.
00127 
00128     int b;
00129     for (b = 0; i != 0; i >>= 1)
00130         if (i & 01) b++;
00131     return b;
00132 }
00133 
00134 #define M_TOL 1.e-4
00135 #define M_ITER_MAX 20
00136 
00137 void refine_cluster_mass2(dyn *b,
00138                           int verbose)          // default = 0
00139 {
00140     unsigned int ext = b->get_external_field();
00141 
00142     if (!ext || b->get_tidal_field()) return;
00143 
00144     // Self-consistently determine the total mass within the outermost
00145     // closed zero-velocity surface under the specified external field(s).
00146     // Use a point-mass approximation for the cluster potential and iterate
00147     // until the actual mass within the surface agrees with the mass used
00148     // to generate the surface.
00149     //
00150     // Experimental code, implemented by Steve, 8/01.
00151 
00152     // Method only works for a single external, velocity-independent field...
00153 
00154     if (bitcount(ext) != 1) return;
00155 
00156     // Quit if internal forces are to be neglected.
00157 
00158     if (b->get_ignore_internal()) return;
00159 
00160     // Do nothing if all we want is to set the dyn story and the current
00161     // values are up to date.
00162 
00163     if (verbose == 0
00164         && getrq(b->get_dyn_story(), "bound_center_time")
00165                 == b->get_system_time())
00166         return;
00167 
00168     // Use the standard center as our starting point.  The center will be
00169     // redetermined self-consistently, along with the mass.
00170 
00171     vector center, vcenter;
00172     get_std_center(b, center, vcenter);
00173 
00174     // Choose the initial mass to include only the volume between the
00175     // standard center and the center of the external potential.
00176 
00177     real M_inside = 0;
00178     R = abs(center - b->get_external_center());         // global R
00179 
00180     for_all_daughters(dyn, b, bb)
00181         if (abs(bb->get_pos() - center) <= R)
00182             M_inside += bb->get_mass();
00183 
00184     real M = -1;                                        // (to start the loop)
00185     int N_inside;
00186     vector cen = center, vcen = vcenter;
00187 
00188     if (verbose) {
00189         cerr << endl << "  refine_cluster_mass2: getting mass by iteration"
00190              << endl << "  initial total system mass = " << M_inside
00191              << endl << "  initial center = " << center
00192              << endl;
00193     }
00194 
00195     int iter = 0;
00196     real r_L = 0, phi_lim = 0;
00197 
00198     // Iteration can (should!) run away to zero mass if the cluster
00199     // density is too low relative to the local tidal field strength.
00200     // Keep track of the "50% center of mass" during the iteration as
00201     // a convenient measure of the cluster center in this case.
00202 
00203     real M0 = M_inside;
00204     vector cen50 = center, vcen50 = vcenter;
00205     bool set50 = false;
00206 
00207     while (iter++ < M_ITER_MAX
00208            && M_inside > 0
00209            && abs(M_inside/M - 1) > M_TOL) {
00210 
00211         // Set current mass and center:
00212 
00213         M = M_inside;
00214         center = cen;
00215         vcenter = vcen;
00216 
00217         // Reinitialize:
00218 
00219         M_inside = 0;
00220         N_inside = 0;
00221         cen = vcen = 0;
00222 
00223         // Determine the Lagrangian points of the (point-mass) cluster
00224         // in the external field, then count stars within the limiting
00225         // equipotential.
00226 
00227         real r_L1, r_L2;
00228         get_rL(b, M, center, r_L1, r_L2);
00229 
00230         if (verbose > 1) {
00231             cerr << endl;
00232             PRC(R); PRC(r_L1); PRC(r_L2);
00233         }
00234 
00235         // Limiting potential:
00236 
00237         real phi_L1 = ext_pot(b, ext_center + r_L1*Rhat) - M/(R-r_L1);
00238         real phi_L2 = ext_pot(b, ext_center + r_L2*Rhat) - M/(r_L2-R);
00239         // PRC(phi_L1); PRC(phi_L2);
00240 
00241         phi_lim = max(phi_L1, phi_L2);          // maximize the cluster mass
00242         r_L = max(R-r_L1, r_L2-R);
00243 
00244         if (verbose > 1) PRL(r_L);
00245 
00246         for_all_daughters(dyn, b, bb) {
00247             real r = abs(bb->get_pos() - center);
00248             if (r < r_L) {
00249                 if (r == 0
00250                     || -M/r + ext_pot(b, bb->get_pos()) < phi_lim) {
00251                     N_inside++;
00252                     M_inside += bb->get_mass();
00253                     cen += bb->get_mass()*bb->get_pos();
00254                     vcen += bb->get_mass()*bb->get_vel();
00255                 }
00256             }
00257         }
00258 
00259         if (M_inside > 0) {
00260             cen /= M_inside;
00261             vcen /= M_inside;
00262         }
00263 
00264         // Linearly interpolate an estimate of the "50% center."
00265 
00266         if ((M > 0.5*M0 && M_inside <= 0.5*M0)
00267             || (M < 0.5*M0 && M_inside >= 0.5*M0)) {
00268             cen50 = center + (0.5*M0-M)*(cen-center)/(M_inside-M);
00269             vcen50 = vcenter + (0.5*M0-M)*(vcen-vcenter)/(M_inside-M);
00270             set50 = true;
00271         }
00272 
00273         if (verbose > 1) {
00274             PRI(2); PRC(iter); PRC(N_inside); PRL(M_inside);
00275             PRI(2); PRL(cen);
00276         }
00277     }
00278 
00279     if (iter >= M_ITER_MAX) {
00280         if (verbose) PRI(2);
00281         cerr << "warning: refine_cluster_mass: too many iterations at time "
00282              << b->get_system_time() << endl;
00283     }
00284 
00285     if (verbose == 1) {
00286         PRI(2); PRC(iter); PRC(N_inside); PRL(M_inside);
00287         PRI(2); PRL(cen);
00288         PRI(2); PRL(vcen);
00289     }
00290 
00291     // Too many iterations probably means a limit cycle of some sort;
00292     // accept the results in that case.
00293 
00294     bool disrupted = (M_inside < 0.01*M0);
00295 
00296     if (disrupted) {
00297 
00298         // Looks like the cluster no longer exists.  Use 50% or ext center.
00299 
00300         if (set50) {
00301             center = cen50;
00302             vcenter = vcen50;
00303         } else {
00304             center = ext_center;
00305             vcenter = 0;
00306         }
00307 
00308         if (verbose) {
00309             PRI(2); PRL(center);
00310             PRI(2); PRL(vcenter);
00311         }
00312 
00313     } else {
00314 
00315         center = cen;
00316         vcenter = vcen;
00317     }
00318 
00319     // Now center and vcenter should be usable, even if M_inside and
00320     // N_inside aren't very meaningful.
00321 
00322     // Write our best estimate of the center to the dyn story.
00323 
00324     putrq(b->get_dyn_story(), "bound_center_time", (real)b->get_system_time());
00325     putvq(b->get_dyn_story(), "bound_center_pos", center);
00326     putvq(b->get_dyn_story(), "bound_center_vel", vcenter);
00327 
00328     // Send the relevant data to the dynamical friction code, and compute
00329     // the current frictional acceleration.  Could combine these calls, but
00330     // keep as is for now.
00331 
00332     set_friction_mass(M_inside);
00333     set_friction_vel(vcenter);
00334     set_friction_acc(b, abs(center));
00335 
00336     // Repeat the inner loop above and flag stars as escapers or not.
00337 
00338     int n_mem = 0;
00339     for_all_daughters(dyn, b, bb) {
00340         bool escaper = true;
00341         if (!disrupted) {
00342             real r = abs(bb->get_pos() - center);
00343             if (r < r_L
00344                 && (r == 0 || -M/r + ext_pot(b, bb->get_pos()) < phi_lim))
00345                 escaper = false;
00346         }
00347         putiq(bb->get_dyn_story(), "esc", escaper);
00348         if (!escaper) n_mem++;
00349 
00350         // Print out t_esc if this is a new escaper.
00351 
00352         if (escaper && !find_qmatch(bb->get_dyn_story(), "t_esc"))
00353             putrq(bb->get_dyn_story(), "t_esc", (real)b->get_system_time());
00354 
00355         // Delete t_esc if this is not an escaper.
00356 
00357         if (!escaper && find_qmatch(bb->get_dyn_story(), "t_esc"))
00358             rmq(bb->get_dyn_story(), "t_esc");
00359 
00360         // Note that the esc flag is redundant -- all necessary
00361         // information is contained in the t_esc line.
00362     }
00363 
00364 #if 0
00365     if (verbose) PRI(2);
00366     cerr << "refine_mass2: "; PRC(b->get_system_time()); PRL(n_mem);
00367 #endif
00368 
00369 }

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