Skip to content

Commit 1aa09dc

Browse files
sutiengrrjbca
andauthored
ENH: Add a mass sampler for the colossus halo mass function (#423)
Co-authored-by: Richard R <58728519+rrjbca@users.noreply.github.com>
1 parent 862af0b commit 1aa09dc

File tree

4 files changed

+113
-0
lines changed

4 files changed

+113
-0
lines changed

setup.cfg

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,11 @@ test =
3434
speclite>=0.11
3535
all =
3636
speclite>=0.11
37+
colossus
3738
docs =
3839
sphinx-astropy
3940
matplotlib
41+
colossus
4042
speclite>=0.11
4143

4244
[options.package_data]

skypy/halos/_colossus.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
"""Colossus dark matter halo properties.
2+
3+
This module contains functions that interfaces with the external code
4+
`Colossus <http://www.benediktdiemer.com/code/colossus/>`_.
5+
6+
"""
7+
8+
import numpy as np
9+
from scipy import integrate
10+
11+
__all__ = [
12+
'colossus_mass_sampler',
13+
]
14+
15+
try:
16+
import colossus # noqa F401
17+
except ImportError:
18+
HAS_COLOSSUS = False
19+
else:
20+
HAS_COLOSSUS = True
21+
22+
23+
def colossus_mass_sampler(redshift, model, mdef, m_min, m_max,
24+
cosmology, sigma8, ns, size=None, resolution=1000):
25+
"""Colossus halo mass sampler.
26+
27+
This function generate a sample of halos from a mass function which
28+
is available in COLOSSUS [1]_.
29+
30+
Parameters
31+
----------
32+
redshift : float
33+
The redshift values at which to sample the halo mass.
34+
model : string
35+
Mass function model which is available in colossus.
36+
mdef : str
37+
Halo mass definition for spherical overdensities used by colossus.
38+
m_min, m_max : float
39+
Lower and upper bounds for halo mass in units of Solar mass, Msun.
40+
cosmology : astropy.cosmology.Cosmology
41+
Astropy cosmology object
42+
sigma8 : float
43+
Cosmology parameter, amplitude of the (linear) power spectrum on the
44+
scale of 8 Mpc/h.
45+
ns : float
46+
Cosmology parameter, spectral index of scalar perturbation power spectrum.
47+
size : int, optional
48+
Number of halos to sample. If size is None (default), a single value is returned.
49+
resolution : int, optional
50+
Resolution of the inverse transform sampling spline. Default is 1000.
51+
52+
Returns
53+
-------
54+
sample : (size,) array_like
55+
Samples drawn from the mass function, in units of solar masses.
56+
57+
References
58+
----------
59+
.. [1] Diemer B., 2018, ApJS, 239, 35
60+
61+
"""
62+
from colossus.cosmology.cosmology import fromAstropy
63+
from colossus.lss import mass_function
64+
fromAstropy(cosmology, sigma8=sigma8, ns=ns)
65+
h0 = cosmology.h
66+
m_h0 = np.logspace(np.log10(m_min*h0), np.log10(m_max*h0), resolution) # unit: Msun/h
67+
dndm = mass_function.massFunction(m_h0, redshift, mdef=mdef, model=model,
68+
q_out='dndlnM', q_in='M')/m_h0
69+
m = m_h0/h0
70+
CDF = integrate.cumtrapz(dndm, (m), initial=0)
71+
CDF = CDF / CDF[-1]
72+
n_uniform = np.random.uniform(size=size)
73+
masssample = np.interp(n_uniform, CDF, m)
74+
return masssample

skypy/halos/mass.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
:nosignatures:
88
:toctree: ../api/
99
10+
colossus_mass_sampler
1011
ellipsoidal_collapse_function
1112
halo_mass_function
1213
halo_mass_sampler
@@ -27,8 +28,10 @@
2728
from functools import partial
2829
from astropy import units
2930
from skypy.utils.random import schechter
31+
from ._colossus import colossus_mass_sampler # noqa F401,F403
3032

3133
__all__ = [
34+
'colossus_mass_sampler',
3235
'ellipsoidal_collapse_function',
3336
'halo_mass_function',
3437
'halo_mass_sampler',

skypy/halos/tests/test_colossus.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import numpy as np
2+
from scipy import integrate
3+
from scipy.stats import kstest
4+
import pytest
5+
from skypy.halos._colossus import HAS_COLOSSUS
6+
7+
8+
@pytest.mark.skipif(not HAS_COLOSSUS, reason='test requires colossus')
9+
@pytest.mark.flaky
10+
def test_colossus_mass_sampler():
11+
from astropy.cosmology import WMAP9
12+
from colossus.cosmology.cosmology import fromAstropy
13+
from colossus.lss import mass_function
14+
from skypy.halos.mass import colossus_mass_sampler
15+
m_min, m_max, size = 1e+12, 1e+16, 100
16+
sample = colossus_mass_sampler(redshift=0.1, model='despali16',
17+
mdef='500c', m_min=m_min, m_max=m_max,
18+
cosmology=WMAP9, sigma8=0.8200, ns=0.9608,
19+
size=size, resolution=1000)
20+
assert np.all(sample >= m_min)
21+
assert np.all(sample <= m_max)
22+
assert np.shape(sample) == (size,)
23+
fromAstropy(WMAP9, sigma8=0.8200, ns=0.9608)
24+
h0 = WMAP9.h
25+
m_h0 = np.logspace(np.log10(1e+12*h0), np.log10(1e+16*h0), 1000)
26+
dndm = mass_function.massFunction(m_h0, 0.1, mdef='500c', model='despali16',
27+
q_out='dndlnM', q_in='M')/m_h0
28+
m = m_h0/h0
29+
CDF = integrate.cumtrapz(dndm, (m), initial=0)
30+
CDF = CDF / CDF[-1]
31+
32+
D, p = kstest(sample, lambda t: np.interp(t, m, CDF))
33+
34+
assert p > 0.01, 'D = {}, p = {}'.format(D, p)

0 commit comments

Comments
 (0)