Skip to content

Commit 6294e49

Browse files
tidy; renaming; changed interface a bit so only T_AGN exposed
1 parent 7a4961b commit 6294e49

File tree

8 files changed

+357
-375
lines changed

8 files changed

+357
-375
lines changed

hmcode/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
from .hmcode import power
1+
from .hmcode import power
2+
from .hmcode import _get_feedback_suppression as get_feedback_suppression

hmcode/hmcode.py

Lines changed: 110 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# Standard imports
2-
import numpy as np
32
from time import time
43

54
# Third-party imports
5+
import numpy as np
66
import camb
77
import pyhalomodel as halo
88

@@ -15,29 +15,27 @@
1515
Pk_lin_extrap_kmax = 1e10 # NOTE: This interplays with the sigmaV integration in a disconcerting way
1616
sigma_cold_approx = False # Should the Eisenstein & Hu (1999) approximation be used for the cold transfer function?
1717

18-
def power(k:np.array, zs:np.array, CAMB_results:camb.CAMBdata,
19-
Mmin=1e0, Mmax=1e18, nM=256, verbose=False,
20-
baryons=False, baryon_params=None, hmcodetweaks=True) -> np.ndarray:
18+
def power(k:np.array, zs:np.array, CAMB_results:camb.CAMBdata, T_AGN=None,
19+
Mmin=1e0, Mmax=1e18, nM=256, tweaks=True, verbose=False) -> np.ndarray:
2120
'''
2221
Calculates the HMcode matter-matter power spectrum
2322
Args:
2423
k: Array of comoving wavenumbers [h/Mpc]
2524
zs: Array of redshifts (ordered from high to low)
2625
CAMB_results: CAMBdata structure
26+
T_AGN: AGN feedback temperature [K] (None to disable)
2727
Mmin: Minimum mass for the halo-model calculation [Msun/h]
2828
Mmax: Maximum mass for the halo-model calculation [Msun/h]
2929
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
30+
tweaks: Use the changes to the vanilla halo model from HMCode2020 if true
3331
Returns:
3432
Array of matter power spectra: Pk[z, k]
3533
'''
3634

3735
# Checks
3836
if verbose: t_start = time()
3937
if not util.is_array_monotonic(-np.array(zs)):
40-
raise ValueError('Redshift must be monotonically decreasing')
38+
raise ValueError('Redshifts must be monotonically decreasing')
4139

