Read Snapshot Data

Reading the header

Reading the header block of the simulation can be done by using:

 h = read_header(filename::String)

Where h is the returned header object:

mutable struct Header
    npart::Vector{Int32}                # an array of particle numbers per type in this snapshot
    massarr::Vector{Float64}            # an array of particle masses per type in this snapshot - if zero: MASS block present
    time::Float64                       # time / scale factor of the simulation
    z::Float64                          # redshift of the simulation
    flag_sfr::Int32                     # 1 if simulation was run with star formation, else 0
    flag_feedback::Int32                # 1 if simulation was run with stellar feedback, else 0
    nall::Vector{UInt32}                # total number of particles in the simulation
    flag_cooling::Int32                 # 1 if simulation was run with cooling, else 0
    num_files::Int32                    # number of snapshots over which the simulation is distributed
    boxsize::Float64                    # total size of the simulation box
    omega_0::Float64                    # Omega matter
    omega_l::Float64                    # Omega dark enery
    h0::Float64                         # little h
    flag_stellarage::Int32              # 1 if simulation was run with stellar age, else 0
    flag_metals::Int32                  # 1 if simulation was run with metals, else 0
    npartTotalHighWord::Vector{UInt32}  # weird
    flag_entropy_instead_u::Int32       # 1 if snapshot U field contains entropy instead of internal energy, else 0
    flag_doubleprecision::Int32         # 1 if snapshot is in double precision, else 0
    flag_ic_info::Int32                 
    lpt_scalingfactor::Float32
    fill::Vector{Int32}                 # the HEAD block needs to be filled with zeros to have a size of 256 bytes
end

This is equivalent to:

 h = head_to_obj(filename::String)

If you want to read the header information into a dictionary you can use:

 h = head_to_dict(filename::String)

Reading a snapshot

Full snapshot

If you want to read a simulation snapshot into memory with GadJet.jl, it’s as easy as this:

    data = read_snap(filename)

This will return a dictionary with the header information in data["Header"] and the blocks sorted by particle type.

As an example, this is how you would access the positions of the gas particles:

    data["Parttype0"]["POS"]

Specific blocks

Reading specific blocks only works with Format 2 at the moment.

If you only want to read a specific block for a single particle type, e.g. positions of gas particles, you can use the function with a specified blockname and particle type like so:

    pos = read_snap(filename, "POS", 0)

This will return an array of the datatype of your simulation, usually Float32.

If the snapshot has no info block this will fail unfortunately.

You can still read the specific block by supplying a hand-constructed Info_Line object:

mutable struct Info_Line
    block_name::String              # name of the data block, e.g. "POS"
    data_type::DataType             # datatype of the block, e.g. Float32 for single precision, Float64 for double
    n_dim::Int32                    # number of dimensions of the block, usually 1 or 3
    is_present::Vector{Int32}       # array of flags for which particle type this block is present,
                                    # e.g. gas only:  [ 1, 0, 0, 0, 0, 0 ]
                                    # e.g. gas + BHs: [ 1, 0, 0, 0, 0, 1 ]
end

and passing that to the function read_block_by_name:

    pos = read_block_by_name(filename, "POS", info=pos_info, parttype=0)

where pos_info is a Info_Line object.

read_snap is used mainly as a wrapper function to call read_block_by_name, in case you were wondering about the function name change.

I will collect some example Info_Line objects in a later release to be able to read some common blocks even without a info block.

Getting snapshot infos

If you have a Format 2 snapshot and just want to know what blocks the snapshot contains you can use the function

    print_blocks(filename)

to get an output of all block names.

If your simulation contains an INFO block you can read the info lines into Info_Line object like so:

    info = read_info(filename, verbose=true)

This will return an Array of Info_Line objects. The optional keyword verbose additionally gives the same functionality as print_blocks and prints the names to the console.

Large Simulations

For large simulations Gadget distributes snapshots over multiple files. These files contain particles associated with specific Peano-Hilbert keys.

To get all particles within a subvolume of the simulation you can use the functions read_particles_in_box(...) or read_particles_in_volume(...).

read_particles_in_box(...) takes a box defined by a lower-left corner and an upper-right corner, constructs the peano hilbert keys, selects the relevant files and reads the particles from these files into a dictionary.

function read_particles_in_box(filename::String, blocks::Vector{String},
                               corner_lowerleft,
                               corner_upperright;
                               parttype::Int=0,
                               verbose::Bool=true)

            (...)

end

You can define an array of blocks you want to read, these will be read in parallel with simple multi-threading.

read_particles_in_volume(...) is a simple wrapper around read_particles_in_box(...), where you can define a central position and a radius around it and it will construct the box containing that sphere for you and read all particles in it.

function read_particles_in_volume(filename::String, blocks::Vector{String},
                                  center_pos::Vector{AbstractFloat},
                                  radius::AbstractFloat;
                                  parttype::Int=0,
                                  verbose::Bool=true)

            (...)
end

In both functions parttype defines the particle type to be read, as in the previous read functions and verbose gives console output.

Filename

With the snapshots being distributed over multiple filenames you need to be careful with that keyword. In this case filename refers to the base-name. Assuming you want to read snapshot 140, which is in the snapshot directory 140 the filename is

filename = "path/to/your/snapshot/directories/snapdir_140/snap_140"

GadJet will then automatically loop through the sub-snapshots which end in “.0”, “.1”, … , “.N”.

Example

If you want to, e.g. read positions, velocities, masses, density and hsml for all gas particles within the virial radius of the most massive halo of a simulation you can do this as follows.

Assuming pos_halo is the position of the center of mass of the halo and r_vir is its virial radius you read the data with

blocks = ["POS", "VEL", "MASS", "RHO", "HSML"]

data   = read_particles_in_volume(filename, blocks, pos_halo, r_vir,
                                  parttype=0,
                                  verbose=true)

This will return a dictionary with the blocks as keys and containing the arrays for the particles.

data["POS"]  # array of positions
data["RHO"]  # array of densities
(...)

Read Subfind Data

Reading the header

Similarly to the normal snapshot you can read the header of the subfind output into a SubfindHeader object

struct SubfindHeader
    nhalos::Int32                       # number of halos in the output file
    nsubhalos::Int32                    # number of subhalos in the output file
    nfof::Int32                         # number of particles in the FoF
    ngroups::Int32                      # number of large groups in the output file
    time::Float64                       # time / scale factor of the simulation
    z::Float64                          # redshift of the simulation
    tothalos::UInt32                    # total number of halos over all output files
    totsubhalos::UInt32                 # total number of subhalos over all output files
    totfof::UInt32                      # total number of particles in the FoF
    totgroups::UInt32                   # total number of large groups over all output files
    num_colors::Int32                   # number of colors
    boxsize::Float64                    # total size of the simulation box
    omega_0::Float64                    # Omega matter
    omega_l::Float64                    # Omega dark enery
    h0::Float64                         # little h
    flag_doubleprecision::Int32         # 1 if snapshot is in double precision, else 0
    flag_ic_info::Int32
end

using

h = read_subfind_header(filename::String)

Reading the subfind files

If you compiled Gadget with WRITE_SUB_IN_SNAP_FORMAT you can read the subfind output like you would a normal snapshot, with any of the above methods. For convenience you can also use a helper function provided by GadJet. Since each of the blocks is only relevant for either halos, subhalos, Fof or large groups you don’t need to define a particly type, aka halo type in this case.

So in order to read the virial radius of the halos in a file you can simply use

R_vir = read_subfind(filename, "RVIR")