/* Gas density profile derived from nfw mass profile and temperature profile Author: Junhua Gu Last modification: 20120721 */ #ifndef NFW_NE #define NFW_NE #include "projector.hpp" #include #include #include //a series of physical constants static const double G=6.673E-8;//cm^3 g^-1 s^2 static const double mu=1.4074; static const double mp=1.67262158E-24;//g static const double k=1.60217646E-9;//erg/keV static const double c=2.99792458E10;//cm/s namespace opt_utilities { //the nfw mass enclosed within a radius r, with parameter rho0 and rs template T nfw_mass_enclosed(T r,T rho0,T rs) { return 4*pi*rho0*rs*rs*rs*(std::log((r+rs)/rs)-r/(r+rs)); } //average mass density template T nfw_average_density(T r,T rho0,T rs) { if(r==0) { return rho0; } return nfw_mass_enclosed(r,rho0,rs)/(4.*pi/3*r*r*r); } //calculate critical density from z, under following cosmological constants static double calc_critical_density(double z, const double H0=2.3E-18, const double Omega_m=.27) { const double E=std::sqrt(Omega_m*(1+z)*(1+z)*(1+z)+1-Omega_m); const double H=H0*E; return 3*H*H/8/pi/G; } //a class wraps method of calculating gas density from mass profile and temperature profile template class nfw_ne :public model,std::vector,std::vector > { private: //pointer to temperature profile function func_obj* pTfunc; //cm per pixel T cm_per_pixel; public: //default constructor nfw_ne() :pTfunc(0),cm_per_pixel(1) { this->push_param_info(param_info,std::string>("rho0",1));//in mp this->push_param_info(param_info,std::string>("rs",100)); this->push_param_info(param_info,std::string>("n0",.01)); } //copy constructor nfw_ne(const nfw_ne& rhs) :cm_per_pixel(rhs.cm_per_pixel) { if(rhs.pTfunc) { pTfunc=rhs.pTfunc->clone(); } else { pTfunc=0; } //initial parameter list this->push_param_info(param_info,std::string>("rho0",rhs.get_param_info("rho0").get_value())); this->push_param_info(param_info,std::string>("rs",rhs.get_param_info("rs").get_value())); this->push_param_info(param_info,std::string>("n0",rhs.get_param_info("n0").get_value())); } //assignment operator nfw_ne& operator=(const nfw_ne& rhs) { cm_per_pixel=rhs.cm_per_pixel; if(pTfunc) { pTfunc->destroy(); } if(rhs.pTfunc) { pTfunc=rhs.pTfunc->clone(); } } //destructor ~nfw_ne() { if(pTfunc) { pTfunc->destroy(); } } public: //attach the temperature profile function void attach_Tfunc(const func_obj& Tf) { if(pTfunc) { pTfunc->destroy(); } pTfunc=Tf.clone(); } //set the cm per pixel value void set_cm_per_pixel(const T& x) { cm_per_pixel=x; } //clone self nfw_ne* do_clone()const { return new nfw_ne(*this); } //calculate density under parameters p, at radius r /* r is a vector, which stores a series of radius values the annuli or pie regions are enclosed between any two adjacent radii. so the returned value has length smaller than r by 1. */ std::vector do_eval(const std::vector & r, const std::vector& p) { assert(pTfunc); //const T kT_erg=k*5; T rho0=std::abs(p[0])*mp; T rs=std::abs(p[1]); T n0=std::abs(p[2]); T rs_cm=rs*cm_per_pixel; std::vector yvec(r.size()); const T kT_erg0=pTfunc->eval((r.at(0)+r.at(1))/2)*k; //calculate the integration #pragma omp parallel for schedule(dynamic) for(int i=0;ieval(r[i])*k; if(abs(r_cm)==0) { continue; } yvec.at(i)=G*nfw_mass_enclosed(r_cm,rho0,rs_cm)*mu*mp/kT_erg/r_cm/r_cm; //std::cout< ydxvec(r.size()-1); #pragma omp parallel for schedule(dynamic) for(int i=1;i result(r.size()-1); #pragma omp parallel for schedule(dynamic) for(int i=0;ieval(r[i])*k; //std::cout<