class utility
The CONCEPT ‘class’ utility enables easy access to linear perturbations (and background quantities) outside of CONCEPT, e.g. for use with other simulation codes. In a nutshell, a cosmology is specified to CONCEPT using the standard parameter specification, with which CONCEPT calls CLASS in order to obtain the required perturbation data. All perturbations are then processed; interpolating them onto a common \((a, k)\) grid, and typically also transforming them to N-body gauge. The resulting data is saved to an HDF5 file, ready to be used for e.g. initial condition generation or gravitational corrections on matter particles from linear species such as neutrinos. The pkdgrav3 code is able to fully utilise such HDF5 files generated by the CONCEPT class utility, enabling simulations fully consistent with general relativistic perturbation theory.
Tip
If you are unfamiliar with the basic framework of the N-body gauge for cosmological simulations, you might want to check out the paper on ‘Fully relativistic treatment of light neutrinos in 𝘕-body simulations’. It is also advisable to have gone through the CONCEPT tutorial at least up to (and including) the first subsection of beyond matter-only simulations.
Entries on this page:
Basic usage
A basic invocation of the CONCEPT class utility looks like
./concept \
-u class \
--kmin <kmin> --kmax <kmax> \
<perturbations>
where <kmin>
and <kmax>
specify the \(k\) range while
<perturbations>
is a string of comma-separated perturbation
specifications. As an example, the below processes \(\delta\) and
\(\theta\) perturbations for ‘total matter’ (combined baryons and cold
dark matter), as well as \(\delta\) perturbations for photons and massless
neutrinos, in the interval
\(10^{-3}\,\text{Mpc}^{-1} \leq k \leq 1 \text{Mpc}^{-1}\):
./concept \
-u class \
--kmin 1e-3/Mpc --kmax 1/Mpc \
"b+cdm:1, g:0, ur:0"
Each specification within <perturbations>
consists of a CLASS species and
a “Boltzmann order” separated by a colon. Commonly used CLASS species include
b
: Baryons.cdm
: Cold dark matter.g
: Photons.ur
: Massless neutrinos.ncdm[0]
,ncdm[1]
,ncdm[2]
, … : Massive neutrinos.metric
: Fictitious species providing relativistic corrections (not a standard CLASS species, provided by CONCEPT).
As in the above example, two (or more) species may be joined using +
,
leading to combined, weighted perturbations.
The available Boltzmann orders are
0
: Process \(\delta\) (energy density contrast) perturbations.1
: Process \(\delta\) and \(\theta\) (velocity divergence) perturbations.2
: Process \(\delta\), \(\theta\), \(\delta P\) (pressure) and \(\sigma\) (shear stress) perturbations.
The Boltzmann order defaults to 0
if left out.
Running the CONCEPT class utility as above will produce a file named
class_processed.hdf5
within the output
directory, containing the
specified perturbations as well as various background quantities. The contents
of these HDF5 files can be explored using tools such as
ViTables, but is also described
below.
For selection of the times (scale factor \(a\) values), see the
--times
command-line option.
For selection of the \(k\) modes, see the
--modes
command-line option.
Command-line options
Below the possible command-line options to the CONCEPT class utility are
described, i.e. additional options to the concept
script allowed once
-u class
is supplied. For the <perturbations>
option, see
basic usage above.
See this page for the
command-line options to the concept
script in general, and specifically
this section for how standard command-line options are used
together with utility specific ones.
Help: -h
, --help
Displays a short description of each command-line option to the class utility and exits:
./concept -u class -h
Minimum Fourier mode: --kmin
Sets the minimum needed Fourier \(k\) mode for the perturbations. For e.g. \(k \geq 5\times 10^{-4}\, \text{Mpc}^{-1}\):
./concept -u class --kmin 5e-4/Mpc
Note
A small tolerance is automatically applied so that the actual lowest \(k\) mode will be slightly below what is specified.
Maximum Fourier mode: --kmax
Sets the maximum needed Fourier \(k\) mode for the perturbations. For e.g. \(k \leq 2\, \text{Mpc}^{-1}\):
./concept -u class --kmax 2/Mpc
Note
A small tolerance is automatically applied so that the actual largest \(k\) mode will be slightly above what is specified.
Tip
Try not to specify a maximum \(k\) much larger than what you need, as the CLASS computation time for each mode grows rapidly with \(k\).
Fourier modes: --modes
When specified as an integer, this sets the total number of Fourier \(k\) modes for the perturbations. E.g.
./concept -u class --modes 128
The placement of the \(k\) modes at which to tabulate the perturbations
are chosen based on the minimum and
maximum mode together with the
class_modes_per_decade
parameter. When the
--modes
option is not specified, class_modes_per_decade
is used
as is, leading to some number of total modes. When the --modes
option is
specified, the numbers of modes per decade within class_modes_per_decade
are all uniformly scaled in order to yield the requested number of modes.
Tip
If you simply want some definite number (say \(128\)) of logarithmically equidistant modes, you can do e.g.
./concept -u class --modes 128 -c "class_modes_per_decade = 1"
Tip
If the processed perturbations are intended for use with pkdgrav3, note that a maximum number of \(256\) modes is allowed.
Other allowed specifications for --modes
are:
Explicit \(k\) values at which to perform the tabulation, specified as any valid Python expression, e.g.
./concept -u class --modes "array([1e-2, 1e-1, 1])/Mpc"
Path to text file containing values of \(k\). It is assumed that the data within this file is expressed in the same units as used by the current CONCEPT run.
Path to HDF5 file produced using the CONCEPT class utility. The \(k\) values to use will be taken from the tabulated perturbations within this file.
In all cases, the minimum and maximum modes are respected, with \(k\) values outside this range being dropped.
Times: --times
When specified as an integer, this sets the total number of times (scale factor \(a\) values) at which to tabulate the perturbations. E.g.
./concept -u class --times 512
When not specified, this defaults to 1024
times. The placement of the
tabulation times follows that which is used by CLASS, providing denser
sampling around epochs of greater change.
Note
If the raw perturbations from the CLASS computation are tabulated at fewer
points in time than requested, no additional times will be added. It is
thus possible that the processed perturbations are tabulated at fewer times
than requested through --times
(though this should not happen for
reasonable values).
The \(a\) values will be within the interval
\(a_{\text{begin}} \leq a \leq 1\), with the a_begin
parameter specifying the lower boundary.
Note
A small tolerance is automatically applied so that the actual smallest
\(a\) value will be slightly below what is specified
through a_begin
.
Tip
If the processed perturbations are intended for use with pkdgrav3, note that a maximum number of \(1024\) times is allowed.
Other allowed specifications for --times
are:
Explicit \(a\) values at which to perform the tabulation, specified as any valid Python expression, e.g.
./concept -u class --times "[1/(1 + z) for z in linspace(0, 99, 512)]"
Path to text file containing values of \(a\).
Path to HDF5 file produced using the CONCEPT class utility. The \(a\) values to use will be taken from the tabulated perturbations within this file.
Gauge: --gauge
Sets the gauge of the processed perturbations. E.g.
./concept -u class --gauge N-body
The available gauges are:
N-body
: The N-body gauge (default).synchronous
: The synchronous gauge.Newtonian
: The conformal Newtonian (also know as the longitudinal) gauge.
When the N-body gauge is selected, CLASS is really run in synchronous gauge, with the perturbations transformed to N-body gauge by CONCEPT.
File contents
The result of a CONCEPT class utility computation is a file called
class_processed.hdf5
, containing the requested perturbations as well as
background quantities. As mentioned earlier, the contents of HDF5 files are
conveniently explored using a graphical tool like
ViTables. Details of the contents of
class_processed.hdf5
are described below.
Data layout
The data layout within class_processed.hdf5
is as follows:
background
: Group containing data sets for various background quantities, tabulated at a common 1D time grid:a
: Scale factor \(a\) values at which all background quantities are tabulated.z
: Redshift \(z\) values at which all background quantities are tabulated.t
: Cosmic time \(t\) values at which all background quantities are tabulated.tau
: Conformal time \(\tau\). values at which all background quantities are tabulated.H
: The Hubble parameter \(H\).rho_<species>
with<species>
some CLASS species: The background energy density \(\bar{\rho}\) of the given species. The critical ‘crit
’ and total ‘tot
’ energy densities are present as well.p_<species>
with<species>
some CLASS species: The background pressure \(\bar{P}\) of the given species.D
: First-order (linear) growth factor \(D = D^{(1)}\), with the convention \(D^{(1)}(a=1) = 1\).f
: First-order (linear) growth rate \(f = f^{(1)} \equiv \mathrm{d}\ln D^{(1)} / \mathrm{d}\ln a\).D2
: Second-order growth factor \(D^{(2)}\), with the convention \(D^{(2)} > 0\).f2
: Second-order growth rate \(f^{(2)} \equiv \mathrm{d}\ln D^{(2)} / \mathrm{d}\ln a\).D3a
: Third-order growth factor \(D^{(3\text{a})}\), with the convention \(D^{(3\text{a})} > 0\).f3a
: Third-order growth rate \(f^{(3\text{a})} \equiv \mathrm{d}\ln D^{(3\text{a})} / \mathrm{d}\ln a\).D3b
: Third-order growth factor \(D^{(3\text{b})}\), with the convention \(D^{(3\text{b})} > 0\).f3a
: Third-order growth rate \(f^{(3\text{b})} \equiv \mathrm{d}\ln D^{(3\text{b})} / \mathrm{d}\ln a\).D3c
: Third-order growth factor \(D^{(3\text{c})}\), with the convention \(D^{(3\text{c})} > 0\).f3c
: Third-order growth rate \(f^{(3\text{c})} \equiv \mathrm{d}\ln D^{(3\text{c})} / \mathrm{d}\ln a\).
In addition to the above datasets, this group also stores some attributes, namely the reduced Hubble constant
h
(given by \(h \equiv H_0/(100\, \text{km}\, \text{s}^{-1}\, \text{Mpc}^{-1})\) as well as density parametersOmega_<species>
for the various species.perturbations
: Group containing the specified perturbations, tabulated at a common 2D \((a, k)\) grid:a
: Data set of scale factor \(a\) values at which all perturbations are tabulated.k
: Data set of Fourier modes \(k\) at which all perturbations are tabulated.delta_<species>
: The \(\delta\) perturbations of the given species.theta_<species>
: The \(\theta\) perturbations of the given species.deltaP_<species>
: The \(\delta P\) perturbations of the given species.sigma_<species>
: The \(\sigma\) perturbations of the given species.
In addition to the above datasets, this group also stores a
gauge
attribute, specifying the gauge of the perturbations.class_params
: Group containing no data sets, but with all CLASS parameters used for the CLASS computation stored as attributes. That is, the attributes within this group contain all information needed to do a CLASS run identical to the one carried out by the CONCEPT class utility.Note
One of these CLASS parameters is
gauge
. When running the CONCEPT class utility in N-body gauge (the default), CLASS is really run in synchronous gauge (with the results transformed to N-body gauge by CONCEPT), and so thegauge
attribute inside theclass_params
group will be set to'synchronous'
. For the actual gauge in which the perturbations are expressed, see thegauge
attribute on theperturbations
group.units
: Group containing no data sets, but with attributes storing the units used for the data throughout the file:unit length
: The length unit used. By default this isMpc
.unit time
: The time unit used. By default this isGyr
.unit mass
: The time unit used. By default this is10**10*m_sun
(\(10^{10}\, m_{\odot}\)).
Extra output
The above lists of background and perturbation quantities
are what end up in the processed HDF5 file by default, though the raw CLASS
computation contains other quantities as well. You may request these other
quantities by listing them in the class_extra_background
parameter and the
class_extra_perturbations
parameter.
As an example, the below requests the comoving distance as an extra background quantity, as well as the conformal Newtonian metric potentials \(\phi\) and \(\psi\) as extra perturbations:
./concept \
-u class \
--kmin <kmin> --kmax <kmax> \
<perturbations> \ -c "class_extra_background = 'comov. dist.'" \ -c "class_extra_perturbations = {'ϕ', 'ψ'}"
Note
While the various perturbations in general depend on the
chosen gauge, this is not so for the gauge specific
metric perturbations ϕ
, ψ
, hʹ
and H_Tʹ
, which are
always given in their definite gauges. Also, hʹ
is not available when
running in conformal Newtonian gauge.
Caution
The units of the various quantities within class_processed.hdf5
are
described below. If adding an extra CLASS quantity via
class_extra_background
or class_extra_perturbations
that is unknown
to CONCEPT, unit convertion will not be carried out, and the quantity
will be provided exactly as CONCEPT got it from CLASS. If this
happens, a warning will be emitted.
Units
As written above, the units
group contains the base
units used for all data within the file, with the default base units being
\(\text{Mpc}\), \(\text{Gpc}\) and \(10^{10}\, m_{\odot}\). Given
these default base units, the table below lists the full units in which the
various data sets are expressed:
Quantity |
Unit (default) |
---|---|
Scale factor |
\([1]\) |
Cosmic time |
\([\text{Gyr}]\) |
Fourier mode |
\([\text{Mpc}^{-1}]\) |
Hubble parameter |
\([\text{Gyr}^{-1}]\) |
Growth factors |
\([1]\) |
Background energy density |
\([10^{10}\, m_{\odot}\, \text{Mpc}^{-3}]\) |
Energy density contrast |
\([1]\) |
Velocity divergence |
\([\text{Gyr}^{-1}]\) |
Pressure background |
\([10^{10}\, m_{\odot}\, \text{Mpc}^{-1}\,\text{Gyr}^{-2}]\) |
Shear stress |
\([\text{Mpc}^2\,\text{Gyr}^{-2}]\) |
Metric perturbations |
\([\text{Mpc}^2\,\text{Gyr}^{-2}]\) |
Time derivatives of metric perturbations |
\([\text{Gyr}^{-1}]\) |
Tip
If you need the Hubble parameter H
in its canonial units of
\(\text{km}\, \text{s}^{-1}\, \text{Mpc}^{-1}\), you can convert it by
multiplying the values as follows:
Tip
The background energy densities rho
are really expressed in units of
mass densities. If you need these in energy density units, multiply by
the speed of light squared:
Note
The base unit system in which to express the data within
class_processed.hdf5
may be changed through the unit_length
,
unit_time
and unit_mass
parameters.
Complete example (massive neutrinos)
Here follows a complete code example for a CONCEPT class utility computation of a cosmology involving massive neutrinos.
The cosmology for which we want to compute the linear perturbations is specified by the following table:
Parameter |
Value |
---|---|
\(H_0\) |
\(67\, \text{km}\, \text{s}^{-1}\, \text{Mpc}^{-1}\) |
\(\Omega_{\text{b}}\) |
\(0.049\) |
\(\Omega_{\text{cdm}} + \Omega_{\nu}\) |
\(0.27\) |
\(T_{\gamma}\) |
\(2.7255\, \text{K}\) |
\(N_{\text{eff}}\) |
\(3.046\) |
\(m_{\nu_{1}}\) |
\(0\, \text{eV}\) |
\(m_{\nu_{2}}\) |
\(8.7\times 10^{-3}\, \text{eV}\) |
\(m_{\nu_{3}}\) |
\(5.0\times 10^{-2}\, \text{eV}\) |
The total neutrino density parameter \(\Omega_{\nu} = \Omega_{\nu_1} + \Omega_{\nu_2} + \Omega_{\nu_3}\) is implicitly set through the effective number of neutrino species \(N_{\text{eff}}\) together with the neutrino masses \(m_1\), \(m_2\), \(m_3\). The neutrino temperature \(T_{\nu}\) (equal for all three species) is related to the photon temperature \(T_{\gamma}\) by
Note
We do not need to specify any parameters having to do with the primordial spectrum (e.g. \(A_{\text{s}}\) and \(n_{\text{s}}\)) as these do not enter the linear CLASS computation.
The below parameter file implements the above neutrino cosmology, though written in a way that allows one to easily change the number of neutrino species:
# Input/output
output_dirs = param.dir
# Cosmology
H0 = 67*km/(s*Mpc)
Ωb = 0.049
Ωcdm = 0.27 - Ων
a_begin = 1/(1 + 99)
_mν = [0, 8.7e-3, 5.0e-2] # neutrino masses in eV
_N_eff = 3.046
class_params = {
# Photon temperature
'T_cmb': 2.7255,
# Neutrino hierarchy
'N_ur' : 0,
'N_ncdm' : len(set(_mν)),
'deg_ncdm': [_mν.count(mν) for mν in sorted(set(_mν))],
'm_ncdm' : [mν if mν > 0 else 1e-100 for mν in sorted(set(_mν))],
'T_ncdm' : [(4/11)**(1/3)*(_N_eff/len(_mν))**(1/4)]*len(set(_mν)),
# Photon precision parameters
'l_max_g' : 1000,
'l_max_pol_g' : 1000,
'radiation_streaming_approximation': 3,
# Massive neutrino precision parameters
'l_max_ncdm' : 200,
'Number of momentum bins' : [50]*len(set(_mν)),
'Quadrature strategy' : [2]*len(set(_mν)),
'ncdm_fluid_approximation': 3,
# General precision parameters
'evolver' : 0,
'recfast_Nz0' : 1e+5,
'tol_thermo_integration' : 1e-6,
'perturb_integration_stepsize': 0.25,
'perturb_sampling_stepsize' : 0.01,
}
The key points of this parameter file are:
Setting
output_dirs
toparam.dir
ensures that the resulting HDF5 file with the perturbations will be placed in the same directory as the parameter file.The amount of cold dark matter \(\Omega_{\text{cdm}}\) is set through
Ωcdm = 0.27 - Ων
, thoughΩν
(\(\Omega_{\nu}\)) is not explicitly set. As stated previously, \(\Omega_{\nu}\) is implicitly defined through the other neutrino parameters, from which CONCEPT automatically setsΩν
.By specifying
a_begin = 1/(1 + 99)
we declare that we are not interested in perturbations prior to \(z = 99\).The neutrino masses
_mν
and effective number of neutrino species_N_eff
are both stored in variables starting with an underscore ‘_
’. This is the canonical naming convention within CONCEPT parameter files for helper variables that are not supposed to be CONCEPT parameters.The
class_params
parameter holds parameters fed to CLASS.Note that
'H0'
,'Omega_b'
and'Omega_cdm'
is automatically added fromH0
,Ωb
andΩcdm
.The parameters are set up to take advantage of the case where
_mν
holds several identical neutrino masses (as in e.g._mν = [0, 3e-2, 3e-2]
). In this case, only neutrinos with unique masses (set(_mν)
) will be computed (saving computation time), with their degeneracy recorded in the'deg_ncdm'
CLASS parameter.We use the
ncdm
species for all neutrinos, including the massless one. We need to explicitly set the number of massless neutrinos,N_ur
, to zero, as this is non-zero by default. To avoid possible issues within the CLASS computation from having a mass identically equal to zero usingncdm
, we replace massless entries in'm_ncdm'
with \(10^{-100}\).In standard CLASS, parameters with multiple values (e.g.
'm_ncdm'
) needs to be specified as a comma-separated string. In CONCEPT parameter files, using lists ‘[...]
’ is possible as well.The many precision parameters improve the correctness of various perturbation results significantly over the default, but also makes the CLASS computation much more expensive.
Tip
If you would like to better understand a given CLASS parameter, you can look for it in the explanatory.ini example CLASS parameter file, which documents many of the possible CLASS parameters.
With the above parameter file saved to a file called e.g.
class-param
, we can run the CONCEPT class utility on it using
something like
./concept \
-u class \
--kmin "1e-3*0.67/Mpc" --kmax "1*0.67/Mpc" --modes 128 \
--times 512 \
"b+cdm:1, g, ncdm[0], ncdm[1], ncdm[2]:2, metric" \
-p /path/to/class-param \
-n 4
Tip
If working on a cluster, you can automatically submit the computation as a job, just as when running full simulations.
The above command requests \(128\) modes between \(k = 10^{-3}\, h\, \text{Mpc}^{-1}\) and \(k = 1\, h\, \text{Mpc}^{-1}\), with \(h = H_0/(100\, \text{km}\, \text{s}^{-1}\, \text{Mpc}^{-1}) = 0.67\), all tabulated at the same \(512\) times. Both \(\delta\) and \(\theta\) perturbations of total matter are requested, allowing for generation of N-body initial conditions. Furthermore, \(\delta\) perturbations in all linear species — photons, the three neutrino species and the metric correction species — are requested, which might be used to supply linear gravitational kicks to matter particles within an N-body simulation. Lastly, \(\theta\), \(\delta P\) and \(\sigma\) perturbations for the heaviest neutrino species are also requested. The perturbations will all be in N-body gauge. Using 4 processes as in the above example command, the entire computation will take around 6 minutes on modern hardware.
With the class_processed.hdf5
file generated from the above command and
parameter file, the below Python script demonstrates how
one can extract and use (some of) the data within this file:
import re
import numpy as np
import matplotlib; matplotlib.use('agg')
import matplotlib.pyplot as plt
import scipy.interpolate
import h5py
# Read in data from the HDF5 file
with h5py.File('class_processed.hdf5', mode='r') as f:
# Read in all background energy densities
background = f['background']
print('Available background quantities:', list(background.keys()))
a_bg = background['a'][:]
ρ_bg = {}
for key, val in background.items():
match = re.search(r'^rho_(.+)$', key)
if match:
ρ_bg[match.group(1)] = val[:]
h = background.attrs['h']
# Read in all δ perturbations
perturbations = f['perturbations']
print('Available perturbations:', list(perturbations.keys()))
a_pt = perturbations['a'][:]
k_pt = perturbations['k'][:]
δ_pt = {}
for key, val in perturbations.items():
match = re.search(r'^delta_(.+)$', key)
if match:
δ_pt[match.group(1)] = val[...]
gauge = perturbations.attrs['gauge']
# Get unit system
units = dict(f['units'].attrs)
print('Units:', units)
# Construct matter power spectrum interpolator
A_s = 2.1e-9
n_s = 0.96
α_s = 0
k_pivot = 0.05 # [Mpc⁻¹]
ζ = lambda k: (
np.pi*np.sqrt(2*A_s)
*k**(-3/2)*(k/k_pivot)**((n_s - 1)/2)
*np.exp(α_s/4*np.log(k/k_pivot)**2)
)
interpolator = scipy.interpolate.RegularGridInterpolator(
(np.log(k_pt), np.log(a_pt)),
np.log((ζ(k_pt)*δ_pt['b+cdm'])**2).T,
method='cubic',
)
P_m = lambda z, logk=np.log(k_pt), interpolator=interpolator: (
np.exp(interpolator((logk, np.log(1/(1 + z)))))
)
# Construct δρ interpolators for all species
δρ = {}
for species, δ_species in δ_pt.items():
ρ_species = np.exp(scipy.interpolate.interp1d(
np.log(a_bg),
np.log(ρ_bg[species]),
kind='cubic',
)(np.log(a_pt)))
interpolator = scipy.interpolate.RegularGridInterpolator(
(np.log(k_pt), np.log(a_pt)),
(δ_species*ρ_species.reshape(-1, 1)).T,
method='linear',
)
δρ[species] = lambda z, logk=np.log(k_pt), interpolator=interpolator: (
interpolator((logk, np.log(1/(1 + z))))
)
# Plot energy density history
fig, axes = plt.subplots(2, 2, figsize=(9, 6.75))
ax = axes[0, 0]
a_min = 1e-3
mask = (a_bg >= a_min)
for species, ρ in ρ_bg.items():
match = re.search(r'^(b|cdm|g|ncdm\[\d+\]|lambda)$', species)
if match:
ax.loglog(a_bg[mask], ρ[mask]/ρ_bg['crit'][mask], label=species)
ax.set_xlim(a_min, 1)
ax.set_ylim(bottom=1e-5)
ax.legend(fontsize=8)
ax.set_xlabel(r'$a$')
ax.set_ylabel(r'$\bar{{\rho}}_{\alpha}/\rho_{\mathrm{crit}}$')
ax.set_title(f'Energy density history')
# Plot matter power spectrum
ax = axes[0, 1]
z_values = [0, 0.5, 1, 2, 5, 10]
for z in z_values:
ax.loglog(k_pt/h, h**3*P_m(z), label=rf'$z = {z}$')
ax.set_xlim(k_pt[0]/h, k_pt[-1]/h)
ax.legend(fontsize=8)
unit_length = units['unit length']
ax.set_xlabel(rf'$k\, \left[h\, \mathrm{{{unit_length}}}^{{-1}}\right]$')
ax.set_ylabel(
rf'$P_{{\mathrm{{b}}+\mathrm{{cdm}}}}\, '
rf'\left[(h^{{-1}}\, \mathrm{{{unit_length}}})^3\right]$'
)
ax.yaxis.tick_right()
ax.yaxis.set_label_position('right')
ax.set_title(f'Matter power spectrum ({gauge} gauge)')
# Plot δρ perturbations of all species
z_values = [50, 1]
unit_mass = (
units['unit mass']
.replace(r'**(10)', r'^{10}')
.replace(r'*m_sun', r'\, m_{\odot}')
)
for ax, z in zip(axes[1, :], z_values):
for i, (species, δρ_species) in enumerate(δρ.items()):
for sign, linestyle, label in zip([-1, +1], ['-', ':'], [species, None]):
ax.loglog(k_pt/h, sign*δρ_species(z), f'C{i}{linestyle}',
zorder=(-np.inf if species == 'metric' else None), label=label)
ax.set_xlim(k_pt[0]/h, k_pt[-1]/h)
ax.set_ylim(bottom=min(
np.min(-δρ['g' ](z)),
np.min(-δρ['ncdm[0]'](z)),
))
ax.set_xlabel(rf'$k\, \left[h\, \mathrm{{{unit_length}}}^{{-1}}\right]$')
ax.set_ylabel(
rf'$-\delta\rho_{{\alpha}}\, '
rf'\left[{unit_mass}\, \mathrm{{{unit_length}}}^{{-3}}\right]$'
)
ax.set_title(rf'$\delta\rho$ perturbations ({gauge} gauge)')
ax.text(0.8, 0.73, rf'$z = {z}$', transform=ax.transAxes)
axes[1, 0].legend(fontsize=8)
axes[1, 1].yaxis.tick_right()
axes[1, 1].yaxis.set_label_position('right')
# Save figure
fig.tight_layout()
fig.savefig('plot.png', dpi=150)
To run the above script, save it to a file — e.g.
plot.py
— within the same directory as class_processed.hdf5
, then
execute it with
python3 plot.py
where python3
is your Python executable.
Tip
The plotting script requires the Python packages NumPy, SciPy, Matplotlib and H5Py, all of which are installed with the Python distribution that comes with CONCEPT. If you have CONCEPT installed (i.e. are not running through Docker), you may then use
source /path/to/concept-installation/concept
$python plot.py
The result of running the script is an image file
plot.png
with \(2\times 2\) panels, showing
Top left: The evolution history of the background densities \(\bar{\rho}_{\alpha}(a)\) for the different species \(\alpha\), relative to the critical density \(\rho_{\text{crit}}(a)\).
Top right: The matter power spectrum \(P_{\text{b}+\text{cdm}}(k)\) at different redshifts \(z\). This is constructed as
\[P_{\text{b}+\text{cdm}}(z, k) = \zeta^2(k) \delta^2_{\text{b}+\text{cdm}}(z, k)\,,\]with \(\delta_{\text{b}+\text{cdm}}(z, k)\) obtained from
class_processed.hdf5
and \(\zeta(k)\) being the primordial curvature perturbation, parametrised by the primordial parameters \(A_{\text{s}}\), \(n_{\text{s}}\), \(\alpha_{\text{s}}\) and \(k_{\text{pivot}}\) as describe here. The script assigns some values to these parameters. Importantly, these values are independent of the CLASS computation of the \(\delta\) perturbations.Lower panels: The \(\delta\rho_{\alpha}(k)\) perturbations for the different species \(\alpha\) at two redshifts (early and late). The fictitious \(\delta\rho_{\text{metric}}\) perturbation — supplying general relativistic corrections — generally oscillates wildly, having both positive and negative values. Dotted lines depict negative values that have been flipped.
Note
In CLASS, the sign convention is such that e.g. \(\delta_{\text{cdm}}\) is in fact purely negative. What is plotted is thus \(-\delta_{\alpha}\).
Running through Docker
As described under Supported platforms, it is possible to run CONCEPT through Docker. While not preferable for running large simulations, running CONCEPT this way for casual use of the class utility is very much encouraged.
Given a parameter file named class-param
(e.g.
the one above), you may run the CONCEPT class
utility through Docker by executing something like
docker run \
--rm \
-v "${PWD}:/mnt" \
jmddk/concept \
concept \
-u class \
--kmin 1e-3/Mpc --kmax 0.1/Mpc --modes 128 \
--times 512 \
"b+cdm:1, g" \
-p /mnt/class-param \
-n 4
from within the directory of class-param
. Given that
output_dirs = param.dir
is specified within class-param
, the resulting
HDF5 file will be placed in your current directory.
Note
If running Windows, the above command is valid within PowerShell, not CMD
You can even get rid of the parameter file — running the CONCEPT class
utility using a stand-alone one-liner — by supplying the necessary
parameters via the -c
command-line option.
Tips and tricks
Below we list a few tips and tricks that are not discussed above.
Plotting perturbations on the fly
It can be difficult to judge whether the various CLASS precision parameters are cranked up high enough to ensure reasonable convergence of the different perturbations. To help with this assessment, it can be useful to see the perturbations plotted, with jagged lines indicating lack of convergence.
By setting the class_plot_perturbations
parameter to True
, CONCEPT will
plot all perturbations entering into the computation of the data in the final
class_processed.hdf5
file. E.g.
./concept \
-u class \
--kmin <kmin> --kmax <kmax> \
<perturbations> \ -c "class_plot_perturbations = True"
This will create a class_perturbations
and a
class_perturbations_processed
directory, containing plots of the various
perturbations. For details on their content, see the
class_plot_perturbations
parameter.
The plots within class_plot_perturbations
show detrended perturbations,
allowing for a detailed view. In these plots, wildly oscillating behaviour is
often seen, which may or may not be physical. Non-smooth, jagged behaviour is
typically a sign of a lack of convergence, though note that this may not be an
issue, since often, most of the information is contained just within the
trend-line. To check whether a convergence problem clearly manifest in the
full (non-detrended) perturbations, check the plots inside the
class_perturbations_processed
directory.
Replacing bad CLASS perturbations
Obtaining converged CLASS perturbations for all \(k\) of interest may require extremely high precision CLASS settings, which in turn increases the time and memory requirements for the CLASS computation. Often, converged perturbations in all species are only needed at large scales, as the small scales are completely dominated by matter. Allowing some non-convergence in the other species at high \(k\) is thus often acceptable, with the benefit that lower CLASS precision settings can be used.
However, pathological behaviour in any perturbation may cause trouble (such
can be detected using the class_plot_perturbations
parameter as described above). If a
perturbation is thought to be ill-behaved beyond some \(k\), CONCEPT
can be told to replace perturbation values at larger \(k\) with new values
obtained via extrapolation from the perturbation values at lower \(k\),
using the class_k_max
parameter. To e.g. only use the
actual CLASS data for \(\partial_{\tau} H_{\text{T}}\) (the conformal time
derivative of the trace-free component of the spatial N-body gauge metric)
up until \(k = 10\, h\, \text{Mpc}^{-1}\), with data beyond this \(k\)
constructed through extrapolation of lower \(k\) data:
./concept \
-u class \
--kmin <kmin> --kmax <kmax> \
<perturbations> \ -c "class_k_max = {'H_T_prime': 10*h/Mpc}"
Ignoring or cleaning the CLASS cache
CONCEPT automatically cashes CLASS computations to disk. When running the CONCEPT class utility several times over with the same input, the first CLASS computation will then be reused, saving computation time.
This behaviour is not always what you want, e.g. if changes to the CLASS
source code has been introduced after a disk caching. To request a rerun of
CLASS regardless of whether a matching cache is found on disk, set the
class_reuse
parameter to False
, e.g.
./concept \
-u class \
--kmin <kmin> --kmax <kmax> \
<perturbations> \ -c "class_reuse = False"
Even with class_reuse = False
, new CLASS computations will be cached to
disk. If the disk cache already exists, this will not be overwritten.
To clear the reusable CLASS cache completely, you may run
(source concept && make clean-class-reusable)