A Showcase of Components in halomod

In this demo, we will showcase each and every one of the different models and components in halomod, to give a taste of its capabilities. Note that the plots generated in this notebook appear in THIS PAPER.

[1]:
import halomod
import hmf
import numpy as np
print(f"Using halomod v{halomod.__version__}")
print(f"Using hmf v{hmf.__version__}")
from halomod.bias import make_colossus_bias
from halomod.concentration import make_colossus_cm
Using halomod v1.6.1.dev3+ge514be1.d20200819
Using hmf v3.3.4.dev14+g9a9b63c.d20210610

Setup Matplotlib

[2]:
%matplotlib inline

import matplotlib.pyplot as plt

from matplotlib import rc, rcParams

Since these plots will be included in a paper, we define some preset configurations for different kinds of plots, to achieve some consistency.

[3]:
paper_font_size = 10  # elsarticle

def single_column(height_ratio=1/1.5):
    linewidth = 3.49  # Get this in your tex using \printinunitsof{in}\prntlen{\linewidth}
    paper_settings(linewidth, height_ratio)


def two_column(height_ratio = 1/1.5):
    textwidth = 7.22  # Get this in your tex using \printinunitsof{in}\prntlen{\textwidth}
    paper_settings(textwidth, height_ratio)

def paper_settings(width, height_ratio = 1/1.5):
    plt.style.use("seaborn-paper")

    rc('figure', figsize=(width, width * height_ratio), dpi=200)
    rc(('xtick', 'ytick'), labelsize=paper_font_size - 2, direction='in')
    rc('legend', fontsize=paper_font_size-1, frameon=False, columnspacing=1, handletextpad=0.4)
    rc('axes', labelsize=paper_font_size-1)

    rc("savefig", dpi=600, bbox='tight')

Setup default model

Some of the components presented here can be calculated using lower-level frameworks, but all of them can be calculated from the TracerHaloModel, so we use this.

[4]:
from halomod import TracerHaloModel
[5]:
base_model = TracerHaloModel(
    dr_table = 0.03,
    dlnk = 0.05,
    dlog10m = 0.05,
    transfer_params={
        'kmax':1e2
    }
)

# Pre-compute many of the relevant quantities
base_model.power_auto_tracer;
recalcing dndm
/home/steven/Documents/Projects/halos/HALOMOD/halomod/src/halomod/halo_model.py:1250: RuntimeWarning: overflow encountered in double_scalars
  c[i] = tools.spline_integral(self.m, intg, xmin=10 ** mmin)
/home/steven/Documents/Projects/halos/HMF/hmf/src/hmf/density_field/halofit.py:106: UserWarning: sigma_8 is not used any more, and will be removed in v4
  warnings.warn("sigma_8 is not used any more, and will be removed in v4")

Since most of the plots we make will be comparing all possible models of a particular component, we define a simple function to find all the models for a particular component:

[6]:
import importlib

def get_models(module, base_class, ignore=()):
    mod = importlib.import_module(module)
    cls = getattr(mod, base_class)

    out = []
    for v in mod.__dict__.values():
        try:
            if issubclass(v, cls) and v != cls and v.__name__ not in ignore:
                out.append(v)
        except TypeError:
            pass
    return out

For bias models:

[7]:
get_models('halomod.bias', 'Bias')
[7]:
[halomod.bias.UnityBias,
 halomod.bias.Mo96,
 halomod.bias.Jing98,
 halomod.bias.ST99,
 halomod.bias.SMT01,
 halomod.bias.Seljak04,
 halomod.bias.Seljak04Cosmo,
 halomod.bias.Tinker05,
 halomod.bias.Mandelbaum05,
 halomod.bias.Pillepich10,
 halomod.bias.Manera10,
 halomod.bias.Tinker10,
 halomod.bias.Tinker10PBSplit]

Now, define a function that will do most of the plotting for us. It will grab all the models defined for a particular component, and plot a resulting quantity for all of them, with a lower panel showing the ratio to the fiducial model.

[10]:
import random

