|
CLUMPY
Version 2011.09_corr2
|
00001 00003 #include "../include/clumps.h" 00004 #include "../include/params.h" 00005 #include "../include/profiles.h" 00006 00007 using namespace std; 00008 #include <iostream> 00009 #include <math.h> 00010 #include <stdlib.h> 00011 00012 //______________________________________________________________________________ 00013 double factor_r_2_to_rscale(double par_prof[4]) 00014 { 00015 //--- Returns F = r_2 / rscale 00016 // par_prof[0] Shape parameter #1 00017 // par_prof[1] Shape parameter #2 00018 // par_prof[2] Shape parameter #3 00019 // par_prof[3] card_profile [gENUM_PROFILE] 00020 // 00021 // N.B.: r_2 corresponds to d/dr(r^2 rho(r)) |(r=r_2) = 0 00022 // For a generic profile (alpha,beta,gamma), we obtain 00023 // EINASTO : rscale=r_2 => F = 1 00024 // EINASTO_N: rscale=re => F = pow(2n/dn,n) [Eq. 8 Graham et al., AJ 132, 2701 (2006)] 00025 // ZHAO : rscale=rs => F = pow((beta-2)/(2-gamma),-1/alpha) 00026 // N.B.: r_2 is not defined for kZHAO if beta<=2, i.e. outer slope (par_prof[1]) => abort 00027 00028 int card_profile = (int)par_prof[3]; 00029 switch (card_profile) { 00030 case kEINASTO: 00031 return 1.; 00032 case kEINASTO_N: 00033 return pow(2. * par_prof[0] / (3.*par_prof[0] - 0.3333333333 + 0.0079 / par_prof[0]), par_prof[0]); 00034 case kZHAO: 00035 if (par_prof[1] > 2.) 00036 return pow((par_prof[1] - 2.) / (2. - par_prof[2]), -1. / par_prof[0]); 00037 else { 00038 cout << ">>> r_{-2} is not defined for kZHAO if beta<=2 => abort() " << endl; 00039 abort(); 00040 } 00041 default : 00042 cout << ">>> card_profile chosen does not correspond to any profile => abort() " << endl; 00043 abort(); 00044 } 00045 return 0.; 00046 } 00047 00048 //______________________________________________________________________________ 00049 string get_name_prof(double par_prof[4]) 00050 { 00051 //--- Returns a name as "profile name (#1,#2,#3)" 00052 // par_prof[0] Shape parameter #1 00053 // par_prof[1] Shape parameter #2 00054 // par_prof[2] Shape parameter #3 00055 // par_prof[3] card_profile [gENUM_PROFILE] 00056 // 00057 int card_profile = (int)par_prof[3]; 00058 char tmp[100]; 00059 string name = gNAMES_PROFILE[card_profile]; 00060 00061 switch (card_profile) { 00062 case kEINASTO: 00063 sprintf(tmp, "%s (#alpha=%.2lf)", name.c_str(), par_prof[0]); 00064 return tmp; 00065 case kEINASTO_N: 00066 sprintf(tmp, "%s (n=%d)", name.c_str(), (int)par_prof[0]); 00067 return tmp; 00068 case kZHAO: 00069 sprintf(tmp, "%s (%.1lf,%.1lf,%.1lf)", 00070 name.c_str(), par_prof[0], par_prof[1], par_prof[2]); 00071 return tmp; 00072 default : 00073 cout << ">>> card_profile chosen does not correspond to any profile => abort() " << endl; 00074 abort(); 00075 } 00076 return ""; 00077 } 00078 00079 //______________________________________________________________________________ 00080 double get_rsat(double par[6]) 00081 { 00082 //--- Returns r_sat [kpc] for which rho(r<r_sat)=rho_sat 00083 // par[0] Dark matter density normalisation [Msol/kpc^3] 00084 // par[1] Scale radius [kpc] 00085 // par[2] Shape parameter #1 00086 // par[3] Shape parameter #2 00087 // par[4] Shape parameter #3 00088 // par[5] card_profile [gENUM_PROFILE] 00089 00090 int profile = (int)par[5]; 00091 switch (profile) { 00092 case kEINASTO: 00093 return 0.; 00094 case kEINASTO_N: 00095 return 0.; 00096 case kZHAO: 00097 if (par[4] > 0.) 00098 return par[1] * pow(par[0] / gDM_RHOSAT, 1. / par[4]); 00099 else 00100 return 0.; 00101 default : 00102 cout << ">>> get_rsat: card_profile " << par[5] 00103 << " does not correspond to any profile => abort() " << endl; 00104 abort(); 00105 } 00106 return 0.; 00107 } 00108 00109 //______________________________________________________________________________ 00110 double get_rvir(double par[6], double const& rho_vir) 00111 { 00112 //--- Returns Rvir, such that rho(Rvir)=rho_vir 00113 // par[0] Dark matter density normalisation [Msol/kpc^3] 00114 // par[1] Scale radius [kpc] 00115 // par[2] Shape parameter #1 00116 // par[3] Shape parameter #2 00117 // par[4] Shape parameter #3 00118 // par[5] card_profile [gENUM_PROFILE] 00119 // rho_vir Alleged DM density at the virial radius [Msol/kpc^3] 00120 00121 double rmin = par[1] / 10.; 00122 double rmax = 1.e3; 00123 int n = 1000; 00124 double r = rmin; 00125 double dr = pow(rmax / rmin, 1. / (double)n); 00126 for (int i = 0; i < n; ++i) { 00127 r *= dr; 00128 double res = 0.; 00129 rho(r, par, res); 00130 if (res < rho_vir) 00131 return r; 00132 } 00133 return 0.; 00134 } 00135 //______________________________________________________________________________ 00136 double rho_EINASTO(double &r, double par[3]) 00137 { 00138 //--- Returns rho(r) for Einasto profile (Navarro et al. 2004 or Springel et al. 2008) [Msol/kpc^3] 00139 // r Distance from the centre of the profile [kpc] 00140 // par[0] rho_{-2}: density normalisation [Msol/kpc^3] 00141 // par[1] r_{-2}: radius at which the slope in -2 (replaces rs for this profile) [kpc] 00142 // par[2] alpha: shape parameter of the profile 00143 // 00144 // => rho(r)= rho_{-2} * exp{-2/alpha [(r/r_{-2})^{alpha} - 1] } 00145 00146 double res = par[0] * exp(-2. / par[2] * (pow(r / par[1], par[2]) - 1.)); 00147 if (res < gDM_RHOSAT) 00148 return res; 00149 else 00150 return gDM_RHOSAT; 00151 } 00152 00153 //______________________________________________________________________________ 00154 double rho_EINASTO_N(double &r, double par[3]) 00155 { 00156 //--- Returns rho(r) for Einasto r^{1/n} profile (Merritt et al. 2006) [Msol/kpc^3] 00157 // r Distance from the centre of the profile [kpc] 00158 // par[0] rho_e: density normalisation [Msol/kpc^3] 00159 // par[1] r_e: radius containing half the mass of the halo (replaces rs for this profile) [kpc] 00160 // par[2] n: integer index of the profile (shape parameter) 00161 // 00162 // => rho(r)= rho_e * exp{-dn [(r/r_e)^{1/n} - 1] } 00163 00164 00165 00166 if (par[2] < 0.5) { 00167 cout << "WARNING in rho_EINASTO_N: n < 0.5 not authorised in CLUMPY" << endl; 00168 abort(); 00169 } 00170 double dn = 3.*par[2] - 0.3333333333 + 0.0079 / par[2]; 00171 00172 double res = par[0] * exp(-dn * (pow((r / par[1]), (1. / par[2])) - 1.)); 00173 if (res < gDM_RHOSAT) 00174 return res; 00175 else 00176 return gDM_RHOSAT; 00177 } 00178 00179 //______________________________________________________________________________ 00180 double rho_ZHAO(double &r, double par[5]) 00181 { 00182 //--- Returns rho(r) for a ZHAO (alpha,beta,gamma) [Msol/kpc^3] 00183 // r Distance from the centre of the profile [kpc] 00184 // par[0] rho_s: density normalisation [Msol/kpc^3] 00185 // par[1] r_s: scale radius [kpc] 00186 // par[2] alpha: transition slope 00187 // par[3] beta: outer slope 00188 // par[4] gamma: inner slope 00189 // 00190 // => rho(r)= rho_s/[(r/r_s)^{gamma} [1+(r/r_s)^{alpha}]^{(beta-gamma)/alpha}] 00191 00192 00193 // Required to avoid divergences at r=0 00194 if (par[4] > 1.e-5) { 00195 if (r > par[1] * pow(par[0] / gDM_RHOSAT, 1. / par[4])) { 00196 return par[0] * pow(par[1] / r, par[4]) 00197 / pow(1. + pow(r / par[1], par[2]), (par[3] - par[4]) / par[2]); 00198 } else 00199 return gDM_RHOSAT; 00200 } else 00201 return par[0] / pow(1. + pow(r / par[1], par[2]), par[3] / par[2]); 00202 } 00203 00204 //______________________________________________________________________________ 00205 void rho(double &r, double par[6], double& res) 00206 { 00207 //--- Sets res = Density profile [Msol/kpc^3] 00208 // Input: 00209 // r Distance from the centre of the profile [kpc] 00210 // par[0] Normalisation: density [Msol/kpc^3] or proxy for dPdV [kpc^{-3}] 00211 // par[1] Scale radius [kpc] 00212 // par[2] Shape parameter #1 00213 // par[3] Shape parameter #2 00214 // par[4] Shape parameter #3 00215 // par[5] card_profile [gENUM_PROFILE] 00216 // Output: 00217 // res Value of rho(r) 00218 00219 int profile1 = (int)par[5]; 00220 00221 // Calculate rho(r) 00222 switch (profile1) { 00223 case kEINASTO: 00224 res = rho_EINASTO(r, par); 00225 break; 00226 case kEINASTO_N: 00227 res = rho_EINASTO_N(r, par); 00228 break; 00229 case kZHAO: 00230 res = rho_ZHAO(r, par); 00231 break; 00232 default : 00233 cout << ">>> rho1: card_profile " << par[5] 00234 << " does not correspond to any profile => abort() " << endl; 00235 abort(); 00236 } 00237 return; 00238 } 00239 00240 //______________________________________________________________________________ 00241 void rho_mix(double &r, double par[21], double& res) 00242 { 00243 //--- Sets res = Density profile [Msol/kpc^3] 00244 // Input: 00245 // r Distance from the centre of the profile [kpc] 00246 // par[0] rho_1(r) normalisation: density [Msol/kpc^3] or proxy for dPdV [kpc^{-3}] 00247 // par[1] rho_1(r) scale radius [kpc] 00248 // par[2] rho_1(r) shape parameter #1 00249 // par[3] rho_1(r) shape parameter #2 00250 // par[4] rho_1(r) shape parameter #3 00251 // par[5] rho_1(r) card_profile [gENUM_PROFILE] 00252 // par[6] UNUSED 00253 // par[7] UNUSED 00254 // par[8] UNUSED 00255 // par[9] UNUSED 00256 // par[10] switch_rho - selects which combination of rho_1 and rho_2 to use 00257 // 0 -> rho(r) = rho1(r) 00258 // 1 -> rho(r) = rho1(r)-rho2(r) 00259 // 2 -> rho(r) = rho1(r)*rho2(r) 00260 // par[11] rho_2(r) normalisation: density [Msol/kpc^3] or proxy for dPdV [kpc^{-3}] 00261 // par[12] rho_2(r) scale radius [kpc] 00262 // par[13] rho_2(r) shape parameter #1 00263 // par[14] rho_2(r) shape parameter #2 00264 // par[15] rho_2(r) shape parameter #3 00265 // par[16] rho_2(r) card_profile [gENUM_PROFILE] 00266 // par[17] UNUSED 00267 // par[18] UNUSED 00268 // par[19] UNUSED 00269 // par[20] UNUSED 00270 // Output: 00271 // res Value of rho(r) 00272 00273 int switch_rho = (int)par[10]; 00274 int profile1 = (int)par[5]; 00275 00276 // Calculate rho1(r) 00277 switch (profile1) { 00278 case kEINASTO: 00279 res = rho_EINASTO(r, par); 00280 break; 00281 case kEINASTO_N: 00282 res = rho_EINASTO_N(r, par); 00283 break; 00284 case kZHAO: 00285 res = rho_ZHAO(r, par); 00286 break; 00287 default : 00288 cout << ">>> rho_1: card_profile " << par[5] 00289 << " does not correspond to any profile => abort() " << endl; 00290 abort(); 00291 } 00292 00293 00294 // Check combi and calculate rho2 if necessary 00295 if (switch_rho == 0) { 00296 if (res > gDM_RHOSAT) 00297 res = gDM_RHOSAT; 00298 return; 00299 } else { 00300 int profile2 = (int)par[16]; 00301 double rho_2 = 0.; 00302 switch (profile2) { 00303 case kEINASTO: 00304 rho_2 = rho_EINASTO(r, &par[11]); 00305 break; 00306 case kEINASTO_N: 00307 rho_2 = rho_EINASTO_N(r, &par[11]); 00308 break; 00309 case kZHAO: 00310 rho_2 = rho_ZHAO(r, &par[11]); 00311 break; 00312 default : 00313 cout << ">>> rho_2: card_profile " << par[16] 00314 << " does not correspond to any profile => abort() " << endl; 00315 abort(); 00316 } 00317 00318 if (switch_rho == 1) { 00319 if (rho_2 < gDM_RHOSAT) 00320 res -= rho_2; 00321 return; 00322 } else if (switch_rho == 2) { 00323 res *= rho_2; 00324 return; 00325 } else { 00326 cout << ">>> switch_rho: " << par[1] 00327 << " does not correspond to any combi for rho_1 and rho_2 => abort() " << endl; 00328 abort(); 00329 } 00330 } 00331 return; 00332 } 00333 00334 //______________________________________________________________________________ 00335 void rho2(double &r, double par[6], double& res) 00336 { 00337 //--- Sets res = Density square of the profile [Msol^2/kpc^6] 00338 // Input: 00339 // r Distance from the centre of the profile [kpc] 00340 // par[0] Normalisation: density [Msol/kpc^3] or proxy for dPdV [kpc^{-3}] 00341 // par[1] Scale radius [kpc] 00342 // par[2] Shape parameter #1 00343 // par[3] Shape parameter #2 00344 // par[4] Shape parameter #3 00345 // par[5] card_profile [gENUM_PROFILE] 00346 // Output: 00347 // res Value of rho^2(r) 00348 00349 rho(r, par, res); 00350 res *= res; 00351 return; 00352 } 00353 00354 //______________________________________________________________________________ 00355 void rho2_mix(double &r, double par[21], double& res) 00356 { 00357 //--- Sets res = Density square of the profile [Msol^2/kpc^6] 00358 // Input: 00359 // r Distance from the centre of the profile [kpc] 00360 // par[0] rho_1(r) normalisation: density [Msol/kpc^3] or proxy for dPdV [kpc^{-3}] 00361 // par[1] rho_1(r) scale radius [kpc] 00362 // par[2] rho_1(r) shape parameter #1 00363 // par[3] rho_1(r) shape parameter #2 00364 // par[4] rho_1(r) shape parameter #3 00365 // par[5] rho_1(r) card_profile [gENUM_PROFILE] 00366 // par[6] UNUSED 00367 // par[7] UNUSED 00368 // par[8] UNUSED 00369 // par[9] UNUSED 00370 // par[10] switch_rho - selects which combination of rho_1 and rho_2 to use 00371 // 0 -> rho(r) = rho1(r) 00372 // 1 -> rho(r) = rho1(r)-rho2(r) 00373 // 2 -> rho(r) = rho1(r)*rho2(r) 00374 // par[11] rho_2(r) normalisation: density [Msol/kpc^3] or proxy for dPdV [kpc^{-3}] 00375 // par[12] rho_2(r) scale radius [kpc] 00376 // par[13] rho_2(r) shape parameter #1 00377 // par[14] rho_2(r) shape parameter #2 00378 // par[15] rho_2(r) shape parameter #3 00379 // par[16] rho_2(r) card_profile [gENUM_PROFILE] 00380 // par[17] UNUSED 00381 // par[18] UNUSED 00382 // par[19] UNUSED 00383 // par[20] UNUSED 00384 // Output: 00385 // res Value of rho^2(r) 00386 00387 rho_mix(r, par, res); 00388 res *= res; 00389 return; 00390 } 00391 00392 //______________________________________________________________________________ 00393 void r2rho(double &r, double par[6], double& res) 00394 { 00395 //--- Sets res = r^2 * Density of the profile [Msol/kpc] 00396 // Input: 00397 // r Distance from the centre of the profile [kpc] 00398 // par[0] Normalisation: density [Msol/kpc^3] or proxy for dPdV [kpc^{-3}] 00399 // par[1] Scale radius [kpc] 00400 // par[2] Shape parameter #1 00401 // par[3] Shape parameter #2 00402 // par[4] Shape parameter #3 00403 // par[5] card_profile [gENUM_PROFILE] 00404 // Output: 00405 // res Value of r^2*rho(r) 00406 00407 rho(r, par, res); 00408 res *= r * r; 00409 return; 00410 } 00411 00412 //______________________________________________________________________________ 00413 void r2rho_mix(double &r, double par[21], double& res) 00414 { 00415 //--- Sets res = r^2 * Density of the profile [Msol/kpc] 00416 // Input: 00417 // r Distance from the centre of the profile [kpc] 00418 // par[0] rho_1(r) normalisation: density [Msol/kpc^3] or proxy for dPdV [kpc^{-3}] 00419 // par[1] rho_1(r) scale radius [kpc] 00420 // par[2] rho_1(r) shape parameter #1 00421 // par[3] rho_1(r) shape parameter #2 00422 // par[4] rho_1(r) shape parameter #3 00423 // par[5] rho_1(r) card_profile [gENUM_PROFILE] 00424 // par[6] UNUSED 00425 // par[7] UNUSED 00426 // par[8] UNUSED 00427 // par[9] UNUSED 00428 // par[10] switch_rho - selects which combination of rho_1 and rho_2 to use 00429 // 0 -> rho(r) = rho1(r) 00430 // 1 -> rho(r) = rho1(r)-rho2(r) 00431 // 2 -> rho(r) = rho1(r)*rho2(r) 00432 // par[11] rho_2(r) normalisation: density [Msol/kpc^3] or proxy for dPdV [kpc^{-3}] 00433 // par[12] rho_2(r) scale radius [kpc] 00434 // par[13] rho_2(r) shape parameter #1 00435 // par[14] rho_2(r) shape parameter #2 00436 // par[15] rho_2(r) shape parameter #3 00437 // par[16] rho_2(r) card_profile [gENUM_PROFILE] 00438 // par[17] UNUSED 00439 // par[18] UNUSED 00440 // par[19] UNUSED 00441 // par[20] UNUSED 00442 // Output: 00443 // res Value of r^2*rho(r) 00444 00445 rho_mix(r, par, res); 00446 res *= r * r; 00447 return; 00448 } 00449 00450 //______________________________________________________________________________ 00451 void r2rho2(double &r, double par[6], double& res) 00452 { 00453 //--- Sets res = r^2 * Density square of the profile [Msol^2/kpc^4] 00454 // Input: 00455 // r Distance from the centre of the profile [kpc] 00456 // par[0] Normalisation: density [Msol/kpc^3] or proxy for dPdV [kpc^{-3}] 00457 // par[1] Scale radius [kpc] 00458 // par[2] Shape parameter #1 00459 // par[3] Shape parameter #2 00460 // par[4] Shape parameter #3 00461 // par[5] card_profile [gENUM_PROFILE] 00462 // Output: 00463 // res Value of r^2*rho^2(r) 00464 00465 00466 rho(r, par, res); 00467 res *= res * r * r; 00468 return; 00469 } 00470 00471 //______________________________________________________________________________ 00472 void r2rho2_mix(double &r, double par[21], double& res) 00473 { 00474 //--- Sets res = r^2 * Density square of the profile [Msol^2/kpc^4] 00475 // Input: 00476 // r Distance from the centre of the profile [kpc] 00477 // par[0] rho_1(r) normalisation: density [Msol/kpc^3] or proxy for dPdV [kpc^{-3}] 00478 // par[1] rho_1(r) scale radius [kpc] 00479 // par[2] rho_1(r) shape parameter #1 00480 // par[3] rho_1(r) shape parameter #2 00481 // par[4] rho_1(r) shape parameter #3 00482 // par[5] rho_1(r) card_profile [gENUM_PROFILE] 00483 // par[6] UNUSED 00484 // par[7] UNUSED 00485 // par[8] UNUSED 00486 // par[9] UNUSED 00487 // par[10] switch_rho - selects which combination of rho_1 and rho_2 to use 00488 // 0 -> rho(r) = rho1(r) 00489 // 1 -> rho(r) = rho1(r)-rho2(r) 00490 // 2 -> rho(r) = rho1(r)*rho2(r) 00491 // par[11] rho_2(r) normalisation: density [Msol/kpc^3] or proxy for dPdV [kpc^{-3}] 00492 // par[12] rho_2(r) scale radius [kpc] 00493 // par[13] rho_2(r) shape parameter #1 00494 // par[14] rho_2(r) shape parameter #2 00495 // par[15] rho_2(r) shape parameter #3 00496 // par[16] rho_2(r) card_profile [gENUM_PROFILE] 00497 // par[17] UNUSED 00498 // par[18] UNUSED 00499 // par[19] UNUSED 00500 // par[20] UNUSED 00501 // Output: 00502 // res Value of r^2*rho^2(r) 00503 00504 rho_mix(r, par, res); 00505 res *= res * r * r; 00506 return; 00507 } 00508 00509 //______________________________________________________________________________ 00510 double r_2_to_rscale(double const& r_2, double par_prof[4]) 00511 { 00512 //--- Returns scale radius rs [kpc] from r_2 [kpc] for a given profile. 00513 // r_2 Radius [kpc] for which the DM profile slope = -2 00514 // par_prof[0] Shape parameter #1 00515 // par_prof[1] Shape parameter #2 00516 // par_prof[2] Shape parameter #3 00517 // par_prof[3] card_profile [gENUM_PROFILE] 00518 00519 return r_2 / factor_r_2_to_rscale(par_prof); 00520 } 00521 00522 //______________________________________________________________________________ 00523 double rscale_to_r_2(double const& rs, double par_prof[4]) 00524 { 00525 //--- Returns r_2 [kpc] from the scale radius rs [kpc] for a given profile 00526 // r_s Scale radius [kpc] (rs, re or r{-2}, depending on card_profile) 00527 // par_prof[0] Shape parameter #1 00528 // par_prof[1] Shape parameter #2 00529 // par_prof[2] Shape parameter #3 00530 // par_prof[3] card_profile [gENUM_PROFILE] 00531 00532 return rs * factor_r_2_to_rscale(par_prof); 00533 } 00534 00535 //______________________________________________________________________________ 00536 void set_par0_given_mref(double par[6], double const& r_ref, double const& m_ref, double const& eps) 00537 { 00538 //--- Returns DM density normalisation [Msol/kpc^3] matching the constraint M(r<r_ref)=m_ref 00539 // Input: 00540 // par[0] UNUSED 00541 // par[1] Scale radius [kpc] 00542 // par[2] Shape parameter #1 00543 // par[3] Shape parameter #2 00544 // par[4] Shape parameter #3 00545 // par[5] card_profile [gENUM_PROFILE] 00546 // r_ref Reference radius [kpc] 00547 // m_ref Mass [Msol] within the radius r_ref 00548 // eps Relative precision sought for integration 00549 // Output: 00550 // par[0] Dark matter density normalisation [Msol/kpc^3] 00551 00552 const int npar = 7; 00553 double par_tmp[npar] = {1., par[1], par[2], par[3], par[4], par[5], r_ref}; 00554 par[0] = m_ref / mass_singlehalo(par_tmp, eps); 00555 } 00556 00557 //______________________________________________________________________________ 00558 void set_par0_given_rhoref(double par[6], double& r_ref, double const& rho_ref) 00559 { 00560 //--- Sets normalisation par[0] such that rho(r_ref)=rho_ref 00561 // Input: 00562 // par[0] UNUSED 00563 // par[1] Scale radius [kpc] 00564 // par[2] Shape parameter #1 00565 // par[3] Shape parameter #2 00566 // par[4] Shape parameter #3 00567 // par[5] card_profile [gENUM_PROFILE] 00568 // r_ref Reference radius [kpc] 00569 // rho_ref Density at r=r_ref [Msol/kpc^3] 00570 // Output: 00571 // par[0] Dark matter density normalisation [Msol/kpc^3] 00572 00573 // Calculate normalisation 00574 double res = 0.; 00575 par[0] = 1.; 00576 rho(r_ref, par, res); 00577 par[0] = rho_ref / res; 00578 return; 00579 }