4240
# Halo mass range
4341
M = util.logspace(Mmin, Mmax, nM)
@@ -64,15 +62,19 @@ def power(k:np.array, zs:np.array, CAMB_results:camb.CAMBdata,
6462
print('Linear growth at z=0: {:.3}'.format(growth(1.)))
6563
print()
6664

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()
65+
# Baryonic feedback
66+
if T_AGN:
67+
feedback_params = _get_feedback_parameters(T_AGN)
68+
if verbose:
69+
print('Using baryonic feedback model from HMCode2020')
70+
print('log_10(T_AGN/K): {:.2f}'.format(np.log10(T_AGN)))
71+
print('B_0: {:.4f}'.format(feedback_params['B0']))
72+
print('B_z: {:.4f}'.format(feedback_params['Bz']))
73+
print('Mb_0: {:.1e}'.format(feedback_params['Mb0']))
74+
print('Mb_z: {:.4f}'.format(feedback_params['Mbz']))
75+
print('f*_0: {:.4f}'.format(feedback_params['f0']))
76+
print('f*_z: {:.4f}'.format(feedback_params['fz']))
77+
print()
7678

7779
# Linear power interpolator
7880
interp, _, k_interp = CAMB_results.get_matter_power_interpolator(nonlinear=False,
@@ -144,46 +146,36 @@ def power(k:np.array, zs:np.array, CAMB_results:camb.CAMBdata,
144146
print('RMS in matter displacement field: {:.4} Mpc/h'.format(sigmaV))
145147
print('Effective index at collapse scale: {:.4}'.format(neff))
146148

147-
# HMcode parameters (Table 2 of https://arxiv.org/pdf/2009.01858.pdf)
148-
kd = 0.05699*sigma8**-1.089 # Two-halo damping wavenumber; equation (16)
149-
f = 0.2696*sigma8**0.9403 # Two-halo fractional damping; equation (16)
150-
nd = 2.853 # Two-halo damping power; equation (16)
151-
ks = 0.05618*sigma8**-1.013 # One-halo damping wavenumber; equation (17)
152-
eta = 0.1281*sigma8**-0.3644 # Halo bloating parameter; equation (19)
153-
B = 5.196 # Minimum halo concentration; equation (20)
154-
alpha = 1.875*(1.603)**neff # Transition smoothing; equation (23)
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:
163-
print('Two-halo damping wavenumber; kd: {:.4} h/Mpc'.format(kd))
164-
print('Two-halo fractional damping; f: {:.4}'.format(f))
165-
print('Two-halo damping power; nd: {:.4}'.format(nd))
166-
print('One-halo damping wavenumber; k*: {:.4} h/Mpc'.format(ks))
167-
print('Halo bloating; eta: {:.4}'.format(eta))
168-
print('Minimum halo concentration; B: {:.4}'.format(B))#, B/4.)
169-
print('Transition smoothing; alpha: {:.4}'.format(alpha))
170-
print()
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-
149+
if tweaks: # HMcode parameters (Table 2 of https://arxiv.org/pdf/2009.01858.pdf)
150+
kd = 0.05699*sigma8**-1.089 # Two-halo damping wavenumber; equation (16)
151+
f = 0.2696*sigma8**0.9403 # Two-halo fractional damping; equation (16)
152+
nd = 2.853 # Two-halo damping power; equation (16)
153+
ks = 0.05618*sigma8**-1.013 # One-halo damping wavenumber; equation (17)
154+
eta = 0.1281*sigma8**-0.3644 # Halo bloating parameter; equation (19)
155+
B = 5.196 # Minimum halo concentration; equation (20)
156+
alpha = 1.875*(1.603)**neff # Transition smoothing; equation (23)
157+
else: # Use vanilla-ish halo model if no HMcode tweaks used
158+
B, eta = 4., 0.
159+
160+
if T_AGN:
161+
B = feedback_params['B0']*np.power(10, z*feedback_params['Bz'])
162+
Mb = feedback_params['Mb0']*np.power(10, z*feedback_params['Mbz'])
163+
fstar = feedback_params['f0']*np.power(10, z*feedback_params['fz'])
164+
165+
if verbose:
166+
if tweaks:
167+
print('Two-halo damping wavenumber; kd: {:.4} h/Mpc'.format(kd))
168+
print('Two-halo fractional damping; f: {:.4}'.format(f))
169+
print('Two-halo damping power; nd: {:.4}'.format(nd))
170+
print('One-halo damping wavenumber; k*: {:.4} h/Mpc'.format(ks))
171+
print('Halo bloating; eta: {:.4}'.format(eta))
172+
print('Minimum halo concentration; B: {:.4}'.format(B))#, B/4.)
173+
print('Transition smoothing; alpha: {:.4}'.format(alpha))
174+
if T_AGN:
175+
print('Gas-loss halo-mass parameter Mb: {:1e}'.format(Mb))
176+
print('Effective halo stellar-mass fraction f*: {:.4f}'.format(f))
177+
print()
178+
187179
# Halo concentration
188180
zf = _get_halo_collapse_redshifts(M, z, iz, dc, growth, CAMB_results, cold=True) # Halo formation redshift
189181
c = B*(1+zf)/(1.+z) # Halo concentration; equation (20)
@@ -194,37 +186,39 @@ def power(k:np.array, zs:np.array, CAMB_results:camb.CAMBdata,
194186
rv = hmod.virial_radius(M)
195187
Uk = np.ones((len(k), len(M)))
196188
for iM, (_rv, _c, _nu) in enumerate(zip(rv, c, nu)): # TODO: Remove loop for speed?
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-
189+
if T_AGN:
190+
Uk[:, iM] = _win_NFW_baryons(k*(_nu**eta), _rv, _c, M[iM], Mb, fstar, Om_m, Om_c, Om_b)[:, 0]
200191
else:
201192
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-
193+
if T_AGN: # NOTE: No Factor of 1-f_nu for baryonic, because this effect is already included!
194+
profile = halo.profile.Fourier(k, M, Uk, amplitude=M/hmod.rhom, mass_tracer=True)
195+
else: # NOTE: Factor of 1-f_nu in profile amplitude
196+
profile = halo.profile.Fourier(k, M, Uk, amplitude=M*(1.-f_nu)/hmod.rhom, mass_tracer=True)
197+
208198
# Vanilla power spectrum calculation
209-
_, Pk_1h_, _ = hmod.power_spectrum(k, Pk_lin, M, sigmaM, {'m': profile}, simple_twohalo=True)
199+
_, _Pk_1h, _ = hmod.power_spectrum(k, Pk_lin, M, sigmaM, {'m': profile}, simple_twohalo=True)
210200

211201
# HMcode tweaks
212-
P_wig = _get_Pk_wiggle(k, Pk_lin, CAMB_results) # Isolate spectral wiggle; footnote 7
213-
Pk_dwl = Pk_lin-(1.-np.exp(-(k*sigmaV)**2))*P_wig # Constuct linear spectrum with smoothed wiggle; equation (15)
214-
Pk_2h = Pk_dwl*(1.-f*(k/kd)**nd/(1.+(k/kd)**nd)) # Two-halo term; equation (16)
215-
Pk_1h = (k/ks)**4/(1.+(k/ks)**4)*Pk_1h_['m-m'] # One-halo term; equation (17)
216-
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-
202+
if tweaks:
203+
Pk_wig = _get_Pk_wiggle(k, Pk_lin, CAMB_results) # Isolate spectral wiggle; footnote 7
204+
Pk_dwl = Pk_lin-(1.-np.exp(-(k*sigmaV)**2))*Pk_wig # Constuct linear spectrum with smoothed wiggle; equation (15)
205+
Pk_2h = Pk_dwl*(1.-f*(k/kd)**nd/(1.+(k/kd)**nd)) # Two-halo term; equation (16)
206+
Pk_1h = (k/ks)**4/(1.+(k/ks)**4)*_Pk_1h['m-m'] # One-halo term; equation (17)
207+
Pk_hm = (Pk_2h**alpha+Pk_1h**alpha)**(1./alpha) # Total prediction via smoothed sum; equation (23)
208+
else:
209+
Pk_hm = Pk_lin+_Pk_1h['m-m']
221210
Pk_HMcode[iz, :] = Pk_hm
222211

212+
if tweaks and T_AGN:
213+
suppression = _get_feedback_suppression(k, zs, CAMB_results, T_AGN, Mmin=Mmin, Mmax=Mmax, nM=nM, verbose=False)
214+
Pk_HMcode *= suppression
215+
223216
# Finish
224217
if verbose:
225218
t_finish = time()
226219
print('HMcode predictions complete for {:} redshifts'.format(len(zs)))
227220
print('Total HMcode run time: {:.3f}s'.format(t_finish-t_start))
221+
print()
228222
return Pk_HMcode
229223

230224

@@ -328,56 +322,50 @@ def _win_NFW(k:np.ndarray, rv:np.ndarray, c:np.ndarray) -> np.ndarray:
328322
return Wk
329323

330324

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)
325+
def _win_NFW_baryons(k:np.ndarray, rv:np.ndarray, c:np.ndarray,
326+
M:np.ndarray, Mb:float, fstar:float,
327+
Om_m:float, Om_c:float, Om_b:float) -> np.ndarray:
328+
'''
329+
Normalised Fourier transform for NFW profile, including baryonic effects
330+
Equation (25) from Mead et al. (2021)
334331
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-
332+
'''
333+
Wk = _win_NFW(k, rv, c)
334+
fg = (Om_b/Om_m-fstar)*(M/Mb)**2/(1.+(M/Mb)**2) # Gas content (Eq. 24 with beta=2)
335+
Wk = (Om_c/Om_m+fg)*Wk
336+
Wk += fstar
342337
return Wk
343338

344339

345-
def get_Baryon_Parameters(T_AGN:float) -> dict:
346-
"""Maps 1-Param baryon feedback model from HMCode2020 to 6 baryonic parameters
340+
def _get_feedback_parameters(T_AGN:float) -> dict:
341+
'''
342+
Maps one-Param baryon feedback model from HMCode2020 to 6 baryonic parameters
347343
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
344+
This fit was obtained using the vanilla halo model!
345+
If the hmcode tweaks are used, different values are likely needed.
346+
'''
347+
theta = np.log10(T_AGN/np.power(10, 7.8))
348+
params = {
349+
'B0': 3.44-0.496*theta,
350+
'Bz': -0.0671-0.0371*theta,
351+
'Mb0': np.power(10, 13.87+1.81*theta), # [Msun/h]
352+
'Mbz': -0.108+0.195*theta,
353+
'f0': (2.01-0.3*theta)*1e-2,
354+
'fz': 0.409+0.0224*theta,
355+
}
366356
return params
367357

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
358+
359+
def _get_feedback_suppression(k:np.array, zs:np.array, CAMB_results:camb.CAMBdata, T_AGN:float,
360+
Mmin=1e0, Mmax=1e18, nM=256, verbose=False) -> np.ndarray:
361+
'''
362+
Calculates the ratio of the powerspectrum with baryonic effects to that of dark-matter-only
363+
Assumes the one-parameter T_AGN model from HMCode2020
364+
Warning: Since the fit for the baryonic effects was obtained with the vanilla halo model,
365+
it is not safe to set tweaks=True below
366+
'''
367+
Pk_gravity = power(k, zs, CAMB_results, T_AGN=None, Mmin=Mmin, Mmax=Mmax, nM=nM,
368+
tweaks=False, verbose=verbose)
369+
Pk_feedback = power(k, zs, CAMB_results, T_AGN=T_AGN, Mmin=Mmin, Mmax=Mmax, nM=nM,
370+
tweaks=False, verbose=verbose)
371+
return Pk_feedback/Pk_gravity

notebooks/demo.ipynb

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,9 @@
1818
"metadata": {},
1919
"outputs": [],
2020
"source": [
21-
"# Standard imports\n",
21+
"# Third-party imports\n",
2222
"import numpy as np\n",
2323
"import matplotlib.pyplot as plt\n",
24-
"\n",
25-
"# Third-party imports\n",
2624
"import camb\n",
2725
"import pyhalomodel as halo\n",
2826
"\n",
@@ -257,7 +255,7 @@
257255
"name": "python",
258256
"nbconvert_exporter": "python",
259257
"pygments_lexer": "ipython3",
260-
"version": "3.10.9"
258+
"version": "3.11.2"
261259
},
262260
"orig_nbformat": 4,
263261
"vscode": {

0 commit comments

Comments
 (0)