00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
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);
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);
00034 return pot;
00035 }
00036
00037
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
00059
00060
00061
00062
00063 int fac = (r1 < r2);
00064 fac = 2*fac - 1;
00065 r1 *= 1 + fac*EPS_R;
00066 r2 *= 1 - fac*EPS_R;
00067
00068 real dr = 0.01 * (r2 - r1);
00069
00070
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
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
00099
00100 r = r1 + (r2-r1)*(0-g1)/(g2-g1);
00101
00102 return r;
00103 }
00104
00105 local void get_rL(dyn *b,
00106 real M,
00107 vector center,
00108 real& r_L1,
00109 real& r_L2)
00110 {
00111
00112
00113
00114
00115 ext_center = b->get_external_center();
00116 R = abs(center - ext_center);
00117 Rhat = (center - ext_center)/(R*M);
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
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)
00139 {
00140 unsigned int ext = b->get_external_field();
00141
00142 if (!ext || b->get_tidal_field()) return;
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154 if (bitcount(ext) != 1) return;
00155
00156
00157
00158 if (b->get_ignore_internal()) return;
00159
00160
00161
00162
00163 if (verbose == 0
00164 && getrq(b->get_dyn_story(), "bound_center_time")
00165 == b->get_system_time())
00166 return;
00167
00168
00169
00170
00171 vector center, vcenter;
00172 get_std_center(b, center, vcenter);
00173
00174
00175
00176
00177 real M_inside = 0;
00178 R = abs(center - b->get_external_center());
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;
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
00199
00200
00201
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
00212
00213 M = M_inside;
00214 center = cen;
00215 vcenter = vcen;
00216
00217
00218
00219 M_inside = 0;
00220 N_inside = 0;
00221 cen = vcen = 0;
00222
00223
00224
00225
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
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
00240
00241 phi_lim = max(phi_L1, phi_L2);
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
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
00292
00293
00294 bool disrupted = (M_inside < 0.01*M0);
00295
00296 if (disrupted) {
00297
00298
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
00320
00321
00322
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
00329
00330
00331
00332 set_friction_mass(M_inside);
00333 set_friction_vel(vcenter);
00334 set_friction_acc(b, abs(center));
00335
00336
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
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
00356
00357 if (!escaper && find_qmatch(bb->get_dyn_story(), "t_esc"))
00358 rmq(bb->get_dyn_story(), "t_esc");
00359
00360
00361
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 }