1616sigma_cold_approx = False # Should the Eisenstein & Hu (1999) approximation be used for the cold transfer function?
1717
1818def power (k :np .array , zs :np .array , CAMB_results :camb .CAMBdata ,
19- Mmin = 1e0 , Mmax = 1e18 , nM = 256 , verbose = False ) -> np .ndarray :
19+ Mmin = 1e0 , Mmax = 1e18 , nM = 256 , verbose = False ,
20+ baryons = False , baryon_params = None , hmcodetweaks = True ) -> np .ndarray :
2021 '''
2122 Calculates the HMcode matter-matter power spectrum
2223 Args:
@@ -26,6 +27,9 @@ def power(k:np.array, zs:np.array, CAMB_results:camb.CAMBdata,
2627 Mmin: Minimum mass for the halo-model calculation [Msun/h]
2728 Mmax: Maximum mass for the halo-model calculation [Msun/h]
2829 nM: Number of mass bins for the halo-model calculation
30+ baryons: if true: include baryonic effects from HMCode2020; if false: Dark Matter Only
31+ baryon_params: Dictionary containing the 6 baryonic parameters from HMCode2020
32+ hmcodetweaks: if true: Use the changes to the vanilla halo model from HMCode2020; if false: Use vanilla halo model
2933 Returns:
3034 Array of matter power spectra: Pk[z, k]
3135 '''
@@ -60,6 +64,16 @@ def power(k:np.array, zs:np.array, CAMB_results:camb.CAMBdata,
6064 print ('Linear growth at z=0: {:.3}' .format (growth (1. )))
6165 print ()
6266
67+ if verbose and baryons :
68+ print ("Using baryonic feedback model from HMCode2020" )
69+ print ("B0: {:.4f}" .format (baryon_params ["B0" ]))
70+ print ("Bz: {:.4f}" .format (baryon_params ["Bz" ]))
71+ print ("Mb0: {:.1e}" .format (baryon_params ["Mb0" ]))
72+ print ("Mbz: {:.4f}" .format (baryon_params ["Mbz" ]))
73+ print ("f*0: {:.4f}" .format (baryon_params ["f0" ]))
74+ print ("f*z: {:.4f}" .format (baryon_params ["fz" ]))
75+ print ()
76+
6377 # Linear power interpolator
6478 interp , _ , k_interp = CAMB_results .get_matter_power_interpolator (nonlinear = False ,
6579 return_z_k = True ,
@@ -96,6 +110,7 @@ def power(k:np.array, zs:np.array, CAMB_results:camb.CAMBdata,
96110 print ('Linear collapse threshold: {:.4}' .format (dc ))
97111 print ('Virial halo overdensity: {:.4}' .format (Dv ))
98112
113+
99114 # Initialise halo model
100115 hmod = halo .model (z , Om_m , name = 'Sheth & Tormen (1999)' , Dv = Dv , dc = dc )
101116
@@ -135,9 +150,16 @@ def power(k:np.array, zs:np.array, CAMB_results:camb.CAMBdata,
135150 nd = 2.853 # Two-halo damping power; equation (16)
136151 ks = 0.05618 * sigma8 ** - 1.013 # One-halo damping wavenumber; equation (17)
137152 eta = 0.1281 * sigma8 ** - 0.3644 # Halo bloating parameter; equation (19)
138- B = 5.196 # Minimum halo concentration; equation (20)
153+ B = 5.196 # Minimum halo concentration; equation (20)
139154 alpha = 1.875 * (1.603 )** neff # Transition smoothing; equation (23)
140- if verbose :
155+
156+
157+ if hmcodetweaks == False : #Go to vanilla halo model if no hmcode tweaks should be used
158+ B = 4
159+ eta = 0
160+ alpha = 1
161+
162+ if verbose and hmcodetweaks :
141163 print ('Two-halo damping wavenumber; kd: {:.4} h/Mpc' .format (kd ))
142164 print ('Two-halo fractional damping; f: {:.4}' .format (f ))
143165 print ('Two-halo damping power; nd: {:.4}' .format (nd ))
@@ -146,7 +168,22 @@ def power(k:np.array, zs:np.array, CAMB_results:camb.CAMBdata,
146168 print ('Minimum halo concentration; B: {:.4}' .format (B ))#, B/4.)
147169 print ('Transition smoothing; alpha: {:.4}' .format (alpha ))
148170 print ()
149-
171+ elif verbose :
172+ print ("Using vanilla halo model" )
173+
174+ if baryons :
175+ B = baryon_params ["B0" ]* np .power (10 ,z * baryon_params ["Bz" ])
176+ Mb = baryon_params ["Mb0" ]* np .power (10 , z * baryon_params ["Mbz" ])
177+ fstar = baryon_params ["f0" ]* np .power (10 , z * baryon_params ["fz" ])
178+
179+
180+
181+ if verbose and baryons :
182+ print ("Halo concentration parameter B:{:.4f}" .format (B ))
183+ print ("Gas loss halo mass parameter Mb:{:1e}" .format (Mb ))
184+ print ("Effective halo stellar mass fraction fstar:{:.4f}" .format (f ))
185+
186+
150187 # Halo concentration
151188 zf = _get_halo_collapse_redshifts (M , z , iz , dc , growth , CAMB_results , cold = True ) # Halo formation redshift
152189 c = B * (1 + zf )/ (1. + z ) # Halo concentration; equation (20)
@@ -157,18 +194,30 @@ def power(k:np.array, zs:np.array, CAMB_results:camb.CAMBdata,
157194 rv = hmod .virial_radius (M )
158195 Uk = np .ones ((len (k ), len (M )))
159196 for iM , (_rv , _c , _nu ) in enumerate (zip (rv , c , nu )): # TODO: Remove loop for speed?
160- Uk [:, iM ] = _win_NFW (k * (_nu ** eta ), _rv , _c )[:, 0 ]
161- profile = halo .profile .Fourier (k , M , Uk , amplitude = M * (1. - f_nu )/ hmod .rhom , mass_tracer = True ) # NOTE: Factor of 1-f_nu
162-
197+ if baryons :
198+ Uk [:, iM ] = _win_NFW_baryons (k * (_nu ** eta ), _rv , _c , M [iM ], Mb , fstar , Om_b , Om_m , Om_c , hmod .rhom )[:,0 ]
199+
200+ else :
201+ Uk [:, iM ] = _win_NFW (k * (_nu ** eta ), _rv , _c )[:, 0 ]
202+ if baryons :
203+ profile = halo .profile .Fourier (k , M , Uk , amplitude = M / hmod .rhom , mass_tracer = True ) # NOTE: No Factor of 1-f_nu for baryonic, because this effect is already included!
204+
205+ else :
206+ profile = halo .profile .Fourier (k , M , Uk , amplitude = M * (1. - f_nu )/ hmod .rhom , mass_tracer = True ) # NOTE: Factor of 1-f_nu
207+
163208 # Vanilla power spectrum calculation
164- _ , Pk_1h , _ = hmod .power_spectrum (k , Pk_lin , M , sigmaM , {'m' : profile }, simple_twohalo = True )
209+ _ , Pk_1h_ , _ = hmod .power_spectrum (k , Pk_lin , M , sigmaM , {'m' : profile }, simple_twohalo = True )
165210
166211 # HMcode tweaks
167212 P_wig = _get_Pk_wiggle (k , Pk_lin , CAMB_results ) # Isolate spectral wiggle; footnote 7
168213 Pk_dwl = Pk_lin - (1. - np .exp (- (k * sigmaV )** 2 ))* P_wig # Constuct linear spectrum with smoothed wiggle; equation (15)
169214 Pk_2h = Pk_dwl * (1. - f * (k / kd )** nd / (1. + (k / kd )** nd )) # Two-halo term; equation (16)
170- Pk_1h = (k / ks )** 4 / (1. + (k / ks )** 4 )* Pk_1h ['m-m' ] # One-halo term; equation (17)
215+ Pk_1h = (k / ks )** 4 / (1. + (k / ks )** 4 )* Pk_1h_ ['m-m' ] # One-halo term; equation (17)
171216 Pk_hm = (Pk_2h ** alpha + Pk_1h ** alpha )** (1. / alpha ) # Total prediction via smoothed sum; equation (23)
217+
218+ if hmcodetweaks == False :
219+ Pk_hm = Pk_lin + Pk_1h_ ['m-m' ]
220+
172221 Pk_HMcode [iz , :] = Pk_hm
173222
174223 # Finish
@@ -276,4 +325,59 @@ def _win_NFW(k:np.ndarray, rv:np.ndarray, c:np.ndarray) -> np.ndarray:
276325 f3 = np .sin (kv )/ (ks + kv )
277326 f4 = np .log (1. + c )- c / (1. + c )
278327 Wk = (f1 + f2 - f3 )/ f4
279- return Wk
328+ return Wk
329+
330+
331+ def _win_NFW_baryons (k :np .ndarray , rv :np .ndarray , c :np .ndarray , M :np .ndarray , Mb :float , f :float , Om_b :float , Om_m :float , Om_c :float , rhom :float ) -> np .ndarray :
332+ """Normalised Fourier transform for NFW profile, including baryonic effects
333+ Is the same as Equation (25) of Mead et al. (2021)
334+ Calls _win_NFW
335+ """
336+ Wk = _win_NFW (k , rv , c )
337+
338+ fg = (Om_b / Om_m - f )* (M / Mb )** 2 / (1 + (M / Mb )** 2 ) #Gas content (Eq. 24 with beta=2 specified)
339+ Wk = ((Om_c )/ Om_m + fg )* Wk
340+ Wk += f
341+
342+ return Wk
343+
344+
345+ def get_Baryon_Parameters (T_AGN :float ) -> dict :
346+ """Maps 1-Param baryon feedback model from HMCode2020 to 6 baryonic parameters
347+ Uses parameters from Table 5 in Mead et al. (2021)
348+ Warning:
349+ This fit was obtained using the vanilla halo model! If the hmcode tweaks are used, different values are likely needed.
350+
351+ Args:
352+ T_AGN (float): AGN Temperature parameter
353+
354+ Returns:
355+ dict: baryonification parameters, B0, Bz, Mb0, Mbz, f0, fz
356+ """
357+
358+ theta = np .log10 (T_AGN / np .power (10 ,7.8 ))
359+ params = {}
360+ params ["B0" ]= 3.44 - 0.496 * theta
361+ params ["Bz" ]= - 0.0671 - 0.0371 * theta
362+ params ["Mb0" ]= np .power (10 , 13.87 + 1.81 * theta ) #Units: Msun/h
363+ params ["Mbz" ]= - 0.108 + 0.195 * theta
364+ params ["f0" ]= (2.01 - 0.3 * theta )* 1e-2
365+ params ["fz" ]= 0.409 + 0.0224 * theta
366+ return params
367+
368+ def get_Baryon_Suppression (k :np .array , zs :np .array , CAMB_results :camb .CAMBdata , T_AGN = None , hmcodetweaks = False ,
369+ Mmin = 1e0 , Mmax = 1e18 , nM = 256 , verbose = False ):
370+ """Calculates the ratio of the powerspectrum with baryonic effect to the dark-matter-only powerspectrum for a given T_AGN
371+ Assumes the 1-param model from HMCode2020
372+ Warning:
373+ Since the fit for the baryonic effects was obtained with the vanilla halo model, it is not safe to set hmcodetweaks=True
374+ """
375+
376+
377+ baryon_params = get_Baryon_Parameters (T_AGN )
378+
379+ Pk_dmo = power (k , zs , CAMB_results , Mmin , Mmax , nM , verbose , baryons = False , hmcodetweaks = hmcodetweaks )
380+
381+ Pk_bar = power (k , zs , CAMB_results , Mmin , Mmax , nM , verbose , baryons = True , baryon_params = baryon_params , hmcodetweaks = hmcodetweaks )
382+
383+ return Pk_bar / Pk_dmo
0 commit comments