Creating Initial Conditions

Writing datasets that are valid for consumption for cosmological codes can be difficult, especially when considering how to best use units. SWIFT uses a different set of internal units (specified in your parameter file) that does not necessarily need to be the same set of units that initial conditions are specified in. Nevertheless, it is important to ensure that units in the initial conditions are all consistent with each other. To facilitate this, we use cosmo_array data. The below example generates randomly placed gas particles with uniform densities.

The functionality to create initial conditions is available through the swiftsimio.snapshot_writer sub-module, and the top-level Writer class.

Warning

The properties that swiftsimio requires in the initial conditions are the only ones that are actually read by SWIFT; other fields will be left un-read and as such cannot be included in initial conditions files using the Writer. Any additional attributes set will be silently ignored.

Warning

You need to be careful that your choice of unit system does not allow values over 2^31, i.e. you need to ensure that your provided values (with units) when written to the file are safe to be interpreted as (single-precision) floats. The only exception to this is coordinates which are stored in double precision.

Example

import numpy as np
import unyt as u
from swiftsimio import Writer, cosmo_array
from swiftsimio.metadata.writer.unit_systems import cosmo_unit_system

# number of gas particles
n_p = 1000
# scale factor of 1.0
a = 1.0
# Box is 100 Mpc
lbox = 100
boxsize = cosmo_array(
     [lbox, lbox, lbox],
     u.Mpc,
     comoving=True,
     scale_factor=a,
     scale_exponent=1,
)

# Create the Writer object. cosmo_unit_system corresponds to default Gadget-like units
# of 10^10 Msun, Mpc, and km/s
w = Writer(unit_system=cosmo_unit_system, boxsize=boxsize, scale_factor=a)

# Randomly spaced coordinates from 0 to lbox Mpc in each direction
w.gas.coordinates = cosmo_array(
    np.random.rand(n_p, 3) * lbox,
    u.Mpc,
    comoving=True,
    scale_factor=w.scale_factor,
    scale_exponent=1,
)

# Random velocities from 0 to 1 km/s
w.gas.velocities = cosmo_array(
    np.random.rand(n_p, 3),
    u.km / u.s,
    comoving=True,
    scale_factor=w.scale_factor,
    scale_exponent=1,
)

# Generate uniform masses as 10^6 solar masses for each particle
w.gas.masses = cosmo_array(
    np.ones(n_p, dtype=float) * 1e6,
    u.solMass,
    comoving=True,
    scale_factor=w.scale_factor,
    scale_exponent=0,
)

# Generate internal energy corresponding to 10^4 K
w.gas.internal_energy = cosmo_array(
    np.ones(n_p, dtype=float) * 1e4 / 1e6,
    u.kb * u.K / u.solMass,
    comoving=True,
    scale_factor=w.scale_factor,
    scale_exponent=-2,
)

# Generate initial guess for smoothing lengths based on mean inter-particle spacing
w.gas.generate_smoothing_lengths()

# w.gas.particle_ids can optionally be set, otherwise they are auto-generated

# write the initial conditions out to a file
w.write("ics.hdf5")

Then, running h5glance (pip install h5glance) on the resulting ics.hdf5 produces:

ics.hdf5
├Header (9 attributes)
├PartType0
│ ├Coordinates       [float64: 1000 × 3] (9 attributes) ├InternalEnergy    [float64: 1000] (9 attributes) ├Masses            [float64: 1000] (9 attributes) ├ParticleIDs       [int64: 1000] (9 attributes) ├SmoothingLengths  [float64: 1000] (9 attributes) └Velocities        [float64: 1000 × 3] (9 attributes)
└Units (5 attributes)