9. Comparison with GADGET-2
In this section we shall perform equivalent simulations with CONCEPT and the well-known GADGET-2 code. Due to the two codes utilising different numerical schemes, as well as the fact that CONCEPT — unlike GADGET-2 — is designed to be consistent with general relativistic perturbation theory by default, some subtleties need to be taken into account in order to perform simulations with CONCEPT that are truly equivalent to those of GADGET-2.
If you are unfamiliar with GADGET-2 or have no interest in running GADGET-2 equivalent simulations with CONCEPT, you may skip this section. However, many of the tricks to come are not exclusively related to GADGET-2.
CON CEPT
As always, we start with a CONCEPT parameter file, which you should save
as e.g. param/tutorial-9
:
# Input/output
if _gen:
initial_conditions = { 'name' : 'GADGET halo', 'species': 'matter',
'N' : _size**3,
}
else:
initial_conditions = f'{path.ic_dir}/{param}_a={a_begin}'
output_dirs = {
'snapshot': path.ic_dir if _gen else f'{path.output_dir}/{param}',
'powerspec': ...,
}
output_bases = {
'snapshot': param if _gen else 'snapshot',
}
output_times = {
'snapshot' : a_begin if _gen else '',
'powerspec': '' if _gen else [0.1, 0.3, 1.0],
}snapshot_type = 'gadget'
# Numerics
boxsize = 512*Mpc/h
potential_options = 2*_size
# Cosmology
H0 = 67*km/(s*Mpc)
Ωb = 0.049
Ωcdm = 0.27
a_begin = 0.02
# Physicsrealization_options = { 'gauge' : 'synchronous', 'back-scale': True,}# Non-parameter helper variables
_size = 64_gen = False
To perform the same simulation with both CONCEPT and GADGET-2, we shall
want to start from a common initial snapshot. The
parameter file is set up to produce this initial
snapshot when _gen
is True
. To create the snapshot then, do
./concept \
-p param/tutorial-9 \
-c "_gen = True"
(as always, feel free to tack on the number of processes you want
with -n
). The snapshot will be dumped to the ic
directory.
As we have snapshot_type = 'gadget'
, the snapshot will be in
GADGET format. Furthermore, naming the matter component 'GADGET halo'
ensures that this component gets mapped to GADGET particle type 1
(conventionally used for cold dark matter, see table 3 in the
user guide for GADGET-2
).
Starting from this snapshot we can now perform the CONCEPT simulation by
running with -c "_gen = False"
. As this is also the value set in the
parameter file, we may in fact start the simulation
simply by
./concept -p param/tutorial-9
Note that the initial_conditions
is set to the path of the generated
snapshot when _gen
is False
.
The power spectrum outputs of the CONCEPT simulation will be dumped to
output/tutorial-9
as usual.
GADGET-2
For GADGET-2, the first thing we need is the source code itself. If you have installed CONCEPT the easy way, you already have it! Let’s make a copy just for use with this tutorial:
(source concept && cp -r "${Gadget2_dir}" "${output_dir}"/tutorial-9/)
You now have the complete GADGET-2 code in output/tutorial-9/Gadget2
.
The Makefile
of GADGET-2 needs to be set up with correct path information
for its dependencies. Furthermore, various options need to be set in order
for the GADGET-2 simulation to come to be equivalent to the CONCEPT
simulation. Last but not least, we need a GADGET-2 parameter file equivalent
to the CONCEPT parameter file. All of this can be
conveniently achieved using the gadget utility included with CONCEPT:
./concept \
-u gadget output/tutorial-9/Gadget2 \
-p param/tutorial-9
The output/tutorial-9/Gadget2
directory now has a properly set up
Makefile
and a parameter file called param
. The output times of the
original parameter file have also been copied to an
outputlist
file, similarly placed in output/tutorial-9/Gadget2
.
Note
The parameters specified in the GADGET-2 Makefile
and param
file
include the cosmology, the grid size of the PM grid, the particle softening
lengths and more, all set to match those used by the specific CONCEPT
simulation as specified by the parameter file
together with default CONCEPT values.
The GADGET-2 TreePM gravitational method is used, which is quite similar in essence to the P³M method used by the CONCEPT simulation, the difference being that the tree approximates the gravitational short-range force by grouping particles together.
Lastly, the values of physical constants employed by CONCEPT and GADGET-2 differ slightly, which will make a small difference for the comparison. If the GADGET-2 source code you are using is the one that goes with the CONCEPT installation, all such constants of the GADGET-2 source code have been patched to match the values used by CONCEPT.
With the various GADGET-2 files in place, let’s build the code and launch the simulation:
(source concept \
&& cd output/tutorial-9/Gadget2 \
&& make clean \
&& make \
&& $mpiexec -n 4 ./Gadget2 param)
where you may wish to change the specified number of processes deployed.
As GADGET-2 is not able to produce power spectra, the results from the
simulation are raw snapshots, placed along with other files in
output/tutorial-9/Gadget2/output
. To investigate these snapshots, we can
make use of the info utility:
./concept -u info output/tutorial-9/Gadget2/output
You should find that the snapshots indeed have the same values of the scale factor \(a\) as specified in the parameter file (perhaps with small numerical errors).
To measure the power spectra of the particle distributions contained within the snapshots, we may make use of the powerspec utility:
./concept \
-u powerspec output/tutorial-9/Gadget2/output \
-p param/tutorial-9
(as always, you may choose to throw more processes at the task with -n
).
Comparison and adjustments
You should now have CONCEPT power spectra in output/tutorial-9
and
corresponding GADGET-2 power spectra in /output/tutorial-9/Gadget2/output
.
We can of course look at each pair of plots, but for a proper comparison we
should plot the power spectra together in a single plot. You may use the
script below:
import glob, os, re
import numpy as np
import matplotlib; matplotlib.use('agg')
import matplotlib.pyplot as plt
# Particle Nyquist frequency
Mpc = 1
h = 0.67
boxsize = 512*Mpc/h
num_particles = 64**3
k_nyquist = 2*np.pi/boxsize*np.cbrt(num_particles)/2
# Read in CO𝘕CEPT data
def read(dirname):
P = {}
for filename in sorted(glob.glob(f'{dirname}/powerspec*'), key=os.path.getmtime):
if filename.endswith('.png'):
continue
with open(filename, mode='r', encoding='utf-8') as f:
header = f.readline()
a = float(re.search('a = (.+)', header).group(1).rstrip('.'))
k, P[float(f'{a:.3f}')] = np.loadtxt(filename, usecols=(0, 2), unpack=True)
return k, P
this_dir = os.path.dirname(os.path.realpath(__file__))
k, P_concept = read(this_dir)
# Read in GADGET-2 data
k, P_gadget = read(f'{this_dir}/Gadget2/output')
# Plot
fig, axes = plt.subplots(2, sharex=True)
for a, P in P_concept.items():
axes[0].loglog(k, P, label=f'$a = {a}$ (CO$N$CEPT)')
if a in P_gadget:
axes[0].loglog(k, P_gadget[a], 'k--')
axes[1].semilogx(k, 100*(P/P_gadget[a] - 1))
for ax in axes:
ylim = ax.get_ylim()
ax.plot([k_nyquist]*2, ylim, ':', color='grey')
ax.set_ylim(ylim)
ax.text(
k_nyquist,
ylim[0] + 0.15*np.diff(ylim),
r'$k_{\mathrm{Nyquist}}\rightarrow$',
ha='right',
)
axes[0].set_xlim(k[0], k[-1])
axes[1].set_xlabel(r'$k\, [\mathrm{Mpc}^{-1}]$')
axes[0].set_ylabel(r'$P\, [\mathrm{Mpc}^3]$')
axes[1].set_ylabel(r'$P_{\mathrm{CO}N\mathrm{CEPT}}/P_{\mathrm{GADGET}} - 1\, [\%]$')
axes[0].legend()
axes[0].tick_params('x', direction='inout', which='both')
axes[1].set_zorder(-1)
fig.tight_layout()
fig.subplots_adjust(hspace=0)
fig.savefig(f'{this_dir}/plot.png', dpi=150)
Store the script as e.g. output/tutorial-9/plot.py
and run it using
./concept -m output/tutorial-9/plot.py
The upper subplot — with absolute power spectra — of the generated
output/tutorial-9/plot.png
should show a good qualitative match between the
two codes, whereas the lower subplot — with relative power spectra —
should reveal a disagreement of several percent. This disagreement stems from
both physical and numerical differences between the codes, which we will now
alleviate by adjusting the CONCEPT simulation.
Cell-centred vs. cell-vertex discretisation
The initial particle distribution, stored within the generated initial
snapshot file ic/tutorial-9_a=0.02
, should ideally be close to homogeneous
and isotropic. We can check this qualitatively by plotting the distribution
in 3D. For this, let’s use the render3D utility:
./concept \
-u render3D ic/tutorial-9_a=0.02 \
-p param/tutorial-9 \
-c "render3D_options = { \
'interpolation': 0, \
'color': 'black', \
'background': 'white', \
'resolution': 2000}"
This produces an image file in the ic
directory. Zooming in on one of the
corners of the box, it should be clear that while we do have a close to
homogeneous system, it is far from isotropic.
Note
Adding the render3D_options
parameter above tunes the render so that it
more clearly shows what we’re after. Indeed, a more interesting render is
obtained by not adding this parameter.
The strong anisotropy of the particles is inherited from the grid on which
they are (pre-)initialised. This grid-like structure of the particle
distribution makes the system sensitive towards other grids used during the
simulation, e.g. the potential grid. In CONCEPT, a default choice of
using ‘cell-centred’ grid discretisation is made, whereas GADGET-2 uses
‘cell-vertex’ grid discretisation. In effect this means that the potential
grids of the two codes are shifted by half a grid cell relative to each other,
in all three dimensions (see the cell_centered
parameter for more information). This detail oughtn’t
matter much, but the grid structure imprinted on the particle distribution,
together with the fact that our simulations are rather small
(\(N = 64^3\)), makes for an exaggerated effect.
We can force CONCEPT to use cell-vertex discretisation by specifying
cell_centered = False
Introduce this new parameter — either by editing the parameter file or
supplying it with -c
— and rerun the CONCEPT simulation. After
also updating the comparison plot, you should find that the relative error is
now much smaller, though still a few percent.
Note
Though we now have better agreement, we should not be tempted to conclude that cell-vertex discretisation is superior to its cell-centred cousin. The improvement came from using the same discretisation.
The observed difference in results for the two discretisation schemes would
be smaller had the initial conditions not contained the strong
anisotropies. CONCEPT does allow for the creation of more isotropic
initial condition by initially placing the particles on either a
body-centered cubic (bcc) lattice or a face-centered cubic (fcc) lattice,
rather than the standard simple cubic (sc) lattice. See the
initial_conditions
parameter
for more information.
Though undesirable when comparing against GADGET-2, CONCEPT
additionally effectively allows for simultaneous usage of both
discretisation schemes by carrying out both of them followed by an
interlacing step to combine the results. This technique effectively
lowers the discretisation scale, reducing the numerical artefacts. For
more information about potential interlacing, see the potential_options
parameter.
Radiation in the background
A key difference between CONCEPT and GADGET-2 is that the former — unlike the latter — tries to incorporate all species of a given cosmology, as demonstrated in the previous section. As such, CONCEPT uses a full background evolution obtained from the CLASS code. By default, this CLASS background includes matter, \(\Lambda\) and radiation, whereas the background of GADGET-2 only consists of matter and \(\Lambda\).
One cannot remove radiation from the CLASS background, as a cosmology without radiation is not supported by CLASS. Instead, we can deactivate the CLASS background entirely, which will turn on an internal background solver of CONCEPT, which like that of GADGET-2 only includes matter and \(\Lambda\). To do so, add
enable_class_background = False
to the parameters (while also still keeping cell_centered = False
) and
rerun the CONCEPT simulation.
Updating the comparison plot, the codes should now agree to within a percent.
Increased short-range precision
The gravitational force of the P³M method in CONCEPT and the TreePM method of GADGET-2 is split into a long-range and a short-range part at a scale \(x_{\text{s}}\), which in both CONCEPT and GADGET-2 has a default value of \(x_{\text{s}} = 1.25 \Delta x\), with \(\Delta x\) the cell size of the potential grid. The short-range force between pairs of particles separated by a distance somewhat larger than \(x_{\text{s}}\) falls off exponentially with the distance. Particle pairs with a separation \(|\boldsymbol{x}_i - \boldsymbol{x}_j| > x_{\text{r}}\) may then be neglected, provided \(x_{\text{r}} \gg x_{\text{s}}\).
In both CONCEPT and GADGET-2, the range of the short-range force has a default value of \(x_{\text{r}} = 4.5x_{\text{s}}\). Due to the grouping of particles by the tree in GADGET-2, the short-range forces between some particles separated by distances somewhat larger than \(x_{\text{r}}\) are being taken into account as well. We can then hope to obtain still better agreement with GADGET-2 by increasing the value of \(x_{\text{r}}\) in CONCEPT slightly. Try rerunning CONCEPT with \(x_{\text{r}} = 5.5x_{\text{s}}\) with the added parameter
shortrange_params = {'range': '5.5*scale'}
and updating the comparison plot. You should find that the two codes now agree well within 1%.
For still better agreement, you may try similarly upgrading
\(x_{\text{r}}\) to \(5.5x_{\text{s}}\) in GADGET-2 (either by
including the updated shortrange_params
when running the CONCEPT
gadget
utility or by manually setting RCUT
in
output/tutorial-9/Gadget2/Makefile
) and then re-compiling and -running
GADGET-2 and computing the power spectra from the new snapshots. Improved
agreement between the two codes is also achieved by increasing the
simulation size.
Final notes
CONCEPT strives to be consistent with general relativistic perturbation theory. It does so by using the full background from CLASS, and adding in gravitational effects from linear perturbations of other species (when enabled), ensuring that the simulation stays in the so-called N-body gauge. All this fanciness is hardly needed when running without massive neutrinos or other exotic species, which GADGET-2 does not support.
GADGET-2 only allows for the simulation of matter (though besides the standard
cold dark matter particles, it further supports (smoothed-particle)
hydrodynamical baryons), and always uses a background containing just matter
and \(\Lambda\). Sticking to even the simplest ΛCDM cosmologies (which
do include photons), neglecting the gravitational tug from radiation is
unacceptable for precision simulations. To resolve this problem, the usual
trick used with Newtonian N-body codes is to generate initial conditions at
\(a = a_{\text{begin}}\) using the results of general relativistic
perturbations theory (which also accounts for radiation) at \(a = 1\), but
scaled back in time using the Newtonian growth factor. Thus, only the
\(a = 1\) results of such back-scaled simulations are really physical.
The realization_options
parameter in the
parameter file used for this section specifies that
back-scaling should be used when generating the initial conditions, and also
that this should be done within the synchronous gauge (as opposed to the
default N-body gauge), as is typically used with back-scaling.
In the above, we eventually disabled the CLASS background within CONCEPT
simulations by setting enable_class_background = False
, which then instead
makes use of a simplified matter + Λ background, similar to what is used
within GADGET-2. Note however that we did this after creating the initial
conditions, meaning that the back-scaling was done in a background that
includes radiation, causing a slight inconsistency. For the comparison between
CONCEPT and GADGET-2, this is not relevant, but for physically accurate
results, the same value of enable_class_background
should be used when
generating the initial conditions as used within the simulation itself.
When using back-scaling, the particle velocities are obtained from the same
(\(\delta\)) transfer function as the positions, using a Newtonian
approximation. The velocities are thus not the actual synchronous gauge
velocities, but are in fact closer to the velocities within the N-body
gauge, as obtained from the \(\theta\) transfer function and no
back-scaling. As the synchronous and N-body gauge \(\delta\) transfer
functions are quite similar, the back-scaled synchronous gauge initial
conditions — used within this section — are then in fact very similar to
the non-back-scaled N-body gauge initial conditions used within
CONCEPT by default. The specifications within realization_options
in
the parameter file are thus not very crucial for the
results, but mostly put there to comply with the spirit of Newtonian
N-body simulations and GADGET-2. We note again that the real difference
between the N-body gauge approach and the back-scaled, synchronous gauge
approach is to be found outside basic ΛCDM cosmologies and matter-only
simulations, where the Newtonian approximations used for the back-scaling
break down.