00001
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045 #include "dyn.h"
00046
00047 #ifndef TOOLBOX
00048
00049 real get_mass(dyn *b)
00050 {
00051 real mass = 0;
00052 for_all_daughters(dyn, b, bb)
00053 mass += bb->get_mass();
00054 return mass;
00055 }
00056
00057 void scale_mass(dyn* b, real mscale)
00058 {
00059 for_all_nodes(dyn, b, bb)
00060 bb->scale_mass(mscale);
00061 }
00062
00063 void scale_pos(dyn* b, real rscale,
00064 vector com_pos)
00065 {
00066 b->set_pos(com_pos + rscale*(b->get_pos()-com_pos));
00067
00068 for_all_daughters(dyn, b, bb)
00069 bb->set_pos(com_pos
00070 + rscale*(bb->get_pos()-com_pos));
00071 }
00072
00073 void scale_vel(dyn* b, real vscale,
00074 vector com_vel)
00075 {
00076 b->set_vel(com_vel + vscale*(b->get_vel()-com_vel));
00077
00078 for_all_daughters (dyn, b, bb)
00079 bb->set_vel(com_vel
00080 + vscale*(bb->get_vel()-com_vel));
00081 }
00082
00083 real get_top_level_kinetic_energy(dyn *b)
00084 {
00085 real kinetic_energy = 0;
00086
00087 for_all_daughters(dyn, b, bb)
00088 kinetic_energy += bb->get_mass() * square(bb->get_vel());
00089
00090 kinetic_energy *= 0.5;
00091 return kinetic_energy;
00092 }
00093
00094 real get_kinetic_energy(dyn *b)
00095 {
00096 real kinetic_energy = 0;
00097
00098 for_all_leaves(dyn, b, bb)
00099 kinetic_energy += bb->get_mass()
00100 * square(something_relative_to_root(bb, &dyn::get_vel));
00101
00102 kinetic_energy *= 0.5;
00103 return kinetic_energy;
00104 }
00105
00106
00107
00108
00109 void get_top_level_energies(dyn *b, real eps2,
00110 real& potential_energy,
00111 real& kinetic_energy)
00112 {
00113 real total_energy;
00114 calculate_energies(b, eps2,
00115 potential_energy, kinetic_energy, total_energy,
00116 true);
00117 }
00118
00119 void scale_virial(dyn *b, real q,
00120 real potential_energy,
00121 real& kinetic_energy,
00122 vector com_vel)
00123 {
00124
00125
00126
00127 if (q > 0) q = -q;
00128
00129 real vscale = sqrt(q*potential_energy/kinetic_energy);
00130 scale_vel(b, vscale, com_vel);
00131 kinetic_energy = q*potential_energy;
00132 }
00133
00134 real scale_energy(dyn * b,
00135 real e, real& energy,
00136 vector com_pos,
00137 vector com_vel)
00138 {
00139
00140
00141
00142 if (energy >= 0) return 1;
00143 if (e > 0) e = -e;
00144
00145 real xscale = energy/e;
00146 real vscale = sqrt(1./xscale);
00147
00148 scale_pos(b, xscale, com_pos);
00149 scale_vel(b, vscale, com_vel);
00150
00151 energy = e;
00152 return xscale;
00153 }
00154
00155 void scale(dyn *b, real eps,
00156 bool c_flag,
00157 bool e_flag, real e,
00158 bool m_flag, real m,
00159 bool q_flag, real q,
00160 bool r_flag, real r,
00161 bool debug,
00162 void (*top_level_energies)(dyn*, real,
00163 real&, real&))
00164 {
00165
00166
00167 if (q_flag && find_qmatch(b->get_log_story(), "alpha3_over_alpha1")) {
00168 warning("scale: can't reset virial ratio for aniso_king model");
00169 q_flag = false;
00170 }
00171
00172
00173
00174 real phys_mass, phys_length, phys_time;
00175 bool phys = get_physical_scales(b, phys_mass, phys_length, phys_time);
00176
00177
00178
00179
00180 if (phys) {
00181
00182
00183
00184
00185
00186 if ((m_flag && !twiddles(m, 1))
00187 || (r_flag && !twiddles(r, 1))
00188 || (q_flag && !twiddles(q, 0.5))
00189 || (e_flag && !twiddles(abs(e), 0.25)))
00190 cerr << "scale: non-standard choice of units for system"
00191 << " with physical data" << endl;
00192 }
00193
00194
00195
00196 if (c_flag) {
00197 cerr << "scale: transforming to com frame" << endl;
00198 b->to_com();
00199 }
00200
00201
00202
00203
00204
00205
00206 check_set_ignore_internal(b);
00207
00208
00209
00210
00211
00212
00213
00214 real mass = 0;
00215
00216 if (b->get_system_time() == 0
00217 && find_qmatch(b->get_log_story(), "initial_mass"))
00218 mass = getrq(b->get_log_story(), "initial_mass");
00219 else
00220 mass = get_mass(b);
00221
00222 if (debug) {
00223 cerr << "debug: "; PRC(mass); PRL(get_mass(b));
00224 }
00225
00226
00227
00228
00229
00230 real r_virial = 0, pot_int = 0, pot_ext = 0, kin = 0;
00231
00232 if (e_flag || r_flag || q_flag) {
00233 if (b->get_system_time() == 0
00234 && find_qmatch(b->get_log_story(), "initial_rvirial")) {
00235
00236
00237
00238 r_virial = getrq(b->get_log_story(), "initial_rvirial");
00239 pot_int = -0.5*mass*mass/r_virial;
00240 kin = get_top_level_kinetic_energy(b);
00241
00242 if (debug) {
00243
00244
00245
00246 real pe_int, ke_tot;
00247 top_level_energies(b, eps*eps, pe_int, ke_tot);
00248 cerr << "debug: "; PRC(pot_int); PRC(pe_int);
00249 cerr << "debug: "; PRC(kin); PRL(ke_tot);
00250 }
00251
00252 } else {
00253
00254
00255
00256 top_level_energies(b, eps*eps, pot_int, kin);
00257 r_virial = -0.5*mass*mass/pot_int;
00258 }
00259
00260
00261
00262
00263
00264 check_set_external(b);
00265 pot_ext = get_external_pot(b);
00266
00267 if (debug) {
00268 cerr << "debug: "; PRL(pot_ext);
00269 }
00270
00271
00272
00273
00274 rmq(b->get_log_story(), "kira_initial_jacobi_radius");
00275
00276
00277
00278
00279
00280
00281
00282 if (e_flag && pot_ext != 0)
00283 err_exit("Can't set energy in case of external field.");
00284 }
00285
00286
00287
00288
00289 vector com_pos, com_vel;
00290 compute_com(b, com_pos, com_vel);
00291
00292 real com_kin = 0.5*mass*square(com_vel);
00293
00294 if (debug) {
00295 cerr << "debug: "; PRC(com_vel); PRL(com_kin);
00296 }
00297
00298
00299
00300
00301
00302
00303 if (m_flag) {
00304 real mfac = m/mass;
00305
00306
00307 scale_mass(b, mfac);
00308
00309 mass = m;
00310 pot_int *= mfac*mfac;
00311 pot_ext *= mfac;
00312 kin *= mfac;
00313 com_kin *= mfac;
00314
00315 cerr << "scale: "; PRL(mass);
00316 if (debug) {
00317 cerr << "debug: "; PRL(com_kin);
00318 }
00319 }
00320
00321
00322
00323
00324 if (r_flag) {
00325
00326
00327
00328
00329 real oldvir = pot_int + get_external_virial(b);
00330
00331 if (debug) {
00332 cerr << "debug: "; PRL((kin-com_kin)/oldvir);
00333 }
00334
00335 real rfac = r/r_virial;
00336 if (debug) {
00337 cerr << "debug: "; PRL(rfac);
00338 }
00339 scale_pos(b, rfac, com_pos);
00340
00341 r_virial = r;
00342 pot_int /= rfac;
00343
00344 pot_ext = get_external_pot(b);
00345 if (debug) {
00346 cerr << "debug: "; PRL(pot_ext);
00347 }
00348
00349 cerr << "scale: "; PRL(r_virial);
00350
00351
00352
00353
00354
00355 if (debug) {
00356 cerr << "debug: "; PRC(pot_int); PRL(get_external_virial(b));
00357 }
00358 real vfac = (pot_int + get_external_virial(b))/oldvir;
00359 if (vfac <= 0)
00360 cerr << "scale: unable to preserve virial ratio" << endl;
00361 else {
00362 vfac = sqrt(vfac);
00363 if (debug) {
00364 cerr << "debug: "; PRL(vfac);
00365 }
00366 scale_vel(b, vfac, com_vel);
00367 kin = com_kin + vfac*vfac*(kin - com_kin);
00368 }
00369
00370 if (debug) {
00371
00372
00373
00374 real pe_int, ke;
00375 top_level_energies(b, eps*eps, pe_int, ke);
00376 real p_ext = get_external_pot(b);
00377 real vir = get_external_virial(b);
00378
00379 cerr << "debug: "; PRC(pot_int); PRL(pe_int);
00380 cerr << "debug: "; PRC(kin); PRL(ke);
00381 cerr << "debug: "; PRC(p_ext); PRL((ke-com_kin)/(pe_int+vir));
00382 cerr << "debug: "; PRL(-0.5*mass*mass/pe_int);
00383 }
00384 }
00385
00386 if (e_flag) {
00387
00388
00389
00390
00391
00392
00393 if (q_flag) {
00394 kin -= com_kin;
00395 scale_virial(b, q, pot_int, kin, com_vel);
00396 kin += com_kin;
00397
00398
00399
00400
00401
00402 q_flag = false;
00403
00404 cerr << "scale: "; PRL(q);
00405 }
00406
00407
00408
00409
00410
00411 real ee = kin - com_kin + pot_int;
00412 real fac = scale_energy(b, e, ee, com_pos, com_vel);
00413 ee += com_kin;
00414
00415
00416
00417 kin = com_kin + (kin - com_kin)/fac;
00418 pot_int /= fac;
00419 r_virial *= fac;
00420
00421
00422
00423
00424 cerr << "scale: "; PRL(e);
00425 }
00426
00427 if (q_flag) {
00428
00429
00430
00431 real vir = get_external_virial(b);
00432 PRL(vir);
00433
00434 real denominator = vir;
00435 if (!b->get_ignore_internal()) denominator += pot_int;
00436
00437 real qvir = -(kin - com_kin) / denominator;
00438 real vfac = sqrt(q/qvir);
00439 PRL(vfac);
00440
00441 scale_vel(b, vfac, com_vel);
00442 kin = com_kin + vfac*vfac*(kin - com_kin);
00443
00444 cerr << "scale: "; PRL(q);
00445 if (debug) {
00446 cerr << "debug: "; PRL((kin-com_kin)/denominator);
00447 }
00448 }
00449
00450
00451
00452
00453 if (b->get_system_time() == 0) {
00454 putrq(b->get_log_story(), "initial_mass", mass, HIGH_PRECISION);
00455 putrq(b->get_log_story(), "initial_rvirial", r_virial);
00456 putrq(b->get_dyn_story(), "initial_total_energy", kin+pot_int+pot_ext);
00457 }
00458 }
00459
00460 bool parse_scale_main(int argc, char *argv[],
00461 real& eps, bool& c_flag,
00462 bool& e_flag, real& e,
00463 bool& m_flag, real& m,
00464 bool& q_flag, real& q,
00465 bool& r_flag, real& r,
00466 bool& debug)
00467 {
00468
00469
00470 debug = false;
00471 c_flag = false;
00472 e_flag = false;
00473 m_flag = false;
00474 q_flag = false;
00475 r_flag = false;
00476 bool eps_flag = false;
00477 bool s_flag = false;
00478
00479 m = 0, q = -1, e = 0, r = 0;
00480 eps = 0;
00481
00482 extern char *poptarg;
00483 int c;
00484 char* param_string = "cdm:M:q:Q:e:E:r:R:sS";
00485
00486 while ((c = pgetopt(argc, argv, param_string)) != -1)
00487 switch(c) {
00488
00489 case 'c': c_flag = true;
00490 break;
00491 case 'd': debug = true;
00492 break;
00493 case 'E': e_flag = true;
00494 r_flag = false;
00495 e = atof(poptarg);
00496 break;
00497 case 'e': eps_flag = true;
00498 eps = atof(poptarg);
00499 break;
00500 case 'M':
00501 case 'm': m_flag = true;
00502 m = atof(poptarg);
00503 break;
00504 case 'Q':
00505 case 'q': q_flag = true;
00506 q = atof(poptarg);
00507 break;
00508 case 'R':
00509 case 'r': r_flag = true;
00510 e_flag = false;
00511 r = atof(poptarg);
00512 break;
00513 case 'S':
00514 case 's': s_flag = true;
00515 m_flag = true;
00516 r_flag = true;
00517 q_flag = true;
00518 m = 1;
00519 q = 0.5;
00520 r = 1;
00521 break;
00522 case '?': params_to_usage(cerr, argv[0], param_string);
00523 return false;
00524 }
00525
00526 if (e_flag && e >= 0) warning("scale: specified energy >= 0");
00527 if (m_flag && m <= 0) warning("scale: specified mass <= 0");
00528 if (q_flag && q < 0) warning("scale: specified virial ratio < 0");
00529 if (r_flag && r <= 0) warning("scale: specified virial radius <= 0");
00530
00531 return true;
00532 }
00533
00534 #else
00535
00536 main(int argc, char ** argv)
00537 {
00538 real m = 0, q = -1, e = 0, r = 0;
00539 real eps = 0;
00540
00541 bool debug = false;
00542 bool c_flag = false;
00543 bool e_flag = false;
00544 bool m_flag = false;
00545 bool q_flag = false;
00546 bool r_flag = false;
00547
00548 if (!parse_scale_main(argc, argv, eps,
00549 c_flag,
00550 e_flag, e, m_flag, m,
00551 q_flag, q, r_flag, r,
00552 debug)) {
00553 get_help();
00554 exit(1);
00555 }
00556
00557 dyn *b = get_dyn(cin);
00558 b->log_history(argc, argv);
00559
00560 scale(b, eps, c_flag, e_flag, e, m_flag, m, q_flag, q, r_flag, r, debug);
00561
00562 put_node(cout, *b);
00563 }
00564
00565 #endif