def model_comparison_plot(
    module, component, attr_name, x, y, ignore=(),
    height_ratio=1/1.5, ylab=None, y_unit = None,
    yratio_lab = None, ylog=True, comparison_limits=(0.8, 1.2), xlim=None,
    ylim=None, must_include=(),
    ncol_legend=1, legend_size=None, max_models=10, extra_models=None,
    extra_params=None
):
    extra_params=extra_params or {}
    extra_models = extra_models or []
    # Get all the models for this component
    models = get_models(module, component, ignore)
    if extra_models:
        models += extra_models

    # Limit them to seven models (randomly)
    if len(models) > max_models:
        print(f"Randomly choosing {max_models} out of {len(models)} models.")
        tmp_models = [m for m in models if m.__name__ in must_include or m in extra_models]
        for m in tmp_models:
            models.remove(m)

        models = random.sample(models, max_models - len(tmp_models))
        models.extend(tmp_models)

    # Most model comparison plots will be single column in the paper.
    single_column(height_ratio)

    subplot_kw = {"xscale": 'log'}
    if xlim:
        subplot_kw['xlim'] = xlim

    # Create a two-panel plot with the lower panel slightly smaller.
    fig, ax = plt.subplots(
        2, 1, sharex=True,
        gridspec_kw={"hspace": 0, 'height_ratios': [3, 2]},
        subplot_kw=subplot_kw
    )

    # Plot the different models.
    model = base_model.clone()  # Make a new updateable model.
    for i, cmp_model in enumerate(models):
        if cmp_model.__name__ != getattr(base_model, attr_name).__name__:
            model.update(**{attr_name.replace("model", 'params'): extra_params.get(cmp_model.__name__, {})})

        model.update(**{attr_name: cmp_model})
        if cmp_model in extra_models:
            ls = ':'
        else:
            ls = ['-', '--', ':'][i//10]

        xx = getattr(model, x)
        if x == 'nu':
            xx = np.sqrt(xx)
        ax[0].plot(xx, getattr(model, y), label=cmp_model.__name__, lw=1, ls=ls)
        ax[1].plot(xx, getattr(model, y) / getattr(base_model, y), ls=ls)

    if ylog:
        ax[0].set_yscale('log')

    ax[0].legend(ncol=ncol_legend, fontsize=legend_size or rcParams['legend.fontsize'])

    ylab = ylab or y

    # Set axis labels and limits.
    if y_unit:
        ylabel = f"{ylab} [{y_unit}]"
    else:
        ylabel = ylab

    ax[0].set_ylabel(ylabel)
    if x == 'k':
        ax[1].set_xlabel("k [$h$ / Mpc]")
    elif x == 'm':
        ax[1].set_xlabel("m [$h^{-1} M_\odot$]")
    elif x == 'nu':
        ax[1].set_xlabel(r"Peak-height, $\nu$")

    if yratio_lab is None:
        yratio_lab = ylab

    ax[1].set_ylabel(r"%s / $%s_{\rm %s}$" %(yratio_lab, yratio_lab.replace("$", ""), getattr(base_model, attr_name).__name__))
    ax[1].set_ylim(comparison_limits)

    if ylim:
        ax[0].set_ylim(ylim)

    # Save the figure
    plt.savefig(f"plots/{attr_name}s.pdf")

Transfer Function

First, transfer functions. We omit the models that require user input (eg. FromFile).

The transfer function determines the linear power spectrum, which in turn affects the halo mass function (more power on larger scales means more high-mass halos).

[9]:
model_comparison_plot(
    module="hmf.density_field.transfer_models",
    component = 'TransferComponent',
    ignore=('FromFile','FromArray', 'EH'),
    attr_name = 'transfer_model',
    x = 'k',
    y = 'power',
    ylab = r"$P_{\rm lin}(k)$",
    y_unit = r"$h^{-3}{\rm Mpc}^3$",
    xlim = (1e-4, 1e2),
    yratio_lab = r"$P^{\rm lin}$",
    height_ratio = 1/1.2,
    ncol_legend=2,
    ylim=(1e-4, 1e5),
    comparison_limits=(0.8, 1.25)
)
plt.savefig("/home/steven/Desktop/transfer_models.pdf")
SOMean(200) {'overdensity': 200}
SOMean(200) {'overdensity': 200}
SOMean(200) {'overdensity': 200}
SOMean(200) {'overdensity': 200}
SOMean(200) {'overdensity': 200}
../_images/examples_component-showcase_19_1.png

First notice that the fiducial model is CAMB (this is only true if camb is installed, otherwise it is EH_BAO). Since CAMB has BAOs, all the models without BAOs show up in the ratio as having wiggles. Interestingly, CAMB has much higher power on small scales than the other models. CAMB is much slower to run than the other analytic models.

The normalization difference on large scales is due to the difference in the integral of the power spectrum, which is normalized to be the same value via \(\sigma_8\).

Mass Definitions

Here we plot the change in mass and concentration when moving from one mass definition to another.

[10]:
from hmf.halos.mass_definitions import SOMean, SOCritical, SOVirial, FOF
[98]:
single_column(height_ratio=1/1.5)


fig, ax = plt.subplots(
    2, 1, sharex=True,
    gridspec_kw={"hspace": 0, 'height_ratios': [3, 2]},
    subplot_kw={"xscale": 'log'}
)

for mdef in [SOMean(overdensity=300), SOCritical(overdensity=300), SOVirial(), FOF()]:
    m, r, c = base_model.mdef.change_definition(
        base_model.m,
        mdef=mdef,
        profile=base_model.halo_profile,
        cosmo=base_model.cosmo
    )

    ax[0].plot(base_model.m, m / base_model.m, label=mdef.colossus_name)
    ax[1].plot(base_model.m, c / base_model.cmz_relation)

ax[0].grid(True)
ax[1].grid(True)

ax[0].legend(ncol=2, frameon=True)

ax[0].set_ylabel(r"$m_{\rm new} / m_{\rm old}$")
ax[1].set_ylabel(r"$c_{\rm new} / c_{\rm old}$")
ax[1].set_xlabel("m, [$h^{-1}M_{\odot}$]")

plt.savefig("plots/mass_conversion.pdf")

../_images/examples_component-showcase_24_0.png

Notice that halos with a higher overdensity threshold move to lower masses and lower concentration.

Window Functions / Filters

The filter model, \(W(x)\), is convolved with the power spectrum to produce the mass variance (which in turn is used to define the halo mass function). Optimally, the shape of the filter model is matched to the shape of primordial patches that become halos. However, typically a simplified model such as a top-hat is used.

[165]:
model_comparison_plot(
    module="hmf.density_field.filters",
    component = 'Filter',
    attr_name = 'filter_model',
    x = 'm',
    y = 'sigma',
    ylab = r"$\sigma(m)$",
    yratio_lab = r"$\sigma$",
    height_ratio = 1/1.2,
    ncol_legend=1,
    ylim=(0, 10),
    ylog=False,
    xlim=(1e8, 1e16),
    comparison_limits = (0.7, 1.3)
)
(100000000.0, 1e+16)
../_images/examples_component-showcase_28_1.png

Note that while any of these can be used to generate \(\sigma(m)\), the normalisation of the power spectrum, \(\sigma(R=8)\), is always calculated using the TopHat.

Mass Function

There are many fitting functions for the HMF included in hmf. Some are fitted against FOF-haloes, while others are fitted to SO halos of various definitions. Here we’ll only plot a few, so that the plot is not too confusing.

[12]:
model_comparison_plot(
    module="hmf.mass_function.fitting_functions",
    component = 'FittingFunction',
    attr_name = 'hmf_model',
    x = 'nu',
    y = 'fsigma',
    ylab = r"$\nu f(\nu)$",
    height_ratio = 1/1.2,
    ncol_legend=2,
    ylim=(5e-8, 1),
    #ylog=False,
    xlim=(6e-2, 1e1),
    comparison_limits = (0.2, 2.1),
    must_include = ("PS", "SMT"),
    ignore=("ST", "Jenkins"),  # Jenkins gets in the way of the legend
    legend_size=7,
    max_models = 14,
    yratio_lab = "f"
)
plt.savefig("/home/steven/Desktop/hmf_models.pdf")
Randomly choosing 14 out of 19 models.
/home/steven/Documents/Projects/halos/HALOMOD/halomod/src/halomod/concentration.py:132: UserWarning: Requested mass definition 'FoF(l=0.2)' is not in native definitions for the 'Duffy08' CMRelation. No mass conversion will be performed, so results will be wrong. Using 'FoF(l=0.2)'.
  f"Requested mass definition '{mdef}' is not in native definitions for "
../_images/examples_component-showcase_32_2.png

Bias

The halo bias describes the clustering strength of halos of a given mass compared to the background matter. Many bias models are included in halomod, but even more can be accessed through the interface to colossus:

[9]:
comparat = make_colossus_bias("comparat17")
bhat11 = make_colossus_bias("bhattacharya11")
[25]:
model_comparison_plot(
    module="halomod.bias",
    component = 'Bias',
    attr_name = 'bias_model',
    x = 'nu',
    y = 'halo_bias',
    ylab = r"b($\nu$)",
    height_ratio = 1/1.2,
    ncol_legend=2,
    comparison_limits = (0.5, 1.6),
    must_include = ('Tinker05', 'Mandelbaum05', "ST99", "SMT01", 'Mo96', 'Jing98'),
    ignore=("UnityBias", "Seljak04Cosmo"),
    legend_size = 7,
    max_models=11,
    xlim=(6e-2, 1e1),
    ylim=(3e-1, 2e3),
    extra_models=[
        comparat,
        bhat11
    ]
)
Randomly choosing 11 out of 13 models.
WARNING: Astropy cosmology class contains massive neutrinos, which are not taken into account in Colossus.
WARNING: Astropy cosmology class contains massive neutrinos, which are not taken into account in Colossus.
../_images/examples_component-showcase_36_1.png

Concentration

The concentration-mass relation affects the shape of the halo profile at different masses. halomod includes physically-motivated forms (eg. Bullock and Ludlow) and power-law forms. Since the power-law forms are really only applicable to a single cosmology, we focus on the analytic forms in this plot:

[16]:
model_comparison_plot(
    module="halomod.concentration",
    component = 'CMRelation',
    attr_name = 'halo_concentration_model',
    x = 'm',
    y = 'cmz_relation',
    ylab = r"c(m)",
    yratio_lab = "c",
    height_ratio = 1/1.2,
    ncol_legend=2,
    comparison_limits = (0.3, 2.1),
    ignore=("Ludlow2016", "Ludlow2016Empirical", "Zehavi11", "Bullock01Power"),
    legend_size = 7,
    ylim=(2, 3e2),
    xlim=(7e7, 5e15),
    extra_models = [
        make_colossus_cm('prada12'),
        make_colossus_cm('diemer15'),
        make_colossus_cm('diemer19'),
#        make_colossus_cm('ishiyama20'),
    ]
)
/home/steven/Documents/Projects/halos/HALOMOD/halomod/src/halomod/concentration.py:130: UserWarning: Requested mass definition 'SOMean(200)' is not in native definitions for the 'Bullock01' CMRelation. No mass conversion will be performed, so results will be wrong. Using 'SOMean(200)'.
  f"Requested mass definition '{mdef}' is not in native definitions for "
/home/steven/Documents/Projects/halos/HALOMOD/halomod/src/halomod/concentration.py:130: UserWarning: Requested mass definition 'SOMean(200)' is not in native definitions for the 'Ludlow16' CMRelation. No mass conversion will be performed, so results will be wrong. Using 'SOMean(200)'.
  f"Requested mass definition '{mdef}' is not in native definitions for "
/home/steven/Documents/Projects/halos/HALOMOD/halomod/src/halomod/concentration.py:130: UserWarning: Requested mass definition 'SOMean(200)' is not in native definitions for the 'Ludlow16Empirical' CMRelation. No mass conversion will be performed, so results will be wrong. Using 'SOMean(200)'.
  f"Requested mass definition '{mdef}' is not in native definitions for "
/home/steven/Documents/Projects/halos/HALOMOD/halomod/src/halomod/concentration.py:538: UserWarning: Only use Ludlow16Empirical c(m,z) relation when using Planck-like cosmology
  "Only use Ludlow16Empirical c(m,z) relation when using Planck-like cosmology"
/home/steven/Documents/Projects/halos/HALOMOD/halomod/src/halomod/concentration.py:130: UserWarning: Requested mass definition 'SOMean(200)' is not in native definitions for the 'Prada12' CMRelation. No mass conversion will be performed, so results will be wrong. Using 'SOMean(200)'.
  f"Requested mass definition '{mdef}' is not in native definitions for "
WARNING: Astropy cosmology class contains massive neutrinos, which are not taken into account in Colossus.
/home/steven/miniconda3/envs/halomod/lib/python3.7/site-packages/colossus/halo/concentration.py:421: UserWarning: Could not find concentration for model prada12, mass 1.12e+17, mdef 200m.
  warnings.warn(msg)
/home/steven/miniconda3/envs/halomod/lib/python3.7/site-packages/colossus/halo/concentration.py:421: UserWarning: Could not find concentration for model prada12, mass 1.26e+17, mdef 200m.
  warnings.warn(msg)
/home/steven/miniconda3/envs/halomod/lib/python3.7/site-packages/colossus/halo/concentration.py:421: UserWarning: Could not find concentration for model prada12, mass 1.41e+17, mdef 200m.
  warnings.warn(msg)
/home/steven/miniconda3/envs/halomod/lib/python3.7/site-packages/colossus/halo/concentration.py:421: UserWarning: Could not find concentration for model prada12, mass 1.58e+17, mdef 200m.
  warnings.warn(msg)
/home/steven/miniconda3/envs/halomod/lib/python3.7/site-packages/colossus/halo/concentration.py:421: UserWarning: Could not find concentration for model prada12, mass 1.78e+17, mdef 200m.
  warnings.warn(msg)
/home/steven/miniconda3/envs/halomod/lib/python3.7/site-packages/colossus/halo/concentration.py:421: UserWarning: Could not find concentration for model prada12, mass 2.00e+17, mdef 200m.
  warnings.warn(msg)
/home/steven/miniconda3/envs/halomod/lib/python3.7/site-packages/colossus/halo/concentration.py:421: UserWarning: Could not find concentration for model prada12, mass 2.24e+17, mdef 200m.
  warnings.warn(msg)
/home/steven/miniconda3/envs/halomod/lib/python3.7/site-packages/colossus/halo/concentration.py:421: UserWarning: Could not find concentration for model prada12, mass 2.51e+17, mdef 200m.
  warnings.warn(msg)
/home/steven/miniconda3/envs/halomod/lib/python3.7/site-packages/colossus/halo/concentration.py:421: UserWarning: Could not find concentration for model prada12, mass 2.82e+17, mdef 200m.
  warnings.warn(msg)
/home/steven/miniconda3/envs/halomod/lib/python3.7/site-packages/colossus/halo/concentration.py:421: UserWarning: Could not find concentration for model prada12, mass 3.16e+17, mdef 200m.
  warnings.warn(msg)
/home/steven/miniconda3/envs/halomod/lib/python3.7/site-packages/colossus/halo/concentration.py:421: UserWarning: Could not find concentration for model prada12, mass 3.55e+17, mdef 200m.
  warnings.warn(msg)
/home/steven/miniconda3/envs/halomod/lib/python3.7/site-packages/colossus/halo/concentration.py:421: UserWarning: Could not find concentration for model prada12, mass 3.98e+17, mdef 200m.
  warnings.warn(msg)
/home/steven/miniconda3/envs/halomod/lib/python3.7/site-packages/colossus/halo/concentration.py:421: UserWarning: Could not find concentration for model prada12, mass 4.47e+17, mdef 200m.
  warnings.warn(msg)
/home/steven/miniconda3/envs/halomod/lib/python3.7/site-packages/colossus/halo/concentration.py:421: UserWarning: Could not find concentration for model prada12, mass 5.01e+17, mdef 200m.
  warnings.warn(msg)
/home/steven/miniconda3/envs/halomod/lib/python3.7/site-packages/colossus/halo/concentration.py:421: UserWarning: Could not find concentration for model prada12, mass 5.62e+17, mdef 200m.
  warnings.warn(msg)
/home/steven/miniconda3/envs/halomod/lib/python3.7/site-packages/colossus/halo/concentration.py:421: UserWarning: Could not find concentration for model prada12, mass 6.31e+17, mdef 200m.
  warnings.warn(msg)
/home/steven/miniconda3/envs/halomod/lib/python3.7/site-packages/colossus/halo/concentration.py:421: UserWarning: Could not find concentration for model prada12, mass 7.08e+17, mdef 200m.
  warnings.warn(msg)
/home/steven/miniconda3/envs/halomod/lib/python3.7/site-packages/colossus/halo/concentration.py:421: UserWarning: Could not find concentration for model prada12, mass 7.94e+17, mdef 200m.
  warnings.warn(msg)
/home/steven/miniconda3/envs/halomod/lib/python3.7/site-packages/colossus/halo/concentration.py:421: UserWarning: Could not find concentration for model prada12, mass 8.91e+17, mdef 200m.
  warnings.warn(msg)
/home/steven/Documents/Projects/halos/HALOMOD/halomod/src/halomod/concentration.py:130: UserWarning: Requested mass definition 'SOMean(200)' is not in native definitions for the 'Diemer15' CMRelation. No mass conversion will be performed, so results will be wrong. Using 'SOMean(200)'.
  f"Requested mass definition '{mdef}' is not in native definitions for "
WARNING: Astropy cosmology class contains massive neutrinos, which are not taken into account in Colossus.
/home/steven/Documents/Projects/halos/HALOMOD/halomod/src/halomod/concentration.py:130: UserWarning: Requested mass definition 'SOMean(200)' is not in native definitions for the 'Diemer19' CMRelation. No mass conversion will be performed, so results will be wrong. Using 'SOMean(200)'.
  f"Requested mass definition '{mdef}' is not in native definitions for "
WARNING: Astropy cosmology class contains massive neutrinos, which are not taken into account in Colossus.
../_images/examples_component-showcase_39_6.png

Notice that both of the physical forms have discontinuities, which arise when the predicted redshift of formation for a given halo mass is less than zero. This typically does not present a problem for the halo model, for which intermediate masses are the most important.

Halo Exclusion

[89]:
model = base_model.clone()

single_column(height_ratio=1/1.5)

fig, ax = plt.subplots(
    2, 1, sharex=True,
    gridspec_kw={"hspace": 0, 'height_ratios': [3, 2]},
    subplot_kw={"xscale": 'log'}
)

for i, excl in enumerate(['NoExclusion', 'Sphere', 'DblSphere_', 'DblEllipsoid_', 'NgMatched_']):
    model.exclusion_model = excl

    ax[0].plot(model.r, model.corr_auto_tracer, label=excl.replace("_", ""), color=f'C{i}')
    ax[0].plot(model.r, model.corr_2h_auto_tracer, ls='--', color=f'C{i}', lw=1)
    ax[1].plot(model.r, model.corr_auto_tracer / base_model.corr_auto_tracer)

model.exclusion_model = 'NoExclusion'

model.hc_spectrum = 'filtered-lin'
ax[0].plot(model.r, model.corr_auto_tracer, label=r"Filt. $P_{\rm lin}(k)$", color=f'C{i+1}')
ax[0].plot(model.r, model.corr_2h_auto_tracer, ls='--', color=f'C{i+1}', lw=1)
ax[1].plot(model.r, model.corr_auto_tracer / base_model.corr_auto_tracer, )

model.hc_spectrum = 'filtered-nl'
ax[0].plot(model.r, model.corr_auto_tracer, label=r"Filt. $P_{\rm nl}(k)$", color=f'C{i+2}')
ax[0].plot(model.r, model.corr_2h_auto_tracer, ls='--', color=f'C{i+2}', lw=1)
ax[1].plot(model.r, model.corr_auto_tracer / base_model.corr_auto_tracer, )

ax[0].legend(ncol=3, frameon=False, fontsize=7, bbox_to_anchor=(0., 1.02, 1., .102))
ax[0].set_yscale('log')

ax[0].set_xlim(1e-1, 1e1)
ax[0].set_ylim(1e-1, 1e4)
ax[1].set_ylabel(r"$\xi / \xi_{\rm No Excl}$")
ax[0].set_ylabel(r"$\xi_{gg}(r)$")
ax[1].set_xlabel("r, [$h^{-1}$Mpc]")

plt.savefig("plots/halo_exclusion.pdf")
../_images/examples_component-showcase_42_0.png

HOD

For the HOD, we’ll only be showing models of point-source-like tracers (i.e. galaxies). A whole set of HOD models for continuous tracers (eg. HI gas) are also available. Also note that these models look very similar to each other. This is by design. Most of the models are essentially nested (i.e. you can get back Zehavi05 from setting some of the Contreras13 parameters to zero or one). By default, halomod sets the parameters so that the model returns the same or a similar occupation function. However, the HOD is not fundamental in nature – it depends on the actual galaxy sample being observed (and its depth/wavelength etc), so these models can vary widely for different parameters.

[139]:
single_column(height_ratio=1/1.5)

model = base_model.clone()
for hod in ['Zehavi05', 'Zheng05', 'Tinker05',  'Geach12', 'Contreras13']:
    model.hod_model = hod
    plt.plot(model.m, model.total_occupation, label=hod)

plt.xscale('log')
plt.yscale('log')
plt.ylim(1e-4, 1e4)
plt.xlim(1e9, 1e16)
plt.legend(fontsize=8)

plt.xlabel("m, [$h^{-1}M_\odot$]")
plt.ylabel("N(m)")
plt.savefig("plots/hod_models.pdf")
../_images/examples_component-showcase_45_0.png

The key things to recognize are a low-mass cutoff, essentially corresponding to the depth of the survey, and a high-mass powerlaw with slope close to one (i.e. doubling halo mass doubles the occupancy). The differentiation between central and satellite halos causes the bump seen above at \(m\sim10^{12}\).

Profiles

[43]:
two_column(height_ratio=1/2.3)

fig, ax = plt.subplots(
    2, 2, sharex='col',
    gridspec_kw={"hspace": 0, 'height_ratios': [3, 2]},
    subplot_kw={"xscale": 'log'}
)

profiles = get_models("halomod.profiles", 'Profile', ignore=("ProfileInf", "Constant", "NFWInf", "HernquistInf", "MooreInf", "GeneralizedNFWInf"))

model = base_model.clone()
for profile in profiles:
    model.halo_profile_model = profile
    model.halo_profile_params = {'alpha': 1.5} if profile.__name__ == "GeneralizedNFW" else {}
    ax[0, 0].plot(model.r, model.halo_profile.rho(model.r, np.array([1e12])), label=profile.__name__)
    ax[1, 0].plot(model.r, model.halo_profile.rho(model.r, np.array([1e12])) /base_model.halo_profile.rho(model.r, np.array([1e12])))

    ax[0, 1].plot(model.m, model.halo_profile.rho(0.03, model.m), label=profile.__name__)
    ax[1, 1].plot(model.m, model.halo_profile.rho(0.03, model.m) / base_model.halo_profile.rho(0.03, model.m))

ax[0, 0].set_yscale('log')
ax[0, 1].set_yscale('log')

ax[0, 0].set_ylim(1e9, 1e17)
ax[0, 0].set_xlim(1e-2, 0.3)
ax[0, 0].legend(ncol=2, fontsize=8)
ax[1, 0].set_ylim(0.1, 2)

ax[0, 1].set_yscale('log')
#ax[0].set_ylim(1e9, 1e17)
ax[0, 1].set_xlim(1e9, 1e17)

ax[1, 0].set_xlabel(r"r, [$h^{-1}{\rm Mpc}$]")
ax[0, 0].set_ylabel(r"$\rho(r|m)$");

ax[0,0].set_title("m = $10^{12} h^{-1}M_\odot$")
ax[0,1].set_title("r = $0.03 h^{-1}$Mpc")

ax[1, 1].set_xlabel(r"m, [$h^{-1}M_\odot$]")
ax[1, 0].set_ylabel(r"$\rho/\rho_{\rm NFW}$")

plt.savefig("plots/profile_models.pdf")
/home/steven/miniconda3/envs/halomod/lib/python3.7/site-packages/ipykernel_launcher.py:16: RuntimeWarning: invalid value encountered in true_divide
  app.launch_new_instance()
/home/steven/miniconda3/envs/halomod/lib/python3.7/site-packages/ipykernel_launcher.py:19: RuntimeWarning: invalid value encountered in true_divide
/home/steven/miniconda3/envs/halomod/lib/python3.7/site-packages/ipykernel_launcher.py:16: RuntimeWarning: divide by zero encountered in true_divide
  app.launch_new_instance()
/home/steven/miniconda3/envs/halomod/lib/python3.7/site-packages/ipykernel_launcher.py:19: RuntimeWarning: divide by zero encountered in true_divide
../_images/examples_component-showcase_48_1.png

We show here the profile for six models, plotted against mass and radius. We omit the “Inf” versions of each profile, since they are the same but extend to infinity (and are less useful for the halo model itself since some of them contain infinite mass).