00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #include "dyn.h"
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050 local inline void add_tidal(dyn * b,
00051 vector pos,
00052 vector vel,
00053 real& pot,
00054 vector& acc,
00055 vector& jerk,
00056 bool pot_only)
00057 {
00058
00059
00060
00061 real a1 = b->get_alpha1();
00062 if (a1 == 0) return;
00063
00064 real a3 = b->get_alpha3();
00065
00066 vector dx = pos - b->get_tidal_center();
00067
00068 if (!pot_only) {
00069
00070 vector da_tidal_centrifugal = -vector(a1*dx[0], 0.0, a3*dx[2]);
00071 vector da_coriolis = 2 * b->get_omega()
00072 * vector(vel[1], -vel[0], 0.0);
00073
00074
00075
00076 acc += da_tidal_centrifugal + da_coriolis;
00077
00078 vector dj_tidal_centrifugal = -vector(a1*vel[0], 0.0, a3*vel[2]);
00079 vector dj_coriolis = 2 * b->get_omega()
00080 * vector(acc[1], -acc[0], 0.0);
00081
00082 jerk += dj_tidal_centrifugal + dj_coriolis;
00083 }
00084
00085 real x = dx[0];
00086 real z = dx[2];
00087
00088 pot += 0.5*(a1*x*x + a3*z*z);
00089 }
00090
00091 local inline real tidal_pot(dyn * b)
00092 {
00093
00094
00095
00096
00097
00098
00099 real a1 = b->get_alpha1();
00100 if (a1 == 0) return 0;
00101
00102 real a3 = b->get_alpha3();
00103
00104 real dpot = 0;
00105 for_all_daughters(dyn, b, bb) {
00106 real x = bb->get_pos()[0] - b->get_tidal_center()[0];
00107 real z = bb->get_pos()[2] - b->get_tidal_center()[0];
00108 real dp = a1*x*x + a3*z*z;
00109 dpot += bb->get_mass() * dp;
00110 }
00111
00112 return 0.5*dpot;
00113 }
00114
00115
00116
00117
00118
00119 local inline void add_plummer(dyn * b,
00120 vector pos,
00121 vector vel,
00122 real& pot,
00123 vector& acc,
00124 vector& jerk,
00125 bool pot_only)
00126 {
00127
00128
00129
00130 real M = b->get_p_mass();
00131 if (M == 0) return;
00132
00133 real a2 = b->get_p_scale_sq();
00134
00135 vector dx = pos - b->get_p_center();
00136 real r2 = square(dx) + a2;
00137 real r1 = sqrt(r2);
00138
00139 if (!pot_only) {
00140 real r3i = 1/(r1*r2);
00141 acc -= M*dx*r3i;
00142 jerk += M*(3*dx*(dx*vel)/r2 - vel)*r3i;
00143 }
00144
00145 pot -= M/r1;
00146 }
00147
00148 local inline real plummer_pot(dyn * b)
00149 {
00150
00151
00152
00153 real M = b->get_p_mass();
00154 if (M == 0) return 0;
00155
00156 real a2 = b->get_p_scale_sq();
00157
00158 real dpot = 0;
00159 for_all_daughters(dyn, b, bb) {
00160 vector dx = bb->get_pos() - bb->get_p_center();
00161 real r2 = square(dx) + a2;
00162 dpot += bb->get_mass() / sqrt(r2);
00163 }
00164
00165 return -M*dpot;
00166 }
00167
00168 local inline real plummer_virial(dyn * b)
00169 {
00170
00171
00172
00173 real M = b->get_p_mass();
00174 if (M == 0) return 0;
00175
00176 real a2 = b->get_p_scale_sq();
00177
00178
00179
00180
00181 vector com_pos, com_vel;
00182 compute_com(b, com_pos, com_vel);
00183
00184
00185 vector dR = com_pos - b->get_p_center();
00186 vector acc_com = dR * pow(square(dR)+a2, -1.5);
00187
00188
00189
00190
00191
00192 real vir = 0;
00193 for_all_daughters(dyn, b, bb) {
00194 vector dr = bb->get_pos() - com_pos;
00195 dR = bb->get_pos() - b->get_p_center();
00196 vector acc_ext = dR * pow(square(dR)+a2, -1.5);
00197 real dvir = bb->get_mass()*dr*(acc_ext - acc_com);
00198
00199 vir += dvir;
00200 }
00201
00202
00203 return -M*vir;
00204 }
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233 static real beta = 0;
00234 void set_friction_beta(real b) {beta = b;}
00235
00236 static real Mfric = 0;
00237 void set_friction_mass(real m) {Mfric = m;}
00238
00239 static vector Vcm = 0;
00240 void set_friction_vel(vector v) {Vcm = v;}
00241
00242 local real density(dyn *b, real r)
00243 {
00244 real A = b->get_pl_coeff();
00245 if (A == 0) return 0;
00246
00247 real a2 = b->get_pl_scale_sq();
00248 real x = b->get_pl_exponent();
00249
00250 return A*x*pow(r*r+a2, 0.5*(x-1))/(4*M_PI*r*r);
00251 }
00252
00253 local real mass(dyn *b, real r)
00254 {
00255 real A = b->get_pl_coeff();
00256 if (A == 0) return 0;
00257
00258 real a2 = b->get_pl_scale_sq();
00259 real x = b->get_pl_exponent();
00260
00261 return A*pow(r*r+a2, 0.5*x);
00262 }
00263
00264 #define LAMBDA_FAC 1
00265
00266 local real logLambda(dyn *b, real r)
00267 {
00268 real mass_unit = -1;
00269 if (b->get_starbase())
00270 mass_unit = b->get_starbase()->conv_m_dyn_to_star(1);
00271
00272
00273
00274 if (beta <= 0 || !b->get_pl())
00275 return 0;
00276
00277 if (mass <= 0)
00278 return 1;
00279
00280 else
00281
00282
00283
00284 return log(LAMBDA_FAC*mass(b, r)*mass_unit);
00285 }
00286
00287 local real potential(dyn *b, real r)
00288
00289 {
00290 real A = b->get_pl_coeff();
00291 if (A == 0) return 0;
00292
00293 real a2 = b->get_pl_scale_sq();
00294 real x = b->get_pl_exponent();
00295
00296
00297
00298
00299 return -A*pow(r*r+a2, 0.5*(x-1))/(x-1);
00300
00301 }
00302
00303 static vector Afric = 0;
00304 void set_friction_acc(dyn *b, real r)
00305 {
00306 if (beta > 0) {
00307
00308 real sigma2 = sqrt(-2*potential(b, r)/3);
00309
00310 real V = abs(Vcm);
00311 real X = sqrt(2-b->get_pl_exponent());
00312
00313
00314
00315
00316
00317 real coeff = 4*M_PI*beta*logLambda(b, r);
00318
00319
00320 if (X > 0.1)
00321
00322 Afric = -coeff * Mfric * Vcm * density(b, r) * pow(V, -3)
00323 * (erf(X) - 2*X*exp(-X*X)/sqrt(M_PI));
00324 else
00325
00326
00327
00328 Afric = -coeff * Mfric * Vcm * density(b, r)
00329 * 4 / (3*sqrt(M_PI)*pow(sigma2, 3));
00330
00331 #if 1
00332 cerr << endl << "set_friction_acc: "; PRL(Afric);
00333 PRC(beta); PRC(coeff); PRC(Mfric); PRL(density(b, r));
00334 PRL(Vcm);
00335 PRC(r); PRC(sigma2); PRC(V); PRL(X);
00336 PRL(erf(X) - 2*X*exp(-X*X)/sqrt(M_PI));
00337 #endif
00338
00339 }
00340 }
00341
00342
00343
00344 bool acx_set = false;
00345 static real acx = 0, acx1 = 0;
00346
00347 local inline void set_acx(real A, real c2, real x)
00348 {
00349 if (c2 > 0) {
00350 acx = A*pow(c2, x/2);
00351 if (x != 1)
00352 acx1 = acx*x/(sqrt(c2)*(x-1));
00353 else
00354 acx1 = A*(1+0.5*log(c2));
00355 }
00356 acx_set = true;
00357 }
00358
00359 local inline void add_power_law(dyn * b,
00360 vector pos,
00361 vector vel,
00362 real& pot,
00363 vector& acc,
00364 vector& jerk,
00365 bool pot_only)
00366 {
00367
00368
00369
00370 real A = b->get_pl_coeff();
00371 if (A == 0) return;
00372
00373 real a2 = b->get_pl_scale_sq();
00374 real x = b->get_pl_exponent();
00375
00376 real c2 = b->get_pl_cutoff_sq();
00377 real M = b->get_pl_mass();
00378 real eps2 = b->get_pl_softening_sq();
00379
00380 #if 0
00381 PRC(A); PRC(a2); PRL(x);
00382 PRC(c2); PRC(M); PRL(eps2);
00383 #endif
00384
00385 if (!acx_set) set_acx(A, c2, x);
00386
00387 vector dx = pos - b->get_pl_center();
00388 real dx2 = square(dx);
00389 real r2 = dx2 + a2;
00390
00391 real dx1i;
00392 if (M > 0 || c2 > 0) dx1i = 1/sqrt(dx2+eps2);
00393
00394 if (x == 1) {
00395
00396 real dpot;
00397 if (dx2 <= c2)
00398 dpot = -M*dx1i + acx1;
00399 else {
00400 dpot = 0.5*A*log(r2);
00401 if (M > 0 || c2 > 0) dpot -= (M-acx)*dx1i;
00402 }
00403 pot += dpot;
00404 }
00405
00406 if (x != 1 || !pot_only) {
00407
00408 real r1 = pow(r2, 0.5*(1-x));
00409
00410 if (!pot_only) {
00411
00412 real dx3i;
00413 if (M > 0 || c2 > 0) dx3i = dx1i/(dx2+eps2);
00414
00415 vector vr = dx*(dx*vel);
00416
00417 if (dx2 > c2) {
00418
00419 real r3i = A/(r1*r2);
00420 acc -= dx*r3i;
00421 jerk += ((3-x)*vr/r2 - vel)*r3i;
00422
00423 if (M > 0 || c2 > 0) {
00424 dx3i *= M-acx;
00425 acc -= dx*dx3i;
00426 jerk += (3*vr/(dx2+eps2) - vel)*dx3i;
00427 }
00428
00429 } else if (M > 0) {
00430
00431 dx3i *= M;
00432 acc -= dx*dx3i;
00433 jerk += (3*vr/(dx2+eps2) - vel)*dx3i;
00434
00435 }
00436 }
00437
00438
00439
00440
00441
00442 if (x != 1) {
00443 real dpot;
00444 if (dx2 <= c2)
00445 dpot = -M*dx1i + acx1;
00446 else {
00447 real r1 = pow(r2, 0.5*(1-x));
00448 dpot = -A/(r1*(1-x));
00449 if (M > 0 || c2 > 0) dpot -= (M-acx)*dx1i;
00450 }
00451 pot += dpot;
00452 }
00453 }
00454 }
00455
00456 local inline real power_law_pot(dyn * b)
00457 {
00458
00459
00460
00461 real A = b->get_pl_coeff();
00462 if (A == 0) return 0;
00463
00464 real a2 = b->get_pl_scale_sq();
00465 real x = b->get_pl_exponent();
00466
00467 real c2 = b->get_pl_cutoff_sq();
00468 real M = b->get_pl_mass();
00469 real eps2 = b->get_pl_softening_sq();
00470
00471 if (!acx_set) set_acx(A, c2, x);
00472
00473 real dpot = 0;
00474 for_all_daughters(dyn, b, bb) {
00475
00476 vector dx = bb->get_pos() - bb->get_pl_center();
00477 real dx2 = square(dx);
00478 real r2 = dx2 + a2;
00479
00480 real dx1i;
00481 if (M > 0 || c2 > 0) dx1i = 1/sqrt(dx2+eps2);
00482
00483 real ddpot;
00484 if (x == 1) {
00485 if (dx2 <= c2)
00486 ddpot = -M*dx1i + acx1;
00487 else {
00488 ddpot = 0.5*A*log(r2);
00489 if (M > 0 || c2 > 0) ddpot -= (M-acx)*dx1i;
00490 }
00491 } else {
00492 if (dx2 <= c2)
00493 ddpot = -M*dx1i + acx1;
00494 else {
00495 real r1 = pow(r2, 0.5*(1-x));
00496 ddpot = -A/(r1*(1-x));
00497 if (M > 0 || c2 > 0) ddpot -= (M-acx)*dx1i;
00498 }
00499 }
00500
00501 dpot += bb->get_mass()*ddpot;
00502 }
00503
00504 return dpot;
00505 }
00506
00507 local inline real power_law_virial(dyn * b)
00508 {
00509
00510
00511
00512
00513
00514 real A = b->get_pl_coeff();
00515 if (A == 0) return 0;
00516
00517 real a2 = b->get_pl_scale_sq();
00518 real x = b->get_pl_exponent();
00519
00520
00521
00522
00523 vector com_pos, com_vel;
00524 compute_com(b, com_pos, com_vel);
00525
00526
00527 vector dR = com_pos - b->get_pl_center();
00528 vector acc_com = dR * pow(square(dR)+a2, 0.5*(x-3));
00529
00530
00531
00532
00533
00534 real vir = 0;
00535 for_all_daughters(dyn, b, bb) {
00536 vector dr = bb->get_pos() - com_pos;
00537 dR = bb->get_pos() - b->get_pl_center();
00538 vector acc_ext = dR * pow(square(dR)+a2, 0.5*(x-3));
00539 real dvir = bb->get_mass()*dr*(acc_ext - acc_com);
00540
00541 vir += dvir;
00542 }
00543
00544
00545 return -A*vir;
00546 }
00547
00548
00549
00550
00551
00552
00553
00554 real dyn::get_external_scale_sq()
00555 {
00556
00557
00558 if (!get_external_field())
00559 return 0;
00560 else if (get_tidal_field())
00561 return 0;
00562 else if (get_plummer())
00563 return p_scale_sq;
00564 else if (get_pl())
00565 return pl_scale_sq;
00566 else
00567 return 0;
00568 }
00569
00570 vector dyn::get_external_center()
00571 {
00572
00573
00574 if (!get_external_field())
00575 return 0;
00576 else if (get_tidal_field())
00577 return tidal_center;
00578 else if (get_plummer())
00579 return p_center;
00580 else if (get_pl())
00581 return pl_center;
00582 else
00583 return 0;
00584 }
00585
00586
00587
00588 void get_external_acc(dyn * b,
00589 vector pos,
00590 vector vel,
00591 real& pot,
00592 vector& acc,
00593 vector& jerk,
00594 bool pot_only)
00595 {
00596
00597
00598
00599
00600
00601 pot = 0;
00602 if (!pot_only) acc = jerk = 0;
00603
00604 unsigned int ext = b->get_external_field();
00605
00606 if (ext) {
00607
00608
00609
00610
00611
00612
00613
00614 if (GETBIT(ext, 1))
00615 add_plummer(b, pos, vel, pot, acc, jerk, pot_only);
00616
00617 if (GETBIT(ext, 2))
00618 add_power_law(b, pos, vel, pot, acc, jerk, pot_only);
00619
00620
00621
00622
00623 if (GETBIT(ext, 0))
00624 add_tidal(b, pos, vel, pot, acc, jerk, pot_only);
00625
00626
00627
00628 if (getiq(b->get_dyn_story(), "esc") == 0)
00629 acc += Afric;
00630 }
00631 }
00632
00633 real vcirc(dyn *b, vector r)
00634 {
00635
00636
00637
00638 vector acc, jerk;
00639 real pot;
00640
00641 get_external_acc(b, r, vector(0), pot, acc, jerk);
00642
00643 real vc2 = -r*acc;
00644
00645 if (vc2 > 0)
00646 return sqrt(vc2);
00647 else
00648 return -sqrt(-vc2);
00649 }
00650
00651
00652
00653 real get_tidal_pot(dyn *b) {return tidal_pot(b);}
00654 real get_plummer_pot(dyn *b) {return plummer_pot(b);}
00655 real get_power_law_pot(dyn *b) {return power_law_pot(b);}
00656
00657 real get_external_pot(dyn * b,
00658 void (*pot_func)(dyn *, real))
00659 {
00660
00661
00662
00663 real pot = 0;
00664 unsigned int ext = b->get_external_field();
00665
00666 if (ext) {
00667
00668 real dpot = 0;
00669
00670
00671
00672 if (GETBIT(ext, 0)) dpot += tidal_pot(b);
00673 if (GETBIT(ext, 1)) dpot += plummer_pot(b);
00674 if (GETBIT(ext, 2)) dpot += power_law_pot(b);
00675
00676
00677 if (pot_func) (*pot_func)(b, dpot);
00678
00679 pot += dpot;
00680 }
00681
00682 return pot;
00683 }
00684
00685 real get_external_virial(dyn * b)
00686 {
00687
00688
00689
00690 real vir = 0;
00691 unsigned int ext = b->get_external_field();
00692
00693 if (ext) {
00694
00695
00696
00697 if (GETBIT(ext, 1)) vir += plummer_virial(b);
00698 if (GETBIT(ext, 2)) vir += power_law_virial(b);
00699
00700 }
00701
00702 return vir;
00703 }
00704
00705 static bool sep = false;
00706
00707 local void print_ext(int n)
00708 {
00709 if (sep) cerr << ",";
00710
00711 switch(n) {
00712 case 0: cerr << "TIDAL";
00713 break;
00714 case 1: cerr << "PLUMMER";
00715 break;
00716 case 2: cerr << "POWER-LAW";
00717 break;
00718 default: cerr << "?";
00719 break;
00720 }
00721
00722 sep = true;
00723 }
00724
00725 void print_external(unsigned int ext,
00726 bool shortbits)
00727 {
00728 if (!ext) return;
00729
00730 if (shortbits)
00731
00732
00733
00734 printbits(ext);
00735
00736 else {
00737
00738
00739
00740 int n = 31;
00741 while (n >= 0) {if (GETBIT(ext, n)) break; n--;}
00742 while (n >= 0) {if (GETBIT(ext, n)) print_ext(n); n--;}
00743 sep = false;
00744 }
00745 }