Numerics
The ‘numerics’ parameter category contains parameters specifying various options regarding the numerical methods used within the simulation, as well as some numerical resolutions and length scales.
boxsize
Description |
Specifies size of simulation box |
||
Default |
512*Mpc
|
||
Elaboration |
All CONCEPT simulations take place within a cubic box of constant comoving side length \(L_{\text{box}}\). This parameter sets this length. |
||
Example 0 |
Use a box size of \(1024\,\text{Mpc}\): boxsize = 1024*Mpc
|
||
Example 1 |
Use a box size of \(1\,\text{Gpc} = 1000\,\text{Mpc}\): boxsize = 1*Gpc
|
||
Example 2 |
Use a box size of \(1024\,\text{Mpc}/h\): boxsize = 1024*Mpc/h
With e.g. \(H_0 = 64\,\text{km}\, \text{s}^{-1}\, \text{Mpc}^{-1}\), this is equivalent to boxsize = 1600*Mpc
Note See the |
potential_options
Description |
Specifications for potential computations |
||
Default |
{
'gridsize': {
'global': {},
'particles': {
'gravity': {
'pm' : ( 'cbrt(Ñ)', 'cbrt(Ñ)'),
'p3m': ('2*cbrt(Ñ)', '2*cbrt(Ñ)'),
},
'lapse': {
'pm': ('cbrt(Ñ)', 'cbrt(Ñ)'),
},
},
'fluid': {
'gravity': {
'pm': ('gridsize', 'gridsize'),
},
'lapse': {
'pm': ('gridsize', 'gridsize'),
},
},
},
'interpolation': {
'gravity': {
'pm' : 'CIC',
'p3m': 'CIC',
},
'lapse': {
'pm': 2,
},
},
'deconvolve': {
'gravity': {
'pm' : (True, True),
'p3m': (True, True),
},
'lapse': {
'pm': (True, True),
},
},
'interlace': {
'gravity': {
'pm' : (False, False),
'p3m': (False, False),
},
'lapse': {
'pm': (False, False),
},
},
'differentiation': {
'default': {
'gravity': {
'pm' : 2,
'p3m': 4,
},
'lapse': {
'pm': 2,
},
},
},
}
|
||
Elaboration |
This parameter is a Potentials are discretised on grids in order to implement long-range interactions. Note Currently, two distinct long-range
interactions/forces are implemented; In CONCEPT a long-range interaction takes place between two groups of components; the suppliers and the receivers, which respectively build the potential and receive a force due to it. In the simplest case of self-gravity between particles of a single component, this component is both the sole supplier and receiver component. CONCEPT uses an ‘upstream \(\rightarrow\) global \(\rightarrow\) downstream scheme’ for potentials, as outlined below:
For receivers obtaining the force grid from the downstream real-space potential grid:
For receivers obtaining the force grid from the downstream Fourier-space potential:
Note Though the above recipe is conceptually faithful to the actual implementation in CONCEPT, typically many of the steps can be combined, reducing the total number of steps (and grids in memory) significantly. In all cases, CONCEPT collapses the above procedure to its minimal equivalence, which in simple (typical) cases among other things leaves out the upstream and downstream potentials completely and combines the two deconvolutions into one. With the implemented potential scheme outlined above,
the different sub-parameters of the
|
||
Example 0 |
Use default potential options, but set the global gravitational P³M potential grid size to \(128\): potential_options = {
'gridsize': {
'global': {
'gravity': {
'p3m': 128,
},
},
},
}
This can be shortened to potential_options = {
'gridsize': {
'global': {
'gravity': 128,
},
},
}
though now both the P³M and PM method of gravity gets a global grid size of \(128\) (if the simulation does not make use of PM, this does not matter). The above can be further shortened to potential_options = {
'gridsize': {
'global': 128,
},
}
Here it will be detected that no force/interaction has
been specified, in which case the default one
— potential_options = {
'gridsize': 128,
}
though this now also sets potential_options = 128
|
||
Example 1 |
Use default potential options, but set the
gravitational P³M potential grid size to \(128\),
for the global potential as well as for the upstream
and downstream potential grids for the component with a
name/species of potential_options = {
'gridsize': {
'global': {
'gravity': {
'pm' : 64,
'p3m': 128,
},
},
'matter': {
'gravity': {
'p3m': (128, 128),
},
},
},
}
Note As the upstream and downstream grid size within the 2-tuple are identical, this can be shortened to potential_options = {
'gridsize': {
'global': {
'gravity': {
'pm' : 64,
'p3m': 128,
},
},
'matter': {
'gravity': {
'p3m': 128,
},
},
},
}
Note This further assigns |
||
Example 2 |
For the gravitational interaction, be it PM or P³M, make use of the highest available order for particle interpolation (PCS), as well as both upstream and downstream (standard) interlacing. Use \(80\) as the size of all potential grids. potential_options = {
'gridsize': 80,
'interpolation': {
'gravity': 'PCS',
},
'interlace': {
'gravity': (True, True), # or ('bcc', 'bcc')
}
}
|
||
Example 3 |
Use \(128\) as the size of all potential grids, use order-6 real-space finite differencing to obtain the force from the gravitational PM potential and use Fourier-space differentiation to obtain the force from the gravitational P³M potential: potential_options = {
'gridsize': 128,
'differentiation': {
'all': {
'gravity': {
'pm' : 6,
'p3m': 'Fourier',
},
},
},
}
|
shortrange_params
Description |
Specifications for short-range forces |
||
Default |
{
'gravity': {
'scale' : '1.25*boxsize/gridsize',
'range' : '4.5*scale',
'tilesize' : 'range',
'subtiling': ('automatic', 16),
'tablesize': 4096,
},
}
|
||
Elaboration |
This parameter is a Each of the sub-parameters are described below.
|
||
Example 0 |
Extend \(x_{\text{r}}\) all the way to \(5.5 x_{\text{s}}\), for the gravitational short-range interaction: shortrange_params = {
'gravity': {
'scale': '1.25*boxsize/gridsize',
'range': '5.5*scale',
},
}
We can shorten the above to shortrange_params = {
'scale': '1.25*boxsize/gridsize',
'range': '5.5*scale',
}
in which case Note In both cases, the remaining sub-parameters will receive default values |
||
Example 1 |
Use a fixed subtile decomposition of \((3, 3, 3)\) for the gravitational short-range interaction: shortrange_params = {
'subtiling': (3, 3, 3),
}
As all three subdivisions are equal, this can be shortened to shortrange_params = {
'subtiling': 3,
}
While probably a bit slower than using automatic subtile refinement, this subtile decomposition has the benefit of being static and thus deterministic. |
||
Example 2 |
Use dynamic subtile refinement with a period of \(8\) time steps for the gravitational short-range interaction: shortrange_params = {
'subtiling': ('automatic', 8),
}
|
powerspec_options
Description |
Specifications for power spectrum computations and dumps |
||
Default |
{
'upstream gridsize': {
'particles': '2*cbrt(Ñ)',
'fluid' : 'gridsize',
},
'global gridsize': {},
'interpolation': {
'default': 'PCS',
},
'deconvolve': {
'default': True,
},
'interlace': {
'default': True,
},
'realization correction': {
'default': True,
},
'k_max': {
'default': 'nyquist',
},
'bins per decade': {
'default': {
' 4*k_min': 4,
'100*k_min': 40,
},
},
'tophat': {
'default': 8*Mpc/h,
},
'significant figures': {
'default': 8,
},
}
|
||
Elaboration |
This is a For computing a power spectrum, one or more components
are first interpolated onto individual upstream grids,
possibly using deconvolution and interlacing, after
which they are added together in Fourier space,
producing a global grid. This scheme is similar to the
one used for potentials, except here we never go back to
real space, neither do we interpolate anything back to
the particles. See the Each sub-parameter is described below:
Note For all sub-parameters above except
|
||
Example 0 |
Use an upstream grid size of \(256\) for the
component with a name/species of powerspec_options = {
'upstream gridsize': {
'matter': 256,
},
}
As we did not specify a global grid size, this will similarly be \(256\). We can also set both explicitly by using powerspec_options = {
'gridsize': {
'matter': 256,
},
}
Here |
||
Example 1 |
Employ many (small) bins of the same (logarithmic) size for all \(k\) of every power spectrum: powerspec_options = {
'bins per decade': {
'all' : 100,
'all combinations': ...,
},
}
This may be shortened to powerspec_options = {
'bins per decade': 100,
}
|
||
Example 2 |
Use CIC interpolation and disable interlacing for power
spectra of the component with a name/species of
powerspec_options = {
'interpolation': {
'matter': 'CIC',
},
'interlace': {
'matter': False, # or 'sc'
}
}
|
bispec_options
Description |
Specifications for bispectrum computations and dumps |
||
Default |
{
'configuration': {
'default': ('equilateral', 20),
},
'shellthickness': {
'default': [
{
'1*k_fundamental': '0.25*k_fundamental',
'4*k_fundamental': 'max(3*k_fundamental, 1/20*log(10)*k)',
},
{
'1*k_fundamental': '0.25*k_fundamental',
'4*k_fundamental': 'max(3*k_fundamental, 1/20*log(10)*k)',
},
{
'1*k_fundamental': '0.25*k_fundamental',
'4*k_fundamental': 'max(3*k_fundamental, 1/20*log(10)*k)',
},
]
},
'upstream gridsize': {
'particles': '2*cbrt(Ñ)',
'fluid' : 'gridsize',
},
'global gridsize': {},
'interpolation': {
'default': 'PCS',
},
'deconvolve': {
'default': True,
},
'interlace': {
'default': True,
},
'significant figures': {
'default': 8,
},
}
|
||
Elaboration |
This is a For computing a bispectrum, one or more components are
first interpolated onto individual upstream grids,
possibly using deconvolution and interlacing, after
which they are added together in Fourier space,
producing a global grid. This scheme is similar to the
one used for potentials, except here we never go back to
real space, neither do we interpolate anything back to
the particles. See the Many of the sub-parameters are the same as within the
Note For all sub-parameters except
|
||
Example 0 |
Use the equilateral configurations for bispectra of the
component with a name/species of bispec_options = {
'configuration': {
'matter': 'equilateral',
},
}
If we want more control over the number of bispectrum bins (the density of sampling points), we can specify the number of bins/subdivisions per decade along the \(k = k_1\) dimension (with the number of subdivisions along the \(t\) and \(\mu\) dimensions also adapting accordingly): bispec_options = {
'configuration': {
'matter': ('equilateral', 30),
},
}
Instead of using the predefined name bispec_options = {
'configuration': {
'matter': {
'k': 'logspace(log10(k_f), log10(nyquist), int(30*log10(nyquist/k_f)))',
't': 1,
'μ': 0.5,
},
},
}
The above specification for If we prefer, we might instead list each equilateral bin individually: _gridsize = 128 # global grid size for bispectrum
bispec_options = {
'configuration': {
'matter': [
(k, 1, 0.5)
for k in logspace(
log10(2*π/boxsize),
log10(2*π/boxsize*(_gridsize//2)),
int(30*log10(_gridsize//2)),
)
],
},
}
Note that in the above we have to reference the grid
size explicitly, whereas previously this was encoded in
_gridsize = 128 # global grid size for bispectrum
bispec_options = {
'configuration': {
'matter': [
(f'{q}*k_f', 1, 0.5)
for q in logspace(
0,
log10(_gridsize//2),
int(30*log10(_gridsize//2)),
)
],
},
}
|
||
Example 1 |
Use a constant shell thickness equal to three times the fundamental frequency, for shell \(k_1\), shell \(k_2\) and shell \(k_3\), for every bispectrum: bispec_options = {
'shellthickness': {
'all' : ['3*k_f', '3*k_f', '3*k_f'],
'all combinations': ...,
},
}
This may be shortened to bispec_options = {
'shellthickness': ['3*k_f', '3*k_f', '3*k_f'],
}
or indeed bispec_options = {
'shellthickness': '3*k_f',
}
|
||
Example 2 |
Use the equilateral configurations for bispectra of the
component with a name/species of bispec_options = {
'configuration': {
'matter': ('equilateral', 30),
},
}
Ideally, the concentric shells of different bins should not overlap, as otherwise the same underlying modes will each contribute to multiple bins. At the same time, we would like to include all available modes within our bins, and so together they should cover all of configuration space, i.e. we want there to be no gaps between the concentric shells. Given the 30 logarithmically equidistant shell radii above, we can match the shell thicknesses in order to achieve this: bispec_options = {
'configuration': {
'matter': ('equilateral', 30),
},
'shellthickness': {
'matter': '1/30*log(10)*k',
},
}
Note that with the growing shell thickness above, the usual shell thickness of \(3k_{\text{f}}\) is not achieved until \(k \sim 40k_{\text{f}}\). We may introduce a minimum shell thickness — say of \(1.5k_{\text{f}}\) — like so: bispec_options = {
'configuration': {
'matter': ('equilateral', 30),
},
'shellthickness': {
'matter': 'max(1.5*k_f, 1/30*log(10)*k)',
},
}
The above minimum shell thickness of \(1.5k_{\text{f}}\) applies for \(k \lesssim 20k_{\text{f}}\), though for the very lowest \(k\) we might want a smaller value. We can introduce a lowest thickness of e.g. \(0.25k_{\text{f}}\) below e.g. \(1k_{\text{f}}\), with the previous thickness specification being applied above e.g. \(10k_{\text{f}}\): bispec_options = {
'configuration': {
'matter': ('equilateral', 30),
},
'shellthickness': {
'matter': {
'1*k_f': '0.25*k_f',
'10*k_f': 'max(1.5*k_f, 1/30*log(10)*k)',
},
},
}
Between the two control points \(1k_{\text{f}}\) and \(10k_{\text{f}}\), the shell thickness is obtained through logarithmic interpolation. For example, the shell thickness at \(4k_{\text{f}}\) becomes \(\sim 1.0k_{\text{f}}\), given the above specification. Note the similarity with the above shell thickness settings and the default settings. |
||
Example 3 |
Measure the bispectrum for all isosceles configurations
— i.e. both L-isosceles and S-isosceles — for the
component with a name/species of bispec_options = {
'configuration': {
'matter': ['L-isosceles', 'S-isosceles'],
},
}
We might want to explicitly control the number of bins for each of two configuration subspaces: bispec_options = {
'configuration': {
'matter': [('L-isosceles', 15), ('S-isosceles', 25)],
},
}
Caution Due to the many possible configuration
specifications, the parsing of these specifications
is less robust than what is usually the case. In
particular, swapping ['L-isosceles', 'S-isosceles']
is a valid specification, this is not: ('L-isosceles', 'S-isosceles') # ❌
Note that the two sets of bins are written without separation in the output data file. However, the order in which the bins appear will always match the order in which they are specified. Tip For the case above (and most others), the transition from one configuration subset to another within a bispectrum data file can easily be located as the row where \(k\) decreases in relation to the previous row. |
||
Example 4 |
Use a squeezed configurations for bispectra of the
component with a name/species of bispec_options = {
'configuration': {
'matter': 'squeezed', # or e.g. (squeezed, 20)
},
}
The squeezed configurations are more tricky than other
configurations, as the \(k_3\) shell vanishes in
the squeezed limit \(t\rightarrow 1\),
\(\mu\rightarrow 0\), while a reliable bispectrum
measurement requires each shell to contain a substantial
amount of grid points. For the built-in bispec_options = {
'configuration': {
'matter': {
'k': (
'logspace(log10(5*k_f), '
'log10(2/3*nyquist), '
'int(20*log10(2/3*nyquist/(5*k_f))))'
),
't': 1,
'μ': 0.95,
},
},
}
In the above we have kept the \(k = k_1\) range the
same as the default; 20 points logarithmically
equidistant between 5 times the fundamental frequency
and two-thirds times the Nyquist frequency. Note however
that some of these configurations are rejected when
using the built-in With \(k_3\) much smaller than \(k_1\) and \(k_2\) it might makes sense to assign the \(k_3\) shell a thickness that is different from the one used by the \(k_1\) and \(k_2\) shell: bispec_options = {
'configuration': {
'matter': {
'k': (
'logspace(log10(5*k_f), '
'log10(2/3*nyquist), '
'int(20*log10(2/3*nyquist/(5*k_f))))'
),
't': 1,
'μ': 0.95,
},
},
'shellthickness': {
'matter': ['3*k_f', '3*k_f', '1.5*k_f'],
},
}
|
||
Example 5 |
Imitate the way Pylians computes bispectra:
Use \(k_1 = 1.1\, h\, \text{Mpc}^{-1}\),
\(k_2 = 0.8\, h\, \text{Mpc}^{-1}\) and \(50\)
values of \(\theta\) between \(0\) and
\(\require{upgreek}\uppi\). Apply all of this for
the component with a name/species of _k1 = 1.1*h/Mpc
_k2 = 0.8*h/Mpc
_θ = linspace(0, π, 50)
bispec_options = {
'configuration': {
'matter': {
'k': _k1,
't': _k2/_k1,
'μ': -cos(_θ),
},
},
'shellthickness': {
'matter': '2*k_f',
},
}
Note In order to fully reduce the bispectrum computation within CONCEPT to one consistent with that of Pylians, one should further:
|
||
Example 6 |
Sample the full configuration space for the component
with a name/species of bispec_options = {
'configuration': {
'matter': ('all', 5),
},
}
We recall that the full configuration space is parametrised as
\[\begin{split}\frac{1}{2} &\le t \le 1\,, \\
\frac{1}{2} &\le \mu \le 1\,, \\
\frac{1}{2} &\le t\mu\,,\end{split}\]
which uniquely covers each configuration (triangle
shape) for a given \(k\) (triangle size). While the
built-in np.random.seed(42) # for consistent bins
def _sample():
r = np.random.random(3)
k = f'k_min*(k_max/k_min)**{r[0]}'
t = (1 + r[1])/2
μ = (1 + r[2])/2
if t*μ < 0.5:
return _sample()
return k, t, μ
bispec_options = {
'configuration': {
'matter': [_sample() for _ in range(100)],
},
}
Note that the above samples the entire possible
\(k = k_1\) range, whereas this range is reduced
for the built-in |
bispec_antialiasing
Description |
Specifies whether to enable anti-aliasing for bispectrum shells |
||
Default |
True
|
||
Elaboration |
Numerically, each bispectrum shell is a collection of Fourier grid cells, each positioned a distance (measured from their centres) of about \(k\) from the origin (with \(k = k_1\) for the first shell, \(k = k_2\) for the second shell, \(k = k_3\) for the third shell). Call this distance the radial coordinate of the cell. With shell anti-aliasing disabled (not the default), a cell is included in the shell if its radial coordinate lies between \(k - s/2\) and \(k + s/2\), \(s\) being the shell thickness of the shell with radius \(k\). The simple scheme for cell inclusion/exclusion within a shell described above comes with a number of drawbacks, arising from allowing the discrete nature of the underlying grid to spread into the shell. A more sophisticated approach is to treat the shells as being truly spherical and continuous, with cells on the boundary being taken into account in proportion to their volumetric overlap with the shell. This is what we refer to as shell anti-aliasing (enabled by default). Note that with shell anti-aliasing, the inner and outer shell radii — related by their difference equalling the shell thickness \(s\) — can now be chosen such that the average (weighted) radial coordinate of the cells within the shell exactly equals the radius \(k\) of the shell, i.e. a measured bispectrum value \(B(k_1, k_2, k_3)\) really do belong exactly to the given \(k_1\), \(k_2\), \(k_3\). This is unlike the non-anti-aliased case where small changes to \(k_1\), \(k_2\), \(k_3\) do not alter the measured value \(B(k_1, k_2, k_3)\). Note For all but the smallest \(k\), CONCEPT in fact chooses the inner and outer shell radii not so that the average radial coordinate of the cells results in the radius \(k\) of the shell, but instead so that the average of the logarithm of the radial coordinates of the cells results in \(\log k\). |
||
Example 0 |
Turn off bispectrum shell anti-aliasing: bispec_antialiasing = False
Though generally not preferable, this is useful if the resulting bispectra are to be compared with ones computed by a different code which does not have this feature. |
class_dedicated_spectra
Description |
Specifies whether to carry out a dedicated CLASS computation for use with perturbation theory spectra |
||
Default |
False
|
||
Elaboration |
When Note This will only affect the perturbation theory output in power spectrum and bispectrum data files; the CLASS data used internally for simulation purposes will always be complete. |
||
Example 0 |
Always rerun CLASS as necessary, ensuring fully populated perturbation theory data in spectral output: class_dedicated_spectra = True
|
class_modes_per_decade
Description |
Number of Fourier modes \(k\) per decade in CLASS computations |
||
Default |
{
3e-3/Mpc: 10,
3e-2/Mpc: 30,
3e-1/Mpc: 30,
1/Mpc: 10,
}
|
||
Elaboration |
This parameter determines the number of CLASS perturbations to compute, by specifying the density of Fourier modes \(k\) as a (running) number per decade. The resulting tabulation of \(k\) is employed for all CLASS perturbations, which are used for e.g. initial conditions. The default choice yields a relatively sparse tabulation of perturbations, except around baryon acoustic oscillations, where more detail is added. If you seek highly resolved linear power spectra or
tree-level, make sure to not just increase
|
||
Example 0 |
Use a constant \(20\) modes per decade, i.e. \(20\) values of \(k\) placed logarithmically equidistant between \(k = 10^{-3}\,\text{Mpc}^{-1}\) and \(k = 10^{-2}\,\text{Mpc}^{-1}\), between \(k = 10^{-2}\,\text{Mpc}^{-1}\) and \(k = 10^{-1}\,\text{Mpc}^{-1}\), etc: class_modes_per_decade = 20
|
||
Example 1 |
Use \(50\) modes per decade around \(k = 10^{-4}\,\text{Mpc}^{-1}\) and \(10\) modes per decade around \(k = 10^1\,\text{Mpc}^{-1}\), with a running number per decade in between found through logarithmic interpolation (resulting in e.g. \(42\) modes per decade around \(k = 10^{-3}\,\text{Mpc}^{-1}\)): class_modes_per_decade = {
1e-4/Mpc: 50,
1e+1/Mpc: 10,
}
|