masterdesky

Installing and running GADGET-4 on Linux

The GADGET-4 (GAlaxies with Dark matter and Gas intEracT - 4) is the fourth iteration of the gravitational N-body and smoothed-particle hydrodynamics (SPH) simulation code written by Volker Springel and was released in 2020. While GADGET-3 never made it to have a public release, GADGET-4 is the next publicly available version of the suite after GADGET-2 from 2005. This tutorial covers how to install GADGET-4 and run a simulation with it on a Linux system.

GADGET-4 is (unsurprisingly) similar to GADGET-2 in many aspects, which I already had a tutorial on how to install and run. Its main purpose, software design and structure, as well as its usage are very similar to its predecessor. GADGET-4 realizes a hybrid cosmological N-body and hydrodynamics simulation that can be used to study the formation and evolution of galaxies and large-scale structures in the Universe. The code is written in ISO C++, although inherits many code segments and patterns from earlier GADGET versions written in C.

In this guide I will show how to correctly install GADGET-4 on a Linux system, and how to run a simple example simulation with it. As simulations depend on the set of compile-time options and the initial conditions, this tutorial alone cannot serve as a comprehensive guide to all possible simulation setups as-is. However, I will cover the common steps that you will encounter during the installation and running of GADGET-4.

Dependency software and libraries

GADGET-4 is built on top of the same non-standard software libraries and tools as GADGET-2 does. To successfully compile GADGET-4, you need to obtain, compile and then link these libraries appropriately during the building process. The following list contains all necessary software that you will need to download and install before trying to install GADGET-4 itself:

  1. Any MPI implementation. I recommend one of the following:
    • MPICH 4.1 (latest tested version at the time of writing)
    • OpenMPI 4.1.5 (latest tested version at the time of writing)
  2. GSL 2.8 (latest tested version at the time of writing)
  3. FFTW 3.3.10 (latest tested 3.x version at the time of writing)
  4. HDF5 1.14.4 (latest tested version at the time of writing)
  5. hwloc 2.10.0 (latest tested version at the time of writing)

You can download all of these files by clicking on the links above, or by using e.g. the wget or curl commands in the terminal. (Or you can just search for them yourself on the internet, of course.) When choosing an MPI library, it should not really matter which one you go with. Moreover, on computation servers, usually one or both of them are already installed on the system. In this tutorial I am going to use OpenMPI, but the steps should be identical in case of using MPICH too. Using wget you can download all of them at once:

$ wget https://download.open-mpi.org/release/open-mpi/v4.1/openmpi-4.1.5.tar.gz
$ wget https://ftp.gnu.org/gnu/gsl/gsl-2.8.tar.gz
$ wget http://www.fftw.org/fftw-3.3.10.tar.gz
$ wget https://github.com/HDFGroup/hdf5/releases/download/hdf5_1.14.4.3/hdf5-1.14.4-3.tar.gz
$ wget https://download.open-mpi.org/release/hwloc/v2.10/hwloc-2.10.0.tar.gz
Links on the internet can and do broke sometimes. Although the developers of these libraries usually provide a stable URL for all prior versions of their software in an official repository, it is possible that these links above are not working. (E.g. HDF5 had a huge makeover in 2023-2024, during which their central repository went offline.) You can always check the official website of the software you want to download for the desired version and the correct URL.

If you downloaded all tarballs from the URLs above, now you can extract, compile and install them. The installation of these libraries is a standard procedure that you can find in this tutorial.

The installation of most of the software above is straightforward. You can follow the steps in the tutorial to install them. However, in case of FFTW 3.x, you have to use the --enable-mpi --enable-float --enable-threads flags during the configuration step! More info about them and FFTW in the tutorial.

Alternatively, on Debian-based systems like Ubuntu, if you have root access to the machine, you can install the dependencies using the apt package manager. However, the versions of these packages might be outdated, as well as elevated permissions on a machine are not available to an end user in most circumstances, so it is generally recommended to install them from source. If you still want to install them using apt, you can do it with the following command:

$ sudo apt install openmpi-bin libopenmpi-dev libhdf5-dev hwloc libgsl-dev libfftw3-dev

After you installed all dependencies, you can proceed to the next section.

Installing GADGET-4

The installation of GADGET-4 is somewhat more complex that GADGET-2, but it is still a straightforward process. The main steps are the configuration of the compile-time flags in Config.sh, correctly linking the necessary dependencies in multiple other configuration files, and finally building GADGET-4 with make. Download GADGET-4 from the official repository to e.g. a dedicated apps folder in your home directory, but you can download it to wherever you want it:

$ git clone https://gitlab.mpcdf.mpg.de/vrs/gadget4.git ~/apps/GADGET-4
$ cd ~/apps/GADGET-4

For convenience and clarity, somewhere between the release of GADGET-2 and GADGET-4, the Makefile of GADGET-2 was separated and organized into multiple files, which I will showcase in the following sections. The very first thing you have to do is copying the Template-Config.sh and Template-Makefile.systype files and renaming these copies in the root directory of GADGET-4:

$ cp Template-Config.sh Config.sh  # although we will overwrite this in this guide
$ cp Template-Makefile.systype Makefile.systype

The Config.sh file contains all the compile-time options of GADGET-4 that can tune the behavior of the code for all simulations performed with it. On the other hand, the Makefile.systype file should be used in tandem with the contents of the buildsystem directory and the Makefile in the root directory of GADGET-4 to define the appropriate compiler and linker flags for your system.

System-specific settings

First focus on the system-specific setups as those only depend on your system, and generally independent of the simulations you want to run. The goal is to define the necessary build flags and link the dependencies correctly for the Makefile of GADGET-4. There are four files you have to pay attention to: Makefile.systype, buildsystem/Makefile.comp.*, buildsystem/Makefile.path.* and the actual Makefile.

Makefile.systype

The Makefile.systype file is a simple file, where the only thing you have to do is to define the system type of your machine. This is a short string that is used to indicate for the Makefile, which system-specific configuration file to use from the buildsystem directory. There is already a number of system types defined in it (along with their configuration files and setting in the buildsystem folder and in the Makefile) that corresponds to some well-known supercomputers in the world, where GADGET was commonly used. To create a custom system type, just define a new string (e.g mycomputer as in this example) and comment out the others in the Makefile.systype file:

# Select Target Computer
#
# Please copy this file to Makefile.systype and uncomment your
# system. Don't commit changes to this file unless you add support for
# a new system.

SYSTYPE="mycomputer"
#SYSTYPE="Generic-gcc"
#SYSTYPE="Generic-intel"
#[... other entries commented out ...]

buildsystem files

The buildsystem directory contains all the system-specific configuration files and some related scripts. For supported systems in the Makefile.systype file, there is also a corresponding Makefile.comp.* and Makefile.path.* file in the buildsystem directory. The Makefile.comp.* files contain the compiler flags that are used to build GADGET-4, while the Makefile.path.* files contain the linker flags with the correct paths to the necessary libraries (GSL, FFTW, etc.) and include files that are used during the build process.

Because we defined a custom system in the Makefile.systype file in the previous step, now we have to define new or use existing Makefile.comp.* and Makefile.path.* files in the buildsystem directory.

While the default Makefile.comp.gcc file is a good starting point for most cases, a new Makefile.path.* file should created to correctly link the dependencies installed on the machine. In this guide I will use the Makefile.comp.gcc file as-is, but I will create a new Makefile.path.mycomputer file in the buildsystem directory to link the dependencies correctly.

  1. If you followed the tutorial on the installation of dependencies from source and installed all of them to their own separate folders in e.g. the directory /home/username/opt, then the setup of the Makefile.path.mycomputer file should look like this:

     GSL_INCL   = -I/home/username/opt/gsl/include
     GSL_LIBS   = -L/home/username/opt/gsl/lib
     FFTW_INCL  = -I/home/username/opt/fftw/include
     FFTW_LIBS  = -L/home/username/opt/fftw/lib -lfftw3
     HDF5_INCL  = -I/home/username/opt/hdf5/include
     HDF5_LIBS  = -L/home/username/opt/hdf5/lib -lhdf5
     HWLOC_INCL = -I/home/username/opt/hwloc/include
     HWLOC_LIBS = -L/home/username/opt/hwloc/lib
    

    Evidently, replace username with your own username on the machine. Variables ending in _INCL define the include paths of the libraries, while variables with the _LIBS suffix define the linker flags and the paths to the libraries themselves. The -lfftw3 and -lhdf5 flags are necessary to link the FFTW and HDF5 libraries, respectively.

  2. If you have root access to the machine you are using and you installed the dependencies using apt on Debian-based system (like Ubuntu) and the dependencies are installed to the default system directories, then the Makefile.path.mycomputer file should look like this:

     GSL_INCL   = -I/usr/include/gsl
     GSL_LIBS   = -L/usr/lib/x86_64-linux-gnu
     FFTW_INCL  = -I/usr/include
     FFTW_LIBS  = -L/usr/lib/x86_64-linux-gnu -lfftw3
     HDF5_INCL  = -I/usr/include/hdf5/serial
     HDF5_LIBS  = -L/usr/lib/x86_64-linux-gnu/hdf5/serial -lhdf5
     HWLOC_INCL = -I/usr/include/hwloc
     HWLOC_LIBS = -L/usr/lib/x86_64-linux-gnu/hwloc
    

Makefile

The Makefile in the root directory of GADGET-4 is the main file that is used to build the code. It is the place, where every system-specific setup from the other files are linked together. There are two sections in this file that requires your attention: the system definitions, referenced by the SYSTYPE variable from Makefile.systype and the Python interpreter.

Latter is just a simple variable that defines the Python executable used during the compilation of GADGET-4. The default value of this variable is python. Although the executable of Python 3.x versions is called python3, this is mapped to python on many Linux distributions and systems. However, this is not always the case and python3 should be explicitly called here. You can change this in the Makefile file on line 97, if necessary:

PYTHON   = python  # Could be python3 on some systems

In the other part, the corresponding buildsystem files (one with the compiler flags and one with the linker flags for the dependencies) are linked to the predefined system from Makefile.systype. Since we defined an entirely new system called mycomputer in Makefile.systype, we have to tell the Makefile which buildsystem files correspond to this. Remember, we only created a new file for the linker flags (Makefile.path.mycomputer) and used the default one for the compiler flags (Makefile.comp.gcc). To include the new system in the Makefile, you have to add the following to the list of system definitions:

##########################
#define available Systems#
##########################
ifeq ($(SYSTYPE),"mycomputer")
include buildsystem/Makefile.path.mycomputer
include buildsystem/Makefile.comp.gcc
endif

ifeq ($(SYSTYPE),"Generic-gcc")
# [... other system definitions ...]

Compile-time options

The Config.sh file contains all the compile-time options of GADGET-4 that can tune the general behavior of the code for all simulations performed with it. These include options like defining the boundary conditions, selecting which physical effects to simulate or consider, miscellaneous technical and debug options, etc. The file is well-documented, and you can find all possible options and their descriptions in it.

GADGET-4 offers a plethora of options that can be freely combined to create a custom simulation setup for a wide range of astrophysical problems. One always has to consider what kind of simulation is going to be run with GADGET-4, and set these options accordingly. If a new type of simulation have to be run, then the options need to be adjusted and GADGET-4 has to be recompiled!

In this guide, I will show how to set up one of the example simulations included in the examples directory with GADGET-4. For convenience, I selected the legacy galaxy collision simulation (examples/G2-galaxy), as it is much less resource intensive than the more robust example (CollidingGalaxiesSFR) included in GADGET-4. All example simulations have their own already prepared Config.sh file in their respective directories, and you can copy them to the root directory of GADGET-4 to compile the code for that specific simulation. Here, just copy the Config.sh file from the examples/G2-galaxy directory to the root directory of GADGET-4:

$ cd ~/apps/GADGET-4
$ cp ./examples/G2-galaxy/Config.sh ./

Building GADGET-4

With the correct buildsystem files, Makefile.systype, Makefile and Config.sh in place, GADGET-4 can be built with make command from the same directory where the Makefile is located. The output of the make command can be redirected to a file, so you can check for any errors or warnings that might occur during the build process. It can be also sped up by utilizing more CPU cores with the -jN option, where N is the desired number of cores. All of these can be done with the following command:

$ cd ~/apps/GADGET-4
$ make -j4 2>&1 | tee m.out

If everything went as well, then this command will automatically create an executable called Gadget4 in this same directory, which can be finally used to run simulations.

Running GADGET-4 simulations

GADGET simulations require at least three basic components:

  1. The executable compiled from the source code with a correct Makefile and the corresponding Config.sh file.
  2. An initial conditions (IC) file that contains the initial positions, velocities and other relevant attributes of the simulated particles.
  3. A parameter file that contains the necessary run-time parameters of the simulation.
$ mkdir -p ~/data/simulations/galaxy

Just for convenience, I copy the compiled executable to this directory. Besides that, I will also copy the parameter file into the same directory; we will need to edit this later, so we can preserve the content of the original file this way.

$ cp ~/apps/GADGET-4/Gadget4 ~/data/simulations/galaxy/
$ cp ~/apps/GADGET-4/examples/G2-galaxy/param.txt ~/data/simulations/galaxy/

Initial conditions

Creating physically meaningful and correct initial conditions for an astrophysical simulation is a complex task that requires its own set of methodologies and thus usually separate software tools. IC creation is out of the scope of this tutorial, however, all examples in GADGET-4 come with their own IC files that can be used to run simulations. They can be downloaded from the official repository of GADGET-4 by clicking this link or by using the commands below. For the sake of this tutorial I will put these files into the ~/data directory created earlier, but of course, you can put these files anywhere you want:

$ cd ~/data
$ curl -O https://wwwmpa.mpa-garching.mpg.de/gadget4/example_ics.tar
$ tar -xvf example_ics.tar && rm example_ics.tar

This will result us in a new directory called ExampleICs in the ~/data folder with all the IC files of the example simulations. The IC file for the galaxy collision simulation is called galaxy_littleendian.dat, which we will use later.

Parameter file

The parameter file is the single input file of the Gadget4 executable that contains all the necessary run-time parameters of the simulation, like the location of the IC file and the output directory, values of main cosmological parameters, integration time step and smoothing lengths, etc. Since in the GADGET-2 tutorial I covered the setup and execution of the same example simulation, this section will be close to identical to that.

Before running the simulation, there are some parameters which needs to be altered first in the copied simulations/galaxy/params.txt file. The first two lines after the initial comment line should be changed to contain the absolute paths of the IC input file (InitCondFile) and the output directory (OutputDir). In this example case these are the following:

%----  Relevant files
InitCondFile       /home/username/data/ExampleICs/galaxy_littleendian.dat
OutputDir          /home/username/data/simulations/galaxy/output

Note that I defined an additional output folder in the ~/data/simulations/galaxy directory to store the output of the simulation. This is a good practice, as the simulation will create a lot of files during the run, and it is better to keep them in a separate folder.

As any other computer simulation, GADGET-4 works by reading in a set of ICs and evolving this state in time. During a run at given time intervals, GADGET-4 saves a ‘snapshot’ of the current state of the system that contains the positions, velocities and other attributes of the simulated particles. GADGET-4 supports multiple different file formats, name its own Gadget-I and II formats and the more modern HDF5 format.

I recommend using HDF5 in general, as it is a much more modern, versatile and most importantly maintained file format and, which is much easier to handle with e.g. Python. To change the output format, you will need to find the %---- File formats block in the parameter file and change the SnapFormat value to 3. This will tell GADGET-4 to save the snapshot files in HDF5 format. Since the prepared example IC is in Gadget format, the ICFormat value should be set to 1 to indicate this. The final %---- File formats block in the parameter file should look like this:

%---- File formats
ICFormat           1
SnapFormat         3

The last parameters you might want to change are the ones that control the length and the output frequency of the simulation. The meaning of space and time in GADGET and its derivatives is not physical, at least not directly. When we mention the unit of distance, velocity, mass or time in this context, we actually mean simulation units. When an IC is created for a simulation, one chooses some unit length, unit velocity and unit mass to define the physical meaning of the numerical values in the IC file. In GADGET, the unit time is derived from these units as UnitTime_in_s = UnitLength_in_cm / UnitVelocity_in_cm_per_s. Unit length, velocity and mass is controlled in the parameter file under the System of units section. Considering the galaxy collision example, the unit length UnitLength_in_cm is set to 3.085678e21, which corresponds to $1 \mathrm{kpc}$. Similarly, the unit velocity UnitVelocity_in_cm_per_s is set to 1.0e5, which corresponds to $1 \mathrm{km/s}$. This gives us a unit time UnitTime_in_s of 3.085678e16, which corresponds to $\approx 0.9785 \mathrm{Gyr}$.

GADGET-4 will create a snapshot at every time interval defined by the TimeBetSnapshot parameter. The shorter this interval is, the more frequently the current state of the simulation will be saved to the disk, resulting in a more detailed “timeline” at the cost of using more disk space. This can be edited in the Output freqency block in the line

%---- Output frequency and output paramaters
...
TimeBetSnapshot    0.01
...

which I set to $0.01$ in case of the simulation you can see at the bottom of the page. Given that a unit time is $\approx 0.9785 \mathrm{Gyr}$, this means that the simulation will be saved every $\approx 9.785 \mathrm{Myr}$!

Besides that, I also increased the TimeMax value (which defines the end time of the simulation) from 3.0 to 8.0 to make the simulation cover a longer time period:

%---- Caracteristics of run
TimeBegin          0.0        % Begin of the simulation
TimeMax            8.0        % End of the simulation

This means that the simulation will run for $\approx 8 \mathrm{Gyr}$. Please note that with this configuration, the simulation will write (TimeMax - TimeBegin) / TimeBetSnapshot $=800$ snapshot files to the disk, so first make sure that you have enough space to store them.

Running the simulation

The only remaining step we have to do is to run the simulation. For that, we need to invoke the Gadget4 executable with the parameter file as its only argument. Since we installed OpenMPI, we can run the simulation in parallel on multiple CPU cores using the

$ mpirun -np N <command>

command, where N is the number of threads we want to use. In this example, I am using 16 CPU cores to run the simulation (a number which might not be accessible to you, given your setup). Assuming that the executable is named as Gadget4 and is located in the ~/data/simulations/galaxy directory, as well as the parameter file named param.txt is located in the same directory, the command to run the simulation on e.g. $16$ CPU threads should look like this:

$ mpirun -np 16 ~/data/simulations/galaxy/Gadget4 ~/data/simulations/galaxy/param.txt

Of course, you can name and place these files however and wherever you like, as long as you provide the correct paths, when they are needed (e.g. in the parameter file or in the command above).

After the simulation is finished, you should see a bunch of new files in the output directory. The most important ones are the snapshot files. They will be named as snapshot_XXX.hdf5, where XXX is the index of each snapshot, arranged in a temporal order. Depending on the specific simulation, these files will contain parameters and the state of various ‘particle types’ (e.g. gas, dark matter, stars, etc.) at different times during the simulation. GADGET and similar software utilizes $6$ different particle types. In this particular example simulation, we have dark matter (the galactic halo) particles and particles in the galactic disk, which corresponds to PartType1 and PartType2 in the snapshot files, respectively. These files can be read and analyzed with the help of e.g. the h5py package using Python. You can open these particular galaxy collision snapshots with the following Python code:

import h5py
import numpy as np

def extract_parttype(f, parttype):
    '''
    Extracts the particle IDs, coordinates and velocities of a given
    particle type from a snapshot file.

    Parameters:
    -----------
    f : h5py.File
        The snapshot file opened with h5py.
    parttype : int
        The particle type to extract. 1 for dark matter (halo), 2 for
        disk particles.

    Returns:
    --------
    np.ndarray of shape (N, 7)
        A 2D numpy array with the particle IDs, coordinates and velocities.
    '''
    I = f[f'PartType{parttype}/ParticleIDs'][:]  # Particle IDs
    C = f[f'PartType{parttype}/Coordinates'][:]  # Particle Coordinates
    V = f[f'PartType{parttype}/Velocities'][:]   # Particle Velocities
    return np.hstack((I[:, np.newaxis], C, V))

def open_snapshot(s):
    '''
    Opens a GADGET-4 snapshot file and extracts the dark matter and disk
    particle data from it.

    Parameters:
    -----------
    s : str
        The path to the snapshot file.
    '''
    with h5py.File(s, 'r') as f:
        G_halo = extract_parttype(f, parttype=1)
        G_disk = extract_parttype(f, parttype=2)
        return G_halo, G_disk

You should not forget that coordinates and velocities are in the simulation units, so you have to convert them to physical units using the unit values defined in the parameter file! After that, the data can be visualized with any library or tool one prefers.

The final animation I created with matplotlib from the simulation I ran is shown below. The animation shows the evolution of the galaxy collision simulation over time, where the dark matter halo is shown in grey and the disk particles are shown in black. The second section of the video zooms into the center of the collision, where the particles are shown in red and blue, representing the two galaxies that are colliding. The animation is created by plotting the particle positions in the $X$-$Y$, $X$-$Z$ and $Y$-$Z$ planes at each time step. The animation can be found on YouTube: