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