Exemplo n.º 1
0
  def __init__(self,M,N=1e4,MMinInfall=1e-5,MMaxInfall=1e-1,Rmax=2,C=None,include_disruption=True,weighted_sample=True):
	''' initialize the sampling parameters.
  
	M: host mass in 1e10Msun/h
	N: number of subhaloes to generate
	MMinInfall: minimum infall mass, in unit of host mass
	MMaxInfall: maximum infall mass, in unit of host mass
	Rmax: maximum radius to sample, in unit of host virial radius
	C: host concentration. If None, it will be determined by the mean mass-concentration relation.
	include_disruption: whether to include disrupted subhaloes in the sample.
	weighted_sample: whether to sample the mass in a weighted way, so that different mass ranges are sampled equally well. this is useful if 				you have a large dynamic range in mass, e.g., from 10^-6 to 10^12 Msun.
	'''
	self.M=M
	self.Host=NFWHalo(M,C) 
	#self.Host.density=my_density_func #to use custom density, overwrite Host.density() function.
	self.C=self.Host.C
	self.HOD=ModelParameter(self.M)
		
	self.Rmax=Rmax
	self.Msample=self.Host.mass(Rmax*self.Host.Rv) #mass inside Rmax
	
	self.mAccMin=MMinInfall*M
	self.mAccMax=MMaxInfall*M
	self.n=N #sample size
	self.nPred=self.HOD.A*self.Msample*(self.mAccMin**-self.HOD.alpha-self.mAccMax**-self.HOD.alpha)/self.HOD.alpha #expected number of subhaloes per host.
	
	self.include_disruption=include_disruption
	if include_disruption:
	  self.nSurvive=int(N*self.HOD.fs)
	  self.nDisrupt=N-self.nSurvive
	else:
	  self.nPred*=self.HOD.fs #only survived subhaloes are generated.
	  self.nSurvive=N
	  self.nDisrupt=int(N/self.HOD.fs*(1-self.HOD.fs))

	self.weighted_sample=weighted_sample
Exemplo n.º 2
0
class SubhaloSample:
  ''' a sample of subhaloes '''
  def __init__(self,M,N=1e4,MMinInfall=1e-5,MMaxInfall=1e-1,Rmax=2,C=None,include_disruption=True,weighted_sample=True):
	''' initialize the sampling parameters.
  
	M: host mass in 1e10Msun/h
	N: number of subhaloes to generate
	MMinInfall: minimum infall mass, in unit of host mass
	MMaxInfall: maximum infall mass, in unit of host mass
	Rmax: maximum radius to sample, in unit of host virial radius
	C: host concentration. If None, it will be determined by the mean mass-concentration relation.
	include_disruption: whether to include disrupted subhaloes in the sample.
	weighted_sample: whether to sample the mass in a weighted way, so that different mass ranges are sampled equally well. this is useful if 				you have a large dynamic range in mass, e.g., from 10^-6 to 10^12 Msun.
	'''
	self.M=M
	self.Host=NFWHalo(M,C) 
	#self.Host.density=my_density_func #to use custom density, overwrite Host.density() function.
	self.C=self.Host.C
	self.HOD=ModelParameter(self.M)
		
	self.Rmax=Rmax
	self.Msample=self.Host.mass(Rmax*self.Host.Rv) #mass inside Rmax
	
	self.mAccMin=MMinInfall*M
	self.mAccMax=MMaxInfall*M
	self.n=N #sample size
	self.nPred=self.HOD.A*self.Msample*(self.mAccMin**-self.HOD.alpha-self.mAccMax**-self.HOD.alpha)/self.HOD.alpha #expected number of subhaloes per host.
	
	self.include_disruption=include_disruption
	if include_disruption:
	  self.nSurvive=int(N*self.HOD.fs)
	  self.nDisrupt=N-self.nSurvive
	else:
	  self.nPred*=self.HOD.fs #only survived subhaloes are generated.
	  self.nSurvive=N
	  self.nDisrupt=int(N/self.HOD.fs*(1-self.HOD.fs))

	self.weighted_sample=weighted_sample
	
  def _lnPDF(self, x):
	''' R in units of Rv'''
	lnmu,lnR=x
	lnmubar=np.log(self.HOD.mustar)+self.HOD.beta*lnR
	dlnmu=lnmu-lnmubar
	if lnmu>0: #mu<1
	  return -np.inf
	if dlnmu>np.log(4.2): #mu<mumax=4.2*mubar
	  return -np.inf
	if lnR>np.log(self.Rmax):
	  return -np.inf
	
	lnPDFmu=-0.5*(dlnmu/self.HOD.sigma_mu)**2
	lnPDFR=3.*lnR+np.log(self.Host.density(np.exp(lnR)*self.Host.Rv)) #dM/dlnR=rho*R^3. 
	return lnPDFmu+lnPDFR

  def assign_mu_R(self, nwalkers=8, nburn=200, plot_chain=True):
	'''run emcee to sample mu and R '''
	nsteps=int(self.n/nwalkers+1+nburn) #one more step to make up for potential round-off in N/nwalkers
	print 'running %d steps'%nsteps
	ndim=2
	x00=np.array([-0.5,-0.5])
	x0=np.kron(np.ones([nwalkers,1]),x00)#repmat to nwalkers rows
	x0+=(np.random.rand(ndim*nwalkers).reshape(nwalkers,ndim)-0.5)*0.1 #random offset, [-0.5,0.5]*0.1
	sampler=emcee.EnsembleSampler(nwalkers,ndim,self._lnPDF)
	sampler.run_mcmc(x0,nsteps)
	if plot_chain:
	  plt.figure()
	  labels=[r"$\ln \mu$",r"$\ln R/R_{200}$"]
	  for i in range(ndim):
		plt.subplot(ndim,1,i+1)
		for j in range(nwalkers):
		  plt.plot(range(nsteps),sampler.chain[j,:,i],'.')
		plt.ylabel(labels[i])
		plt.plot([nburn,nburn],plt.ylim(),'k--')
	  plt.xlabel('Step')
	  plt.subplot(211)
	  plt.title('%d walkers, %d burn-in steps assumed'%(nwalkers,nburn), fontsize=10)
	#==========extract mu and R===========
	sample=sampler.chain[:,nburn:,:]
	flatchain=sample.reshape([-1,ndim])[-self.n:] #take the last N entries
	flatchain=np.exp(flatchain) #from log() to linear
	self.mu,self.R=flatchain.T
	#==========disruptions===============
	if self.include_disruption:
	  self.mu[self.nSurvive:]=0. #trailing masses set to 0.
	
  def project_radius(self):
	phi=np.arccos(np.random.rand(self.n)*2-1.) #random angle around the z-axis
	self.Rp=self.R*np.sin(phi) #projected radius

  def assign_mass(self):
	'''sample m and mAcc'''
	if self.weighted_sample:
	  lnmmin,lnmmax=np.log(self.mAccMin), np.log(self.mAccMax)
	  lnmAcc=np.random.rand(self.n)*(lnmmax-lnmmin)+lnmmin #uniform distribution between lnmmin and lnmmax
	  self.mAcc=np.exp(lnmAcc)
	  self.weight=self.mAcc**-self.HOD.alpha
	  self.weight=self.weight/self.weight.sum()*self.nPred #w/sum(w)*Npred, equals to dN/dlnm*[delta(lnm)/N] as N->inf
	  #self.weight=self.HOD.fs*self.HOD.A*Host.Msample*mAcc**-self.HOD.alpha*(lnmmax-lnmmin)/self.n #the weight is dN/dlnm*[delta(lnm)/N]
	  print np.sum(self.weight), self.nPred
	else:
	  mmax,mmin=self.mAccMin**(-self.HOD.alpha),self.mAccMax**(-self.HOD.alpha) 
	  mAcc=np.random.rand(self.n)*(mmax-mmin)+mmin #uniform in m**-alpha which is proportional to N
	  self.mAcc=mAcc**-(1./self.HOD.alpha)
	  self.weight=1.*self.nPred/self.n*np.ones(self.n)
	
	self.m=self.mAcc*self.mu

  def populate(self, plot_chain=True):
	'''populate the sample with m,mAcc,R and weight'''
	self.assign_mu_R(plot_chain=plot_chain)
	self.assign_mass()
	
  def assign_stellarmass(self): 
	'''generate stellar mass from infall mass, according to an abundance matching model'''
	logMstar=np.log10(InfallMass2StellarMass(self.mAcc))
	sigmaLogMstar=0.192
	deltaLogMstar=np.random.normal(0, sigmaLogMstar, self.n)
	self.mStar=10**(logMstar+deltaLogMstar)
  
  def assign_annihilation_emission(self, concentration_model='Ludlow'):
	'''generate annihilation luminosity
	concentration_model: 'MaccioW1', Maccio08 relation with WMAP 1 cosmology
						 'Ludlow', Ludlow14 relation with WMAP 1 cosmology'''
	#first generate concentration from infall mass, according to a mass-concetration relation
	logC=np.log10(mean_concentration(self.mAcc[:self.nSurvive],concentration_model)) #mean
	sigmaLogC=0.13 
	deltaLogC=np.random.normal(0, sigmaLogC, self.nSurvive) #scatter
	cAcc=10**(logC+deltaLogC)
	SatHalo=[NFWHalo(self.mAcc[i], cAcc[i]) for i in range(self.nSurvive)]
	rt=np.array([SatHalo[i].radius(self.m[i]) for i in range(self.nSurvive)]) #truncation radius
	self.L=np.zeros_like(self.m)
	self.L[:self.nSurvive]=np.array([SatHalo[i].luminosity(rt[i]) for i in range(self.nSurvive)]) #truncated luminosity

  def save(self, outfile, save_all=False):
	''' save the sample to outfile.
	if save_all=True, save all the properties; otherwise only R,m,mAcc,weight will be saved.'''
	if save_all:
	  np.savetxt(outfile, np.array([self.R,self.m,self.mAcc,self.weight,self.Rp,self.mStar,self.L]).T, header='R/R200, m/[1e10Msun/h], mAcc/[1e10Msun/h], weight, Rp/R200, mStar/[1e10Msun/h], Luminosity/[(1e10Msun/h)^2/(kpc/h)^3]')
	else:
	  np.savetxt(outfile, np.array([self.R,self.m,self.mAcc,self.weight]).T, header='R/R200, m/[1e10Msun/h], mAcc/[1e10Msun/h], weight')