Colossus tutorial: halo concentration

Welcome to the Colossus concentration tutorial. Concentration is defined as the ratio of the outer radius of a halo to the scale radius, a concept that goes back to the Navarro, Frenk & White papers that proposed the NFW density profile. The Colossus concentration module implements a number of models for the mean or median concentration of halos.

In [1]:
from __future__ import print_function 
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

As always with Colossus, we need to set a cosmology.

In [2]:
from colossus.cosmology import cosmology
cosmology.setCosmology('planck18');

Let's import the concentration module:

In [3]:
from colossus.halo import concentration

Now we can evaluate concentrations for a range of models of the c-M relation. First, let's list the models Colossus implements:

In [4]:
for model_name in concentration.models:
    print(model_name)
bullock01
duffy08
klypin11
prada12
bhattacharya13
dutton14
diemer15_orig
diemer15
klypin16_m
klypin16_nu
ludlow16
child18
diemer19
ishiyama21

While there are functions for each of these models, the easier way to use the concentration module is through the unified concentration() interface. This function does a number of things: it converts between mass definitions, checks the validity of models and so on. Let's say we want to use the Bullock et al. 2001 model to get the concentration of a halo with virial mass $10^{12} M_{\odot}/h$ at $z = 0.5$:

In [5]:
concentration.concentration(1E12, 'vir', 0.5, model = 'bullock01')
Out[5]:
7.331045667087758

Of course, the function also accepts an array of masses, and returns an array of concentrations:

In [6]:
M = 10**np.arange(10.0, 15.0, 1.0)
concentration.concentration(M, 'vir', 0.5, model = 'bullock01')
Out[6]:
array([11.01847606,  9.09584212,  7.33104567,  5.7644042 ,  4.46141506])

However, not all models were constrained at all masses and redshifts, and Colossus can warn us in such cases:

In [7]:
concentration.concentration(M, 'vir', 0.5, model = 'dutton14')
/Users/benedito/University/code/colossus_dev/colossus/halo/concentration.py:441: UserWarning: Some masses or redshifts are outside the validity of the concentration model.
  warnings.warn('Some masses or redshifts are outside the validity of the concentration model.')
Out[7]:
array([11.33628686,  9.32117855,  7.66427055,  6.30189013,  5.18168284])

The power-law model of Dutton & Maccio 2014 should probably not be used outside the range of masses where it was constrained. But which masses are valid and which aren't? Using the range_return parameter, we can get the function to return a mask that indicates the validity:

In [8]:
c, mask = concentration.concentration(M, 'vir', 0.5, model = 'dutton14', range_return = True)
print(mask)
print(c[mask])
[False  True  True  True  True]
[9.32117855 7.66427055 6.30189013 5.18168284]

Only the lowest mass bin is outside the range, so we won't use that. One thing the concentration module does not check is the cosmology: if a model was calibrated only for a particular cosmology, it can still be evaluated even if a different cosmology is set. For example:

In [9]:
concentration.concentration(1E12, 'vir', 0.5, model = 'duffy08')
Out[9]:
6.226274912879475

The Duffy et al. 2008 model was calibrated for a WMAP5 cosmology, so care needs to be taken if we're working in a Planck 2015 cosmology (as set above). Let's put it all together and compare the models implemented in Colossus:

In [10]:
cosmology.setCosmology('bolshoi')
M = 10**np.arange(8.0, 15.4, 0.1)

plt.figure()
plt.xscale('log')
plt.xlabel('M200c(Msun/h)')
plt.ylabel('Concentration')
for model_name in concentration.models:
    c, mask = concentration.concentration(M, '200c', 0.0, model = model_name, range_return = True)
    plt.plot(M[mask], c[mask], label = model_name.replace('_', '\_'))
plt.xlim(1E3, 4E15)
plt.ylim(2.0, 18.0)
plt.legend();