diff --git a/examples/IsolatedGalaxy/IsolatedGalaxy_multi_component/makeDisk.py b/examples/IsolatedGalaxy/IsolatedGalaxy_multi_component/makeDisk.py
index cec23105e59edc4e1a6c551a80b722b4eb580d05..70f5c2d9c49293210f185b936b4d264ba82fd462 100755
--- a/examples/IsolatedGalaxy/IsolatedGalaxy_multi_component/makeDisk.py
+++ b/examples/IsolatedGalaxy/IsolatedGalaxy_multi_component/makeDisk.py
@@ -588,14 +588,14 @@ nb.rename("galaxy_multi_component.hdf5")
 nb.write()
 
 #%%
-#Add the StellarParticleType attribute to the dataset
+# Add the StellarParticleType attribute to the dataset
 import h5py as h5
 import numpy as np
 
 nb_star = nb.select("stars")
 N_star = np.sum(nb_star.npart)
-star_tpe = 2 # Single population stars
-star_type = np.ones(N_star)*star_tpe
+star_tpe = 2  # Single population stars
+star_type = np.ones(N_star) * star_tpe
 
-with  h5.File("galaxy_multi_component.hdf5", "r+") as f:
+with h5.File("galaxy_multi_component.hdf5", "r+") as f:
     f["PartType4"].create_dataset("StellarParticleType", data=star_type)
diff --git a/examples/SinkParticles/HomogeneousBoxSinkParticles/README b/examples/SinkParticles/HomogeneousBoxSinkParticles/README
new file mode 100644
index 0000000000000000000000000000000000000000..8669089494c529ed3e2fbe4c9ebc8c084574eeea
--- /dev/null
+++ b/examples/SinkParticles/HomogeneousBoxSinkParticles/README
@@ -0,0 +1,24 @@
+# Intro
+This example is a modified version of the HomogeneousBox in SWIFT that allows to add sink particles to the box. By default, there is no gravity.
+
+The default level is 5 (N_particle = 2^(3*level)). It is quick. If you want to try the example with higher levels, we recommend using HPC facilities.
+
+*This example is mainly used for sink MPI debugging.*
+
+# Configure
+
+To run this example with GEAR model,
+
+./configure --with-chemistry=GEAR_10 --with-cooling=grackle_0 --with-stars=GEAR --with-star-formation=GEAR --with-feedback=GEAR --with-sink=GEAR --with-kernel=wendland-C2 --with-grackle=path/to/grackle --enable-debug --enable-debugging-checks
+
+and then
+
+make -j
+
+# ICs
+The run.sh script calls `makeIC.py' script with default values. You can experiment by changing the ICs. Run `python3 makeIC.py --help` to get the list of parameters.
+
+# Run
+Type `run.sh` (or `n_ranks=4 mpi_run.sh`), and let's go!
+
+You can provide parameters to the running scripts, have a look inside them.
diff --git a/examples/SinkParticles/HomogeneousBoxSinkParticles/getChemistryTable.sh b/examples/SinkParticles/HomogeneousBoxSinkParticles/getChemistryTable.sh
new file mode 100755
index 0000000000000000000000000000000000000000..b10fd23964158ee7a38d352dbd0ddd9beb7bdd77
--- /dev/null
+++ b/examples/SinkParticles/HomogeneousBoxSinkParticles/getChemistryTable.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+wget http://virgodb.cosma.dur.ac.uk/swift-webstorage/FeedbackTables/POPIIsw.h5
diff --git a/examples/SinkParticles/HomogeneousBoxSinkParticles/getGrackleCoolingTable.sh b/examples/SinkParticles/HomogeneousBoxSinkParticles/getGrackleCoolingTable.sh
new file mode 100755
index 0000000000000000000000000000000000000000..e3eb106240709c80151a48625567d2cd78e5f568
--- /dev/null
+++ b/examples/SinkParticles/HomogeneousBoxSinkParticles/getGrackleCoolingTable.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+wget http://virgodb.cosma.dur.ac.uk/swift-webstorage/CoolingTables/CloudyData_UVB=HM2012.h5
diff --git a/examples/SinkParticles/HomogeneousBoxSinkParticles/makeIC.py b/examples/SinkParticles/HomogeneousBoxSinkParticles/makeIC.py
new file mode 100755
index 0000000000000000000000000000000000000000..6ad3be507b4fd12d8bef3c0af4a1b674cb950a27
--- /dev/null
+++ b/examples/SinkParticles/HomogeneousBoxSinkParticles/makeIC.py
@@ -0,0 +1,267 @@
+################################################################################
+# This file is part of SWIFT.
+# Copyright (c) 2022 Yves Revaz (yves.revaz@epfl.ch)
+#                         2024 Darwin Roduit (darwin.roduit@epfl.ch)
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+################################################################################
+
+import h5py
+import numpy as np
+import argparse
+from astropy import units
+from astropy import constants
+
+
+class store_as_array(argparse._StoreAction):
+    """Provides numpy array as argparse arguments."""
+
+    def __call__(self, parser, namespace, values, option_string=None):
+        values = np.array(values)
+        return super().__call__(parser, namespace, values, option_string)
+
+
+def parse_options():
+
+    usage = "usage: %prog [options] file"
+    parser = argparse.ArgumentParser(description=usage)
+
+    parser.add_argument(
+        "--lJ",
+        action="store",
+        dest="lJ",
+        type=float,
+        default=0.250,
+        help="Jeans wavelength in box size unit",
+    )
+
+    parser.add_argument(
+        "--rho",
+        action="store",
+        dest="rho",
+        type=float,
+        default=0.1,
+        help="Mean gas density in atom/cm3",
+    )
+
+    parser.add_argument(
+        "--mass",
+        action="store",
+        dest="mass",
+        type=float,
+        default=50,
+        help="Gas particle mass in solar mass",
+    )
+
+    parser.add_argument(
+        "--level",
+        action="store",
+        dest="level",
+        type=int,
+        default=5,
+        help="Resolution level: N = (2**l)**3",
+    )
+
+    parser.add_argument(
+        "--sink_mass",
+        action="store",
+        type=float,
+        default=50,
+        help="Sink particles mass in solar mass",
+    )
+
+    parser.add_argument(
+        "--sinks_vel",
+        action=store_as_array,
+        nargs=3,
+        type=float,
+        default=np.array([10, 0, 0]),
+        help="Sink particle velocity. All sinks get the same velocity",
+    )
+
+    parser.add_argument(
+        "--sink_pos",
+        action=store_as_array,
+        nargs=3,
+        type=float,
+        default=np.array([0, 0, 0]),
+        help="Sink particle position. Only use it to place one sink particle.",
+    )
+
+    parser.add_argument(
+        "--n_sink",
+        action="store",
+        type=int,
+        default=10,
+        help="Number of sink particles in the box",
+    )
+
+    parser.add_argument(
+        "-o",
+        action="store",
+        dest="outputfilename",
+        type=str,
+        default="box.hdf5",
+        help="output filename",
+    )
+
+    options = parser.parse_args()
+    return options
+
+
+########################################
+# main
+########################################
+
+opt = parse_options()
+
+# define standard units
+UnitMass_in_cgs = 1.988409870698051e43  # 10^10 M_sun in grams
+UnitLength_in_cgs = 3.0856775814913673e21  # kpc in centimeters
+UnitVelocity_in_cgs = 1e5  # km/s in centimeters per second
+UnitCurrent_in_cgs = 1  # Amperes
+UnitTemp_in_cgs = 1  # Kelvin
+UnitTime_in_cgs = UnitLength_in_cgs / UnitVelocity_in_cgs
+
+UnitMass = UnitMass_in_cgs * units.g
+UnitLength = UnitLength_in_cgs * units.cm
+UnitTime = UnitTime_in_cgs * units.s
+UnitVelocity = UnitVelocity_in_cgs * units.cm / units.s
+
+np.random.seed(1)
+
+# Number of particles
+N = (2 ** opt.level) ** 3  # number of particles
+
+# Mean density
+rho = opt.rho  # atom/cc
+rho = rho * constants.m_p / units.cm ** 3
+
+# Gas particle mass
+m = opt.mass  # in solar mass
+m = m * units.Msun
+
+# Gas mass in the box
+M = N * m
+
+# Size of the box
+L = (M / rho) ** (1 / 3.0)
+
+# Jeans wavelength in box size unit
+lJ = opt.lJ
+lJ = lJ * L
+
+# Gravitational constant
+G = constants.G
+
+# Jeans wave number
+kJ = 2 * np.pi / lJ
+# Velocity dispersion
+sigma = np.sqrt(4 * np.pi * G * rho) / kJ
+
+
+print("Boxsize                               : {}".format(L.to(units.kpc)))
+print("Number of particles                   : {}".format(N))
+print("Equivalent velocity dispertion        : {}".format(sigma.to(units.m / units.s)))
+
+# Convert to code units
+m = m.to(UnitMass).value
+L = L.to(UnitLength).value
+rho = rho.to(UnitMass / UnitLength ** 3).value
+sigma = sigma.to(UnitVelocity).value
+
+# Generate the particles
+pos = np.random.random([N, 3]) * np.array([L, L, L])
+vel = np.zeros([N, 3])
+mass = np.ones(N) * m
+u = np.ones(N) * sigma ** 2
+ids = np.arange(N)
+h = np.ones(N) * 3 * L / N ** (1 / 3.0)
+rho = np.ones(N) * rho
+
+print("Inter-particle distance (code unit)   : {}".format(L / N ** (1 / 3.0)))
+
+
+#####################
+# Now, take care of the sink
+#####################
+N_sink = opt.n_sink
+m_sink = opt.sink_mass * units.M_sun
+m_sink = m_sink.to(UnitMass).value  # Convert the sink mass to internal units
+
+
+if N_sink == 1:
+    pos_sink = np.reshape(opt.sinks_vel, (N_sink, 3))
+else:
+    pos_sink = np.random.random([N_sink, 3]) * np.array([L, L, L])
+
+if opt.sinks_vel is not None:
+    vel_sink = np.tile(
+        opt.sinks_vel, (N_sink, 1)
+    )  # Duplicate the velocity for all sinks
+else:
+    np.zeros([N_sink, 3])
+
+mass_sink = np.ones(N_sink) * m_sink
+ids_sink = np.arange(N, N + N_sink)
+
+#####################
+# Finally write the ICs in the file
+#####################
+
+# File
+fileOutput = h5py.File(opt.outputfilename, "w")
+print("{} saved.".format(opt.outputfilename))
+
+# Header
+grp = fileOutput.create_group("/Header")
+grp.attrs["BoxSize"] = [L, L, L]
+grp.attrs["NumPart_Total"] = [N, 0, 0, N_sink, 0, 0]
+grp.attrs["NumPart_Total_HighWord"] = [0, 0, 0, 0, 0, 0]
+grp.attrs["NumPart_ThisFile"] = [N, 0, 0, N_sink, 0, 0]
+grp.attrs["Time"] = 0.0
+grp.attrs["NumFileOutputsPerSnapshot"] = 1
+grp.attrs["MassTable"] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
+grp.attrs["Flag_Entropy_ICs"] = [0, 0, 0, 0, 0, 0]
+grp.attrs["Dimension"] = 3
+
+
+# Units
+grp = fileOutput.create_group("/Units")
+grp.attrs["Unit length in cgs (U_L)"] = UnitLength_in_cgs
+grp.attrs["Unit mass in cgs (U_M)"] = UnitMass_in_cgs
+grp.attrs["Unit time in cgs (U_t)"] = UnitTime_in_cgs
+grp.attrs["Unit current in cgs (U_I)"] = UnitCurrent_in_cgs
+grp.attrs["Unit temperature in cgs (U_T)"] = UnitTemp_in_cgs
+
+
+# Write Gas particle group
+grp = fileOutput.create_group("/PartType0")
+grp.create_dataset("Coordinates", data=pos, dtype="d")
+grp.create_dataset("Velocities", data=vel, dtype="f")
+grp.create_dataset("Masses", data=mass, dtype="f")
+grp.create_dataset("SmoothingLength", data=h, dtype="f")
+grp.create_dataset("InternalEnergy", data=u, dtype="f")
+grp.create_dataset("ParticleIDs", data=ids, dtype="L")
+grp.create_dataset("Densities", data=rho, dtype="f")
+
+
+# Write sink particle group
+grp = fileOutput.create_group("/PartType3")
+grp.create_dataset("Coordinates", data=pos_sink, dtype="d")
+grp.create_dataset("Velocities", data=vel_sink, dtype="f")
+grp.create_dataset("Masses", data=mass_sink, dtype="f")
+grp.create_dataset("ParticleIDs", data=ids_sink, dtype="L")
+fileOutput.close()
diff --git a/examples/SinkParticles/HomogeneousBoxSinkParticles/mpi_run.sh b/examples/SinkParticles/HomogeneousBoxSinkParticles/mpi_run.sh
new file mode 100755
index 0000000000000000000000000000000000000000..8b884691d68c92902a68b62826c4a7dcfaa9dc91
--- /dev/null
+++ b/examples/SinkParticles/HomogeneousBoxSinkParticles/mpi_run.sh
@@ -0,0 +1,51 @@
+#!/bin/bash
+
+# make run.sh fail if a subcommand fails
+set -e
+
+n_ranks=${n_ranks:=2}  #Number of MPI ranks
+n_threads=${n_threads:=1}  #Number of threads to use
+level=${level:=5}  #Number of particles = 2^(3*level)
+jeans_length=${jeans_length:=0.250}  #Jeans wavelenght in unit of the boxsize
+n_sinks=${n_sinks:=10}  #Number of sinks
+
+# Remove the ICs
+if [ -e ICs_homogeneous_box.hdf5 ]
+then
+    rm ICs_homogeneous_box.hdf5
+fi
+
+#Create the ICs if they do not exist
+if [ ! -e ICs_homogeneous_box.hdf5 ]
+then
+    echo "Generating initial conditions to run the example..."
+    python3 makeIC.py --level $level -o ICs_homogeneous_box.hdf5 --lJ $jeans_length --n_sink $n_sinks --sink_pos 0 0 0 --sinks_vel 10 10 0
+fi
+
+# Get the Grackle cooling table
+if [ ! -e CloudyData_UVB=HM2012.h5 ]
+then
+    echo "Fetching the Cloudy tables required by Grackle..."
+    ./getGrackleCoolingTable.sh
+fi
+
+if [ ! -e POPIIsw.h5 ]
+then
+    echo "Fetching the chemistry tables..."
+    ./getChemistryTable.sh
+fi
+
+# Create output directory
+DIR=snap #First test of units conversion
+if [ -d "$DIR" ];
+then
+    echo "$DIR directory exists. Its content will be removed."
+    rm -r $DIR
+else
+    echo "$DIR directory does not exists. It will be created."
+    mkdir $DIR
+fi
+
+printf "Running simulation..."
+
+mpirun -n $n_ranks ../../../swift_mpi --pin --hydro --sinks --stars --external-gravity --feedback --threads=$n_threads --verbose 1 params.yml 2>&1 | tee output.log
diff --git a/examples/SinkParticles/HomogeneousBoxSinkParticles/params.yml b/examples/SinkParticles/HomogeneousBoxSinkParticles/params.yml
new file mode 100755
index 0000000000000000000000000000000000000000..fd7c945e8dadf6ba204f973f60d652981cfa4bee
--- /dev/null
+++ b/examples/SinkParticles/HomogeneousBoxSinkParticles/params.yml
@@ -0,0 +1,101 @@
+# Define the system of units to use internally.
+InternalUnitSystem:
+  UnitMass_in_cgs:     1.988409870698051e+43   # 10^10 solar masses 
+  UnitLength_in_cgs:   3.0856775814913673e+21  # 1 kpc 
+  UnitVelocity_in_cgs: 1e5   # km/s
+  UnitCurrent_in_cgs:  1   # Amperes
+  UnitTemp_in_cgs:     1   # Kelvin
+
+# Parameters for the self-gravity scheme
+Gravity:
+  MAC:                           adaptive  # Choice of mulitpole acceptance criterion: 'adaptive' OR 'geometric'.
+  epsilon_fmm:                   0.001     # Tolerance parameter for the adaptive multipole acceptance criterion.
+  theta_cr:                      0.7       # Opening angle for the purely gemoetric criterion.
+  eta:          0.025               # Constant dimensionless multiplier for time integration.
+  theta:        0.7                 # Opening angle (Multipole acceptance criterion).
+  max_physical_baryon_softening: 0.005  # Physical softening length (in internal units)
+  mesh_side_length:        32
+
+# Parameters governing the time integration (Set dt_min and dt_max to the same value for a fixed time-step run.)
+TimeIntegration:
+  time_begin:        0.    # The starting time of the simulation (in internal units).
+  time_end:          0.282 # The end time of the simulation (in internal units).
+  dt_min:            1e-10 # The minimal time-step size of the simulation (in internal units).
+  dt_max:            2e-2  # The maximal time-step size of the simulation (in internal units).
+
+# Parameters governing the snapshots
+Snapshots:
+  subdir: snap
+  basename:   snapshot      # Common part of the name of output files
+  time_first: 0. #230 Myr # (Optional) Time of the first output if non-cosmological time-integration (in internal units)
+  delta_time: 10e-3        # Time difference between consecutive outputs (in internal units)
+
+Scheduler:
+  cell_extra_gparts: 100      # (Optional) Number of spare sparts per top-level allocated at rebuild time for on-the-fly creation.
+  cell_extra_sinks: 100       # (Optional) Number of spare sparts per top-level allocated at rebuild time for on-the-fly creation.
+  cell_extra_sparts: 100      # (Optional) Number of spare sparts per top-level allocated at rebuild time for on-the-fly creation.
+  max_top_level_cells: 3        #
+
+# Parameters governing the conserved quantities statistics
+Statistics:
+  delta_time:           5e-3     # Time between statistics output
+  time_first:             0.     # (Optional) Time of the first stats output if non-cosmological time-integration (in internal units)
+
+# Parameters related to the initial conditions
+InitialConditions:
+  file_name:          ICs_homogeneous_box.hdf5
+  periodic:                    1    # Are we running with periodic ICs?
+  shift:              [0.0,0.0,0.0]
+
+# Parameters for the hydrodynamics scheme
+SPH:
+  resolution_eta:        1.2348   # Target smoothing length in units of the mean inter-particle separation (1.2348 == 57Ngbs with the Wendland C2 kernel).
+  CFL_condition:         0.1      # Courant-Friedrich-Levy condition for time integration.
+  h_max:                 5
+  minimal_temperature:   1
+
+
+# Cooling with Grackle 3.0
+GrackleCooling:
+  cloudy_table: CloudyData_UVB=HM2012.h5        # Name of the Cloudy Table (available on the grackle bitbucket repository)
+  with_UV_background: 0                         # Enable or not the UV background
+  redshift: -1                                  # Redshift to use (-1 means time based redshift)
+  with_metal_cooling: 1                         # Enable or not the metal cooling
+  provide_volumetric_heating_rates: 0           # User provide volumetric heating rates
+  provide_specific_heating_rates: 0             # User provide specific heating rates
+  self_shielding_method: -1                     # Grackle (<= 3) or Gear self shielding method
+  self_shielding_threshold_atom_per_cm3: 0.007  # Required only with GEAR's self shielding. Density threshold of the self shielding
+  max_steps: 1000
+  convergence_limit: 1e-2
+  thermal_time_myr: 5
+  maximal_density_Hpcm3: -1                     # Maximal density (in hydrogen atoms/cm^3) for cooling. Higher densities are floored to this value to ensure grackle works properly when interpolating beyond the cloudy_table maximal density. A value < 0 deactivates this parameter.
+
+GEARChemistry:
+  initial_metallicity: 0
+
+GEARFeedback:
+  supernovae_energy_erg: 1e51                     # supernovae energy, used only for SNIa
+  supernovae_efficiency: 0.1                      # supernovae energy efficiency, used for both SNIa and SNII
+  yields_table: POPIIsw.h5
+  yields_table_first_stars: POPIIsw.h5
+  discrete_yields: 1
+  imf_transition_metallicity: -5                  # Maximal metallicity ([Fe/H]) for a first star (0 to deactivate).
+  elements: [Fe, Mg, O, C, Al, Ca, Ba, Zn, Eu]    # Elements to read in the yields table. The number of element should be one less than the number of elements (N) requested during the configuration (--with-chemistry=GEAR_N).
+
+GEARSink:
+  cut_off_radius: 5e-3                            # Cut off radius of all the sinks in internal units.
+  f_acc: 0.1
+  temperature_threshold_K:       100              # Max temperature (in K) for forming a sink when density_threshold_g_per_cm3 <= density <= maximal_density_threshold_g_per_cm3.
+  density_threshold_Hpcm3: 1e1           # Minimum gas density (in g/cm3) required to form a sink particle.
+  maximal_density_threshold_Hpcm3: 1e5   # If the gas density exceeds this value (in g/cm3), a sink forms regardless of temperature if all other criteria are passed.
+  stellar_particle_mass_Msun: 50                  # Mass of the stellar particle representing the low mass stars, in solar mass
+  minimal_discrete_mass_Msun: 8                   # Minimal mass of stars represented by discrete particles, in solar mass
+  stellar_particle_mass_first_stars_Msun: 50      # Mass of the stellar particle representing the low mass stars, in solar mass
+  minimal_discrete_mass_first_stars_Msun: 8       # Minimal mass of stars represented by discrete particles, in solar mass
+  star_spawning_sigma_factor: 0.5                 # Factor to rescale the velocity dispersion of the stars when they are spawned. (Default: 0.2)
+  sink_formation_contracting_gas_criterion:   1   # (Optional) Activate the contracting gas check for sink formation. (Default: 1)
+  sink_formation_smoothing_length_criterion:  1   # (Optional) Activate the smoothing length check for sink formation. (Default: 1)
+  sink_formation_jeans_instability_criterion: 1   # (Optional) Activate the two Jeans instability checks for sink formation. (Default: 1)
+  sink_formation_bound_state_criterion:       1   # (Optional) Activate the bound state check for sink formation. (Default: 1)
+  sink_formation_overlapping_sink_criterion:  1   # (Optional) Activate the overlapping sink check for sink formation. (Default: 1)
+  disable_sink_formation:                     0   # (Optional) Disable sink formation. (Default: 0)
diff --git a/examples/SinkParticles/HomogeneousBoxSinkParticles/run.sh b/examples/SinkParticles/HomogeneousBoxSinkParticles/run.sh
new file mode 100755
index 0000000000000000000000000000000000000000..9db866d75f792434d5fe2d93f9e6668299737dd2
--- /dev/null
+++ b/examples/SinkParticles/HomogeneousBoxSinkParticles/run.sh
@@ -0,0 +1,55 @@
+#!/bin/bash
+
+# make run.sh fail if a subcommand fails
+set -e
+
+n_threads=${n_threads:=8}  #Number of threads to use
+level=${level:=5}  #Number of particles = 2^(3*level)
+jeans_length=${jeans_length:=0.250}  #Jeans wavelenght in unit of the boxsize
+gas_density=${gas_density:=0.1} #Gas density in atom/cm^3
+gas_particle_mass=${gas_particle_mass:=50} #Mass of the gas particles
+n_sinks=${n_sinks:=10}  #Number of sinks
+
+# Remove the ICs
+if [ -e ICs_homogeneous_box.hdf5 ]
+then
+    rm ICs_homogeneous_box.hdf5
+fi
+
+#Create the ICs if they do not exist
+if [ ! -e ICs_homogeneous_box.hdf5 ]
+then
+    echo "Generating initial conditions to run the example..."
+    python3 makeIC.py --level $level -o ICs_homogeneous_box.hdf5 --lJ $jeans_length --n_sink $n_sinks --sink_pos 0 0 0 --sinks_vel 10 10 0
+fi
+
+
+# Get the Grackle cooling table
+if [ ! -e CloudyData_UVB=HM2012.h5 ]
+then
+    echo "Fetching the Cloudy tables required by Grackle..."
+    ./getGrackleCoolingTable.sh
+fi
+
+
+if [ ! -e POPIIsw.h5 ]
+then
+    echo "Fetching the chemistry tables..."
+    ./getChemistryTable.sh
+fi
+
+
+# Create output directory
+DIR=snap #First test of units conversion
+if [ -d "$DIR" ];
+then
+    echo "$DIR directory exists. Its content will be removed."
+    rm -r $DIR
+else
+    echo "$DIR directory does not exists. It will be created."
+    mkdir $DIR
+fi
+
+printf "Running simulation..."
+
+../../../swift --hydro --sinks --stars --external-gravity --feedback --threads=$n_threads params.yml 2>&1 | tee output.log
diff --git a/src/cell.c b/src/cell.c
index 4f58054830f31a43dd96f8539262af0fc0b5ceb6..faadb774325f5bdf38ddc1c43742ed261c84a45f 100644
--- a/src/cell.c
+++ b/src/cell.c
@@ -293,6 +293,39 @@ int cell_link_bparts(struct cell *c, struct bpart *bparts) {
   return c->black_holes.count;
 }
 
+/**
+ * @brief Link the cells recursively to the given #sink array.
+ *
+ * @param c The #cell.
+ * @param sinks The #sink array.
+ *
+ * @return The number of particles linked.
+ */
+int cell_link_sinks(struct cell *c, struct sink *sinks) {
+#ifdef SWIFT_DEBUG_CHECKS
+  if (c->nodeID == engine_rank)
+    error("Linking foreign particles in a local cell!");
+
+  if (c->sinks.parts != NULL)
+    error("Linking sparts into a cell that was already linked");
+#endif
+
+  c->sinks.parts = sinks;
+  c->sinks.parts_rebuild = sinks;
+
+  /* Fill the progeny recursively, depth-first. */
+  if (c->split) {
+    int offset = 0;
+    for (int k = 0; k < 8; k++) {
+      if (c->progeny[k] != NULL)
+        offset += cell_link_sinks(c->progeny[k], &sinks[offset]);
+    }
+  }
+
+  /* Return the total number of linked particles. */
+  return c->sinks.count;
+}
+
 /**
  * @brief Recurse down foreign cells until reaching one with hydro
  * tasks; then trigger the linking of the #part array from that
@@ -413,6 +446,7 @@ void cell_unlink_foreign_particles(struct cell *c) {
   c->hydro.parts = NULL;
   c->stars.parts = NULL;
   c->black_holes.parts = NULL;
+  c->sinks.parts = NULL;
 
   if (c->split) {
     for (int k = 0; k < 8; k++) {
diff --git a/src/cell.h b/src/cell.h
index 2bb2d6976964461d797069a24c9bad9f9e71cdf3..9cb04b32c4a81affa50ea6584c1679ca756414dc 100644
--- a/src/cell.h
+++ b/src/cell.h
@@ -280,6 +280,15 @@ struct pcell_step {
     float dx_max_part;
   } black_holes;
 
+  struct {
+
+    /*! Minimal integer end-of-timestep in this cell (sinks) */
+    integertime_t ti_end_min;
+
+    /*! Maximal distance any #part has travelled since last rebuild */
+    float dx_max_part;
+  } sinks;
+
   struct {
 
     /*! Minimal integer end-of-timestep in this cell (rt) */
@@ -562,6 +571,7 @@ int cell_link_parts(struct cell *c, struct part *parts);
 int cell_link_gparts(struct cell *c, struct gpart *gparts);
 int cell_link_sparts(struct cell *c, struct spart *sparts);
 int cell_link_bparts(struct cell *c, struct bpart *bparts);
+int cell_link_sinks(struct cell *c, struct sink *sinks);
 int cell_link_foreign_parts(struct cell *c, struct part *parts);
 int cell_link_foreign_gparts(struct cell *c, struct gpart *gparts);
 void cell_unlink_foreign_particles(struct cell *c);
diff --git a/src/cell_pack.c b/src/cell_pack.c
index 21bf9ad122c788f228e811a3dd7024d39fa5cafb..83f8c4cab9d9c9de3cddfc906f789c3e0d2b2384 100644
--- a/src/cell_pack.c
+++ b/src/cell_pack.c
@@ -303,6 +303,7 @@ int cell_unpack(struct pcell *restrict pc, struct cell *restrict c,
       temp->hydro.count = 0;
       temp->grav.count = 0;
       temp->stars.count = 0;
+      temp->sinks.count = 0;
       temp->loc[0] = c->loc[0];
       temp->loc[1] = c->loc[1];
       temp->loc[2] = c->loc[2];
@@ -319,6 +320,7 @@ int cell_unpack(struct pcell *restrict pc, struct cell *restrict c,
       temp->hydro.dx_max_sort = 0.f;
       temp->stars.dx_max_part = 0.f;
       temp->stars.dx_max_sort = 0.f;
+      temp->sinks.dx_max_part = 0.f;
       temp->black_holes.dx_max_part = 0.f;
       temp->nodeID = c->nodeID;
       temp->parent = c;
@@ -457,6 +459,9 @@ int cell_pack_end_step(const struct cell *c, struct pcell_step *pcells) {
   pcells[0].black_holes.ti_end_min = c->black_holes.ti_end_min;
   pcells[0].black_holes.dx_max_part = c->black_holes.dx_max_part;
 
+  pcells[0].sinks.ti_end_min = c->sinks.ti_end_min;
+  pcells[0].sinks.dx_max_part = c->sinks.dx_max_part;
+
   /* Fill in the progeny, depth-first recursion. */
   int count = 1;
   for (int k = 0; k < 8; k++)
@@ -501,6 +506,9 @@ int cell_unpack_end_step(struct cell *c, const struct pcell_step *pcells) {
   c->black_holes.ti_end_min = pcells[0].black_holes.ti_end_min;
   c->black_holes.dx_max_part = pcells[0].black_holes.dx_max_part;
 
+  c->sinks.ti_end_min = pcells[0].sinks.ti_end_min;
+  c->sinks.dx_max_part = pcells[0].sinks.dx_max_part;
+
   /* Fill in the progeny, depth-first recursion. */
   int count = 1;
   for (int k = 0; k < 8; k++)
diff --git a/src/cell_sinks.h b/src/cell_sinks.h
index 6bd2f9a9afed9847001a9a106b6f2dac9a1b433d..9043ad191552657c7183b35ec7d443207f4af384 100644
--- a/src/cell_sinks.h
+++ b/src/cell_sinks.h
@@ -42,6 +42,9 @@ struct cell_sinks {
     /*! Pointer to the #sink data. */
     struct sink *parts;
 
+    /*! Pointer to the #spart data at rebuild time. */
+    struct sink *parts_rebuild;
+
     /*! Linked list of the tasks computing this cell's sink swallow. */
     struct link *swallow;
 
diff --git a/src/cell_split.c b/src/cell_split.c
index ee669ae17ac05eb8de1c8724c4656d8946d04c33..df0fc2572e0b5fa1c33164c07b7b1c7453a3804e 100644
--- a/src/cell_split.c
+++ b/src/cell_split.c
@@ -384,6 +384,7 @@ void cell_split(struct cell *c, const ptrdiff_t parts_offset,
     c->progeny[k]->sinks.count = bucket_count[k];
     c->progeny[k]->sinks.count_total = c->progeny[k]->sinks.count;
     c->progeny[k]->sinks.parts = &c->sinks.parts[bucket_offset[k]];
+    c->progeny[k]->sinks.parts_rebuild = c->progeny[k]->sinks.parts;
   }
 
   /* Finally, do the same song and dance for the gparts. */
diff --git a/src/cell_unskip.c b/src/cell_unskip.c
index 3ce7d791a712e5dcacbc7794af08e81513fa5fdd..adfd6eb6ef1512c845a46674681cc6c1edea0bc3 100644
--- a/src/cell_unskip.c
+++ b/src/cell_unskip.c
@@ -3001,7 +3001,7 @@ int cell_unskip_sinks_tasks(struct cell *c, struct scheduler *s) {
       if (cell_need_rebuild_for_sinks_pair(ci, cj)) rebuild = 1;
       if (cell_need_rebuild_for_sinks_pair(cj, ci)) rebuild = 1;
 
-#ifdef WITH_MPI
+#if defined(WITH_MPI) && !defined(SWIFT_DEBUG_CHECKS)
       error("TODO");
 #endif
     }
diff --git a/src/cooling/grackle/cooling.c b/src/cooling/grackle/cooling.c
index 205a7b4f96ca663fbf0ee540febb38d4f5479488..be7d417259654ccdf370fb644de1db012f5f683a 100644
--- a/src/cooling/grackle/cooling.c
+++ b/src/cooling/grackle/cooling.c
@@ -68,6 +68,18 @@ double cooling_get_physical_density(
     const struct part* p, const struct cosmology* cosmo,
     const struct cooling_function_data* cooling);
 
+/**
+ * @brief Record the time when cooling was switched off for a particle.
+ *
+ * @param p #part data.
+ * @param xp Pointer to the #xpart data.
+ * @param time The time when the cooling was switched off.
+ */
+INLINE void cooling_set_part_time_cooling_off(struct part* p, struct xpart* xp,
+                                              const double time) {
+  xp->cooling_data.time_last_event = time;
+}
+
 /**
  * @brief Common operations performed on the cooling function at a
  * given time-step or redshift.
diff --git a/src/cooling/grackle/cooling.h b/src/cooling/grackle/cooling.h
index 92f6c921634bb62e58626effbcdc1019b2ecc75f..e5849a421eff0763217b09c8bcf15734471a1b94 100644
--- a/src/cooling/grackle/cooling.h
+++ b/src/cooling/grackle/cooling.h
@@ -105,6 +105,16 @@ INLINE static float cooling_get_subgrid_density(const struct part* p,
   return -1.f;
 }
 
+/**
+ * @brief Record the time when cooling was switched off for a particle.
+ *
+ * @param p #part data.
+ * @param xp Pointer to the #xpart data.
+ * @param time The time when the cooling was switched off.
+ */
+void cooling_set_part_time_cooling_off(struct part* p, struct xpart* xp,
+                                       const double time);
+
 float cooling_get_radiated_energy(const struct xpart* restrict xp);
 void cooling_print_backend(const struct cooling_function_data* cooling);
 
diff --git a/src/cooling/none/cooling.h b/src/cooling/none/cooling.h
index dbb5e9872bf4e197f372c3f4a121c1beaaa775f9..d7955c4e4b1902796b855012e3f454f69e0eb70e 100644
--- a/src/cooling/none/cooling.h
+++ b/src/cooling/none/cooling.h
@@ -277,6 +277,19 @@ __attribute__((always_inline)) INLINE static float cooling_get_radiated_energy(
   return 0.f;
 }
 
+/**
+ * @brief Record the time when cooling was switched off for a particle.
+ *
+ * In none model, this function does nothing.
+ *
+ * @param p #part data.
+ * @param xp Pointer to the #xpart data.
+ * @param time The time when the cooling was switched off.
+ */
+INLINE static void cooling_set_part_time_cooling_off(struct part* p,
+                                                     struct xpart* xp,
+                                                     const double time) {}
+
 /**
  * @brief Split the coolong content of a particle into n pieces
  *
diff --git a/src/engine.c b/src/engine.c
index 3b992186dcdf2e9907accda1598cc084f4156603..1707dcf6300f1224e9fc8ccac7b769206653c64f 100644
--- a/src/engine.c
+++ b/src/engine.c
@@ -781,13 +781,14 @@ void engine_allocate_foreign_particles(struct engine *e, const int fof) {
       e->policy & (engine_policy_hydro | engine_policy_grid_hydro);
   const int with_stars = e->policy & engine_policy_stars;
   const int with_black_holes = e->policy & engine_policy_black_holes;
+  const int with_sinks = e->policy & engine_policy_sinks;
   struct space *s = e->s;
   ticks tic = getticks();
 
   /* Count the number of particles we need to import and re-allocate
      the buffer if needed. */
   size_t count_parts_in = 0, count_gparts_in = 0, count_sparts_in = 0,
-         count_bparts_in = 0;
+         count_bparts_in = 0, count_sinks_in = 0;
   for (int k = 0; k < nr_proxies; k++) {
     for (int j = 0; j < e->proxies[k].nr_cells_in; j++) {
 
@@ -806,6 +807,11 @@ void engine_allocate_foreign_particles(struct engine *e, const int fof) {
 
       /* For black holes, we just use the numbers in the top-level cells */
       count_bparts_in += e->proxies[k].cells_in[j]->black_holes.count;
+
+      /* For sinks, we just use the numbers in the top-level cells + some
+         extra space */
+      count_sinks_in +=
+          e->proxies[k].cells_in[j]->sinks.count + space_extra_sinks;
     }
   }
 
@@ -871,28 +877,49 @@ void engine_allocate_foreign_particles(struct engine *e, const int fof) {
       error("Failed to allocate foreign bpart data.");
   }
 
+  /* Allocate space for the foreign particles we will receive */
+  size_t old_size_sinks_foreign = s->size_sinks_foreign;
+  if (!fof && count_sinks_in > s->size_sinks_foreign) {
+    if (s->sinks_foreign != NULL) swift_free("sinks_foreign", s->sinks_foreign);
+    s->size_sinks_foreign = engine_foreign_alloc_margin * count_sinks_in;
+    if (swift_memalign("sinks_foreign", (void **)&s->sinks_foreign, sink_align,
+                       sizeof(struct sink) * s->size_sinks_foreign) != 0)
+      error("Failed to allocate foreign sink data.");
+    bzero(s->sinks_foreign, s->size_sinks_foreign * sizeof(struct sink));
+
+    /* Note: If you ever see a sink particle with id = -666, the following
+       lines is the ones that sets the ID to this value. */
+    for (size_t i = 0; i < s->size_sinks_foreign; ++i) {
+      s->sinks_foreign[i].time_bin = time_bin_not_created;
+      s->sinks_foreign[i].id = -666;
+    }
+  }
+
   if (e->verbose) {
     message(
-        "Allocating %zd/%zd/%zd/%zd foreign part/gpart/spart/bpart "
-        "(%zd/%zd/%zd/%zd MB)",
+        "Allocating %zd/%zd/%zd/%zd/%zd foreign part/gpart/spart/bpart/sink "
+        "(%zd/%zd/%zd/%zd/%zd MB)",
         s->size_parts_foreign, s->size_gparts_foreign, s->size_sparts_foreign,
-        s->size_bparts_foreign,
+        s->size_bparts_foreign, s->size_sinks_foreign,
         s->size_parts_foreign * sizeof(struct part) / (1024 * 1024),
         s->size_gparts_foreign * sizeof(struct gpart) / (1024 * 1024),
         s->size_sparts_foreign * sizeof(struct spart) / (1024 * 1024),
-        s->size_bparts_foreign * sizeof(struct bpart) / (1024 * 1024));
+        s->size_bparts_foreign * sizeof(struct bpart) / (1024 * 1024),
+        s->size_sinks_foreign * sizeof(struct sink) / (1024 * 1024));
 
     if ((s->size_parts_foreign - old_size_parts_foreign) > 0 ||
         (s->size_gparts_foreign - old_size_gparts_foreign) > 0 ||
         (s->size_sparts_foreign - old_size_sparts_foreign) > 0 ||
-        (s->size_bparts_foreign - old_size_bparts_foreign) > 0) {
+        (s->size_bparts_foreign - old_size_bparts_foreign) > 0 ||
+        (s->size_sinks_foreign - old_size_sinks_foreign) > 0) {
       message(
-          "Re-allocations %zd/%zd/%zd/%zd part/gpart/spart/bpart "
-          "(%zd/%zd/%zd/%zd MB)",
+          "Re-allocations %zd/%zd/%zd/%zd/%zd part/gpart/spart/bpart/sink "
+          "(%zd/%zd/%zd/%zd/%zd MB)",
           (s->size_parts_foreign - old_size_parts_foreign),
           (s->size_gparts_foreign - old_size_gparts_foreign),
           (s->size_sparts_foreign - old_size_sparts_foreign),
           (s->size_bparts_foreign - old_size_bparts_foreign),
+          (s->size_sinks_foreign - old_size_sinks_foreign),
           (s->size_parts_foreign - old_size_parts_foreign) *
               sizeof(struct part) / (1024 * 1024),
           (s->size_gparts_foreign - old_size_gparts_foreign) *
@@ -900,7 +927,9 @@ void engine_allocate_foreign_particles(struct engine *e, const int fof) {
           (s->size_sparts_foreign - old_size_sparts_foreign) *
               sizeof(struct spart) / (1024 * 1024),
           (s->size_bparts_foreign - old_size_bparts_foreign) *
-              sizeof(struct bpart) / (1024 * 1024));
+              sizeof(struct bpart) / (1024 * 1024),
+          (s->size_sinks_foreign - old_size_sinks_foreign) *
+              sizeof(struct sink) / (1024 * 1024));
     }
   }
 
@@ -909,6 +938,7 @@ void engine_allocate_foreign_particles(struct engine *e, const int fof) {
   struct gpart *gparts = s->gparts_foreign;
   struct spart *sparts = s->sparts_foreign;
   struct bpart *bparts = s->bparts_foreign;
+  struct sink *sinks = s->sinks_foreign;
   for (int k = 0; k < nr_proxies; k++) {
     for (int j = 0; j < e->proxies[k].nr_cells_in; j++) {
 
@@ -940,6 +970,14 @@ void engine_allocate_foreign_particles(struct engine *e, const int fof) {
         cell_link_bparts(e->proxies[k].cells_in[j], bparts);
         bparts = &bparts[e->proxies[k].cells_in[j]->black_holes.count];
       }
+
+      if (!fof && with_sinks) {
+
+        /* For sinks, we just use the numbers in the top-level cells */
+        cell_link_sinks(e->proxies[k].cells_in[j], sinks);
+        sinks =
+            &sinks[e->proxies[k].cells_in[j]->sinks.count + space_extra_sinks];
+      }
     }
   }
 
@@ -948,6 +986,7 @@ void engine_allocate_foreign_particles(struct engine *e, const int fof) {
   s->nr_gparts_foreign = gparts - s->gparts_foreign;
   s->nr_sparts_foreign = sparts - s->sparts_foreign;
   s->nr_bparts_foreign = bparts - s->bparts_foreign;
+  s->nr_sinks_foreign = sinks - s->sinks_foreign;
 
   if (e->verbose)
     message("Recursively linking foreign arrays took %.3f %s.",
@@ -1135,8 +1174,15 @@ int engine_estimate_nr_tasks(const struct engine *e) {
 #endif
   }
   if (e->policy & engine_policy_sinks) {
-    /* 1 drift, 2 kicks, 1 time-step, 1 sink formation */
-    n1 += 5;
+    /* 1 drift, 2 kicks, 1 time-step, 1 sink formation     | 5
+       density: 1 self + 13 pairs                          | 14
+       swallow: 1 self + 13 pairs                          | 14
+       do_gas_swallow: 1 self + 13 pairs                   | 14
+       do_sink_swallow: 1 self + 13 pairs                  | 14
+       ghosts: density_ghost, sink_ghost_1, sink_ghost_2   | 3
+       implicit: sink_in,  sink_out                        | 2 */
+    n1 += 66;
+    n2 += 3;
     if (e->policy & engine_policy_stars) {
       /* 1 star formation */
       n1 += 1;
@@ -1205,7 +1251,8 @@ int engine_estimate_nr_tasks(const struct engine *e) {
     struct cell *c = &e->s->cells_top[k];
 
     /* Any cells with particles will have tasks (local & foreign). */
-    int nparts = c->hydro.count + c->grav.count + c->stars.count;
+    int nparts = c->hydro.count + c->grav.count + c->stars.count +
+                 c->black_holes.count + c->sinks.count;
     if (nparts > 0) {
       ntop++;
       ncells++;
diff --git a/src/engine.h b/src/engine.h
index 50e98011c29ff3e2cd731ebce5fcce6b8c5df085..81c6fa07109833dcabc906e435bfb6edc1fe9a0e 100644
--- a/src/engine.h
+++ b/src/engine.h
@@ -749,7 +749,8 @@ void engine_exchange_strays(struct engine *e, const size_t offset_parts,
                             size_t *Ngpart, const size_t offset_sparts,
                             const int *ind_spart, size_t *Nspart,
                             const size_t offset_bparts, const int *ind_bpart,
-                            size_t *Nbpart);
+                            size_t *Nbpart, const size_t offset_sinks,
+                            const int *ind_sink, size_t *Nsink);
 void engine_rebuild(struct engine *e, int redistributed, int clean_h_values);
 void engine_repartition(struct engine *e);
 void engine_repartition_trigger(struct engine *e);
diff --git a/src/engine_config.c b/src/engine_config.c
index 5e6c4eb98ccc427e76f771070632c082ec9683d0..74fc0d20d6dd12fc90c17d09505c092f4da148c9 100644
--- a/src/engine_config.c
+++ b/src/engine_config.c
@@ -950,6 +950,8 @@ void engine_config(int restart, int fof, struct engine *e,
         params, "Scheduler:cell_extra_gparts", space_extra_gparts_default);
     space_extra_bparts = parser_get_opt_param_int(
         params, "Scheduler:cell_extra_bparts", space_extra_bparts_default);
+    space_extra_sinks = parser_get_opt_param_int(
+        params, "Scheduler:cell_extra_sinks", space_extra_sinks_default);
 
     /* Do we want any spare particles for on the fly creation?
        This condition should be the same than in space.c */
diff --git a/src/engine_maketasks.c b/src/engine_maketasks.c
index 5592e384ec9d4fc2a1609ad5744ea1b46397f8ad..e18cf26e5a1073b6f68123875d43e1f64968a908 100644
--- a/src/engine_maketasks.c
+++ b/src/engine_maketasks.c
@@ -365,14 +365,13 @@ void engine_addtasks_send_stars(struct engine *e, struct cell *ci,
                                 struct cell *cj, struct task *t_density,
                                 struct task *t_prep2, struct task *t_sf_counts,
                                 const int with_star_formation) {
-#ifdef SWIFT_DEBUG_CHECKS
+#ifdef WITH_MPI
+#if !defined(SWIFT_DEBUG_CHECKS)
   if (e->policy & engine_policy_sinks && e->policy & engine_policy_stars) {
-    error("TODO");
+    error("TODO: Star formation sink over MPI");
   }
 #endif
 
-#ifdef WITH_MPI
-
   struct link *l = NULL;
   struct scheduler *s = &e->sched;
   const int nodeID = cj->nodeID;
@@ -916,13 +915,13 @@ void engine_addtasks_recv_stars(struct engine *e, struct cell *c,
                                 struct task *t_sf_counts,
                                 struct task *const tend,
                                 const int with_star_formation) {
-#ifdef SWIFT_DEBUG_CHECKS
+#ifdef WITH_MPI
+#if !defined(SWIFT_DEBUG_CHECKS)
   if (e->policy & engine_policy_sinks && e->policy & engine_policy_stars) {
-    error("TODO");
+    error("TODO: Star formation sink over MPI");
   }
 #endif
 
-#ifdef WITH_MPI
   struct scheduler *s = &e->sched;
 
   /* Early abort (are we below the level where tasks are)? */
@@ -4378,9 +4377,9 @@ void engine_addtasks_send_mapper(void *map_data, int num_elements,
   const int with_rt = (e->policy & engine_policy_rt);
   struct cell_type_pair *cell_type_pairs = (struct cell_type_pair *)map_data;
 
-#ifdef SWIFT_DEBUG_CHECKS
+#if defined(WITH_MPI) && !defined(SWIFT_DEBUG_CHECKS)
   if (e->policy & engine_policy_sinks) {
-    error("TODO");
+    error("TODO: Sink MPI tasks are not implemented yet!");
   }
 #endif
 
@@ -4451,9 +4450,9 @@ void engine_addtasks_recv_mapper(void *map_data, int num_elements,
   const int with_rt = (e->policy & engine_policy_rt);
   struct cell_type_pair *cell_type_pairs = (struct cell_type_pair *)map_data;
 
-#ifdef SWIFT_DEBUG_CHECKS
+#if defined(WITH_MPI) && !defined(SWIFT_DEBUG_CHECKS)
   if (e->policy & engine_policy_sinks) {
-    error("TODO");
+    error("TODO: Sink MPI tasks are not implemented yet!");
   }
 #endif
 
diff --git a/src/engine_redistribute.c b/src/engine_redistribute.c
index bb8b7b6ead70796990c7ecb0311c2a65e4959bf1..cf22b146c4040d1a62c25f75b85a9975271de037 100644
--- a/src/engine_redistribute.c
+++ b/src/engine_redistribute.c
@@ -319,6 +319,14 @@ void ENGINE_REDISTRIBUTE_DEST_MAPPER(gpart);
  */
 void ENGINE_REDISTRIBUTE_DEST_MAPPER(bpart);
 
+/**
+ * @brief Accumulate the counts of sink particles per cell.
+ * Threadpool helper for accumulating the counts of particles per cell.
+ *
+ * sink version.
+ */
+void ENGINE_REDISTRIBUTE_DEST_MAPPER(sink);
+
 #endif /* redist_mapper_data */
 
 #ifdef WITH_MPI /* savelink_mapper_data */
@@ -399,12 +407,22 @@ void ENGINE_REDISTRIBUTE_SAVELINK_MAPPER(bpart, 1);
 void ENGINE_REDISTRIBUTE_SAVELINK_MAPPER(bpart, 0);
 #endif
 
+/**
+ * @brief Save position of sink-gpart links.
+ * Threadpool helper for accumulating the counts of particles per cell.
+ */
+#ifdef SWIFT_DEBUG_CHECKS
+void ENGINE_REDISTRIBUTE_SAVELINK_MAPPER(sink, 1);
+#else
+void ENGINE_REDISTRIBUTE_SAVELINK_MAPPER(sink, 0);
+#endif
+
 #endif /* savelink_mapper_data */
 
 #ifdef WITH_MPI /* relink_mapper_data */
 
-/* Support for relinking parts, gparts, sparts and bparts after moving between
- * nodes. */
+/* Support for relinking parts, gparts, sparts, bparts and sinks after moving
+ * between nodes. */
 struct relink_mapper_data {
   int nodeID;
   int nr_nodes;
@@ -412,6 +430,7 @@ struct relink_mapper_data {
   int *s_counts;
   int *g_counts;
   int *b_counts;
+  int *sink_counts;
   struct space *s;
 };
 
@@ -435,6 +454,7 @@ void engine_redistribute_relink_mapper(void *map_data, int num_elements,
   int *g_counts = mydata->g_counts;
   int *s_counts = mydata->s_counts;
   int *b_counts = mydata->b_counts;
+  int *sink_counts = mydata->sink_counts;
   struct space *s = mydata->s;
 
   for (int i = 0; i < num_elements; i++) {
@@ -446,12 +466,14 @@ void engine_redistribute_relink_mapper(void *map_data, int num_elements,
     size_t offset_gparts = 0;
     size_t offset_sparts = 0;
     size_t offset_bparts = 0;
+    size_t offset_sinks = 0;
     for (int n = 0; n < node; n++) {
       int ind_recv = n * nr_nodes + nodeID;
       offset_parts += counts[ind_recv];
       offset_gparts += g_counts[ind_recv];
       offset_sparts += s_counts[ind_recv];
       offset_bparts += b_counts[ind_recv];
+      offset_sinks += sink_counts[ind_recv];
     }
 
     /* Number of gparts sent from this node. */
@@ -493,6 +515,17 @@ void engine_redistribute_relink_mapper(void *map_data, int num_elements,
         s->gparts[k].id_or_neg_offset = -partner_index;
         s->bparts[partner_index].gpart = &s->gparts[k];
       }
+
+      /* Does this gpart have a sink partner ? */
+      else if (s->gparts[k].type == swift_type_sink) {
+
+        const ptrdiff_t partner_index =
+            offset_sinks - s->gparts[k].id_or_neg_offset;
+
+        /* Re-link */
+        s->gparts[k].id_or_neg_offset = -partner_index;
+        s->sinks[partner_index].gpart = &s->gparts[k];
+      }
     }
   }
 }
@@ -519,13 +552,6 @@ void engine_redistribute_relink_mapper(void *map_data, int num_elements,
 void engine_redistribute(struct engine *e) {
 
 #ifdef WITH_MPI
-#ifdef SWIFT_DEBUG_CHECKS
-  const int nr_sinks_new = 0;
-#endif
-  if (e->policy & engine_policy_sinks) {
-    error("Not implemented yet");
-  }
-
   const int nr_nodes = e->nr_nodes;
   const int nodeID = e->nodeID;
   struct space *s = e->s;
@@ -536,12 +562,14 @@ void engine_redistribute(struct engine *e) {
   struct gpart *gparts = s->gparts;
   struct spart *sparts = s->sparts;
   struct bpart *bparts = s->bparts;
+  struct sink *sinks = s->sinks;
   ticks tic = getticks();
 
   size_t nr_parts = s->nr_parts;
   size_t nr_gparts = s->nr_gparts;
   size_t nr_sparts = s->nr_sparts;
   size_t nr_bparts = s->nr_bparts;
+  size_t nr_sinks = s->nr_sinks;
 
   /* Start by moving inhibited particles to the end of the arrays */
   for (size_t k = 0; k < nr_parts; /* void */) {
@@ -609,6 +637,27 @@ void engine_redistribute(struct engine *e) {
     }
   }
 
+  /* Now move inhibited sink particles to the end of the arrays */
+  for (size_t k = 0; k < nr_sinks; /* void */) {
+    if (sinks[k].time_bin == time_bin_inhibited ||
+        sinks[k].time_bin == time_bin_not_created) {
+      nr_sinks -= 1;
+
+      /* Swap the particle */
+      memswap(&s->sinks[k], &s->sinks[nr_sinks], sizeof(struct sink));
+
+      /* Swap the link with the gpart */
+      if (s->sinks[k].gpart != NULL) {
+        s->sinks[k].gpart->id_or_neg_offset = -k;
+      }
+      if (s->sinks[nr_sinks].gpart != NULL) {
+        s->sinks[nr_sinks].gpart->id_or_neg_offset = -nr_sinks;
+      }
+    } else {
+      k++;
+    }
+  }
+
   /* Finally do the same with the gravity particles */
   for (size_t k = 0; k < nr_gparts; /* void */) {
     if (gparts[k].time_bin == time_bin_inhibited ||
@@ -626,6 +675,8 @@ void engine_redistribute(struct engine *e) {
         s->sparts[-s->gparts[k].id_or_neg_offset].gpart = &s->gparts[k];
       } else if (s->gparts[k].type == swift_type_black_hole) {
         s->bparts[-s->gparts[k].id_or_neg_offset].gpart = &s->gparts[k];
+      } else if (s->gparts[k].type == swift_type_sink) {
+        s->sinks[-s->gparts[k].id_or_neg_offset].gpart = &s->gparts[k];
       }
 
       if (s->gparts[nr_gparts].type == swift_type_gas) {
@@ -637,6 +688,9 @@ void engine_redistribute(struct engine *e) {
       } else if (s->gparts[nr_gparts].type == swift_type_black_hole) {
         s->bparts[-s->gparts[nr_gparts].id_or_neg_offset].gpart =
             &s->gparts[nr_gparts];
+      } else if (s->gparts[nr_gparts].type == swift_type_sink) {
+        s->sinks[-s->gparts[nr_sinks].id_or_neg_offset].gpart =
+            &s->gparts[nr_gparts];
       }
     } else {
       k++;
@@ -857,6 +911,73 @@ void engine_redistribute(struct engine *e) {
   }
   swift_free("b_dest", b_dest);
 
+  /* Get destination of each sink-particle */
+  int *sink_counts;
+  if ((sink_counts = (int *)calloc(nr_nodes * nr_nodes, sizeof(int))) == NULL)
+    error("Failed to allocate sink_counts temporary buffer.");
+
+  int *sink_dest;
+  if ((sink_dest = (int *)swift_malloc("sink_dest", sizeof(int) * nr_sinks)) ==
+      NULL)
+    error("Failed to allocate sink_dest temporary buffer.");
+
+  redist_data.counts = sink_counts;
+  redist_data.dest = sink_dest;
+  redist_data.base = (void *)sinks;
+
+  threadpool_map(&e->threadpool, engine_redistribute_dest_mapper_sink, sinks,
+                 nr_sinks, sizeof(struct sink), threadpool_auto_chunk_size,
+                 &redist_data);
+
+  /* Sort the particles according to their cell index. */
+  if (nr_sinks > 0)
+    space_sinks_sort(s->sinks, sink_dest, &sink_counts[nodeID * nr_nodes],
+                     nr_nodes, 0);
+
+#ifdef SWIFT_DEBUG_CHECKS
+  /* Verify that the sink have been sorted correctly. */
+  for (size_t k = 0; k < nr_sinks; k++) {
+    const struct sink *sink = &s->sinks[k];
+
+    if (sink->time_bin == time_bin_inhibited)
+      error("Inhibited particle found after sorting!");
+
+    if (sink->time_bin == time_bin_not_created)
+      error("Inhibited particle found after sorting!");
+
+    /* New cell index */
+    const int new_cid =
+        cell_getid(s->cdim, sink->x[0] * s->iwidth[0],
+                   sink->x[1] * s->iwidth[1], sink->x[2] * s->iwidth[2]);
+
+    /* New cell of this sink */
+    const struct cell *c = &s->cells_top[new_cid];
+    const int new_node = c->nodeID;
+
+    if (sink_dest[k] != new_node)
+      error("sink's new node index not matching sorted index.");
+
+    if (sink->x[0] < c->loc[0] || sink->x[0] > c->loc[0] + c->width[0] ||
+        sink->x[1] < c->loc[1] || sink->x[1] > c->loc[1] + c->width[1] ||
+        sink->x[2] < c->loc[2] || sink->x[2] > c->loc[2] + c->width[2])
+      error("sink not sorted into the right top-level cell!");
+  }
+#endif
+
+  /* We need to re-link the gpart partners of sinks. */
+  if (nr_sinks > 0) {
+
+    struct savelink_mapper_data savelink_data;
+    savelink_data.nr_nodes = nr_nodes;
+    savelink_data.counts = sink_counts;
+    savelink_data.parts = (void *)sinks;
+    savelink_data.nodeID = nodeID;
+    threadpool_map(&e->threadpool, engine_redistribute_savelink_mapper_sink,
+                   nodes, nr_nodes, sizeof(int), threadpool_auto_chunk_size,
+                   &savelink_data);
+  }
+  swift_free("sink_dest", sink_dest);
+
   /* Get destination of each g-particle */
   int *g_counts;
   if ((g_counts = (int *)calloc(nr_nodes * nr_nodes, sizeof(int))) == NULL)
@@ -932,22 +1053,30 @@ void engine_redistribute(struct engine *e) {
                     MPI_SUM, MPI_COMM_WORLD) != MPI_SUCCESS)
     error("Failed to allreduce bparticle transfer counts.");
 
+  /* Get all the sink_counts from all the nodes. */
+  if (MPI_Allreduce(MPI_IN_PLACE, sink_counts, nr_nodes * nr_nodes, MPI_INT,
+                    MPI_SUM, MPI_COMM_WORLD) != MPI_SUCCESS)
+    error("Failed to allreduce sink particle transfer counts.");
+
   /* Report how many particles will be moved. */
   if (e->verbose) {
     if (e->nodeID == 0) {
-      size_t total = 0, g_total = 0, s_total = 0, b_total = 0;
-      size_t unmoved = 0, g_unmoved = 0, s_unmoved = 0, b_unmoved = 0;
+      size_t total = 0, g_total = 0, s_total = 0, b_total = 0, sink_total = 0;
+      size_t unmoved = 0, g_unmoved = 0, s_unmoved = 0, b_unmoved = 0,
+             sink_unmoved = 0;
       for (int p = 0, r = 0; p < nr_nodes; p++) {
         for (int n = 0; n < nr_nodes; n++) {
           total += counts[r];
           g_total += g_counts[r];
           s_total += s_counts[r];
           b_total += b_counts[r];
+          sink_total += sink_counts[r];
           if (p == n) {
             unmoved += counts[r];
             g_unmoved += g_counts[r];
             s_unmoved += s_counts[r];
             b_unmoved += b_counts[r];
+            sink_unmoved += sink_counts[r];
           }
           r++;
         }
@@ -967,14 +1096,19 @@ void engine_redistribute(struct engine *e) {
         message("%ld of %ld (%.2f%%) of b-particles moved", b_total - b_unmoved,
                 b_total,
                 100.0 * (double)(b_total - b_unmoved) / (double)b_total);
+      if (sink_total > 0)
+        message(
+            "%ld of %ld (%.2f%%) of sink-particles moved",
+            sink_total - sink_unmoved, sink_total,
+            100.0 * (double)(sink_total - sink_unmoved) / (double)sink_total);
     }
   }
 
-  /* Now each node knows how many parts, sparts, bparts, and gparts will be
-   * transferred to every other node. Get the new numbers of particles for this
-   * node. */
+  /* Now each node knows how many parts, sparts, bparts, sinks and gparts will
+   * be transferred to every other node. Get the new numbers of particles for
+   * this node. */
   size_t nr_parts_new = 0, nr_gparts_new = 0, nr_sparts_new = 0,
-         nr_bparts_new = 0;
+         nr_bparts_new = 0, nr_sinks_new = 0;
   for (int k = 0; k < nr_nodes; k++)
     nr_parts_new += counts[k * nr_nodes + nodeID];
   for (int k = 0; k < nr_nodes; k++)
@@ -983,6 +1117,8 @@ void engine_redistribute(struct engine *e) {
     nr_sparts_new += s_counts[k * nr_nodes + nodeID];
   for (int k = 0; k < nr_nodes; k++)
     nr_bparts_new += b_counts[k * nr_nodes + nodeID];
+  for (int k = 0; k < nr_nodes; k++)
+    nr_sinks_new += sink_counts[k * nr_nodes + nodeID];
 
 #ifdef WITH_CSDS
   const int initial_redistribute = e->ti_current == 0;
@@ -992,6 +1128,7 @@ void engine_redistribute(struct engine *e) {
     size_t spart_offset = 0;
     size_t gpart_offset = 0;
     size_t bpart_offset = 0;
+    size_t sink_offset = 0;
 
     for (int i = 0; i < nr_nodes; i++) {
       const size_t c_ind = engine_rank * nr_nodes + i;
@@ -1002,6 +1139,7 @@ void engine_redistribute(struct engine *e) {
         spart_offset += s_counts[c_ind];
         gpart_offset += g_counts[c_ind];
         bpart_offset += b_counts[c_ind];
+        sink_offset += sink_counts[c_ind];
         continue;
       }
 
@@ -1023,11 +1161,17 @@ void engine_redistribute(struct engine *e) {
         error("TODO");
       }
 
+      /* Log the sinks */
+      if (sink_counts[c_ind] > 0) {
+        error("TODO");
+      }
+
       /* Update the counters */
       part_offset += counts[c_ind];
       spart_offset += s_counts[c_ind];
       gpart_offset += g_counts[c_ind];
       bpart_offset += b_counts[c_ind];
+      sink_offset += sink_counts[c_ind];
     }
   }
 #endif
@@ -1081,6 +1225,15 @@ void engine_redistribute(struct engine *e) {
   s->nr_bparts = nr_bparts_new;
   s->size_bparts = engine_redistribute_alloc_margin * nr_bparts_new;
 
+  /* Sink particles. */
+  new_parts = engine_do_redistribute(
+      "sinks", sink_counts, (char *)s->sinks, nr_sinks_new, sizeof(struct sink),
+      sink_align, sink_mpi_type, nr_nodes, nodeID, e->syncredist);
+  swift_free("sinks", s->sinks);
+  s->sinks = (struct sink *)new_parts;
+  s->nr_sinks = nr_sinks_new;
+  s->size_sinks = engine_redistribute_alloc_margin * nr_sinks_new;
+
   /* All particles have now arrived. Time for some final operations on the
      stuff we just received */
 
@@ -1090,6 +1243,7 @@ void engine_redistribute(struct engine *e) {
     size_t spart_offset = 0;
     size_t gpart_offset = 0;
     size_t bpart_offset = 0;
+    size_t sink_offset = 0;
 
     for (int i = 0; i < nr_nodes; i++) {
       const size_t c_ind = i * nr_nodes + engine_rank;
@@ -1100,6 +1254,7 @@ void engine_redistribute(struct engine *e) {
         spart_offset += s_counts[c_ind];
         gpart_offset += g_counts[c_ind];
         bpart_offset += b_counts[c_ind];
+        sink_offset += sink_counts[c_ind];
         continue;
       }
 
@@ -1121,11 +1276,17 @@ void engine_redistribute(struct engine *e) {
         error("TODO");
       }
 
+      /* Log the sinks */
+      if (sink_counts[c_ind] > 0) {
+        error("TODO");
+      }
+
       /* Update the counters */
       part_offset += counts[c_ind];
       spart_offset += s_counts[c_ind];
       gpart_offset += g_counts[c_ind];
       bpart_offset += b_counts[c_ind];
+      sink_offset += sink_counts[c_ind];
     }
   }
 #endif
@@ -1139,6 +1300,7 @@ void engine_redistribute(struct engine *e) {
   relink_data.g_counts = g_counts;
   relink_data.s_counts = s_counts;
   relink_data.b_counts = b_counts;
+  relink_data.sink_counts = sink_counts;
   relink_data.nodeID = nodeID;
   relink_data.nr_nodes = nr_nodes;
 
@@ -1151,6 +1313,7 @@ void engine_redistribute(struct engine *e) {
   free(g_counts);
   free(s_counts);
   free(b_counts);
+  free(sink_counts);
 
 #ifdef SWIFT_DEBUG_CHECKS
   /* Verify that all parts are in the right place. */
@@ -1186,6 +1349,15 @@ void engine_redistribute(struct engine *e) {
       error("Received b-particle (%zu) that does not belong here (nodeID=%i).",
             k, cells[cid].nodeID);
   }
+  for (size_t k = 0; k < nr_sinks_new; k++) {
+    const int cid = cell_getid(s->cdim, s->sinks[k].x[0] * s->iwidth[0],
+                               s->sinks[k].x[1] * s->iwidth[1],
+                               s->sinks[k].x[2] * s->iwidth[2]);
+    if (cells[cid].nodeID != nodeID)
+      error(
+          "Received sink-particle (%zu) that does not belong here (nodeID=%i).",
+          k, cells[cid].nodeID);
+  }
 
   /* Verify that the links are correct */
   part_verify_links(s->parts, s->gparts, s->sinks, s->sparts, s->bparts,
@@ -1200,10 +1372,11 @@ void engine_redistribute(struct engine *e) {
     for (int k = 0; k < nr_cells; k++)
       if (cells[k].nodeID == nodeID) my_cells += 1;
     message(
-        "node %i now has %zu parts, %zu sparts, %zu bparts and %zu gparts in "
+        "node %i now has %zu parts, %zu sparts, %zu bparts, %zu sinks and %zu "
+        "gparts in "
         "%i cells.",
-        nodeID, nr_parts_new, nr_sparts_new, nr_bparts_new, nr_gparts_new,
-        my_cells);
+        nodeID, nr_parts_new, nr_sparts_new, nr_bparts_new, nr_sinks_new,
+        nr_gparts_new, my_cells);
   }
 
   /* Flag that we do not have any extra particles any more */
@@ -1211,6 +1384,7 @@ void engine_redistribute(struct engine *e) {
   s->nr_extra_gparts = 0;
   s->nr_extra_sparts = 0;
   s->nr_extra_bparts = 0;
+  s->nr_extra_sinks = 0;
 
   /* Flag that a redistribute has taken place */
   e->step_props |= engine_step_prop_redistribute;
diff --git a/src/engine_strays.c b/src/engine_strays.c
index d55909c73e08c5b594d6ab30662f3b6e64d92a25..2ecd2576fcb0091534aaf64e83550eef9d82234e 100644
--- a/src/engine_strays.c
+++ b/src/engine_strays.c
@@ -33,6 +33,13 @@
 /* Local headers. */
 #include "proxy.h"
 
+#ifdef WITH_MPI
+/* Number of particle types to wait for after launching the proxies. We have
+   parts, xparts, gparts, sparts, bparts and sinks to exchange, hence 6 types.
+ */
+#define MPI_REQUEST_NUMBER_PARTICLE_TYPES 6
+#endif
+
 /**
  * @brief Exchange straying particles with other nodes.
  *
@@ -57,18 +64,22 @@
  * @param ind_bpart The foreign #cell ID of each bpart.
  * @param Nbpart The number of stray bparts, contains the number of bparts
  *        received on return.
+ * @param offset_sinks The index in the sinks array as of which the foreign
+ *        parts reside (i.e. the current number of local #sink).
+ * @param ind_sink The foreign #cell ID of each sink.
+ * @param Nsink The number of stray sinks, contains the number of sinks
+ *        received on return.
  *
  * Note that this function does not mess-up the linkage between parts and
  * gparts, i.e. the received particles have correct linkeage.
  */
-void engine_exchange_strays(struct engine *e, const size_t offset_parts,
-                            const int *restrict ind_part, size_t *Npart,
-                            const size_t offset_gparts,
-                            const int *restrict ind_gpart, size_t *Ngpart,
-                            const size_t offset_sparts,
-                            const int *restrict ind_spart, size_t *Nspart,
-                            const size_t offset_bparts,
-                            const int *restrict ind_bpart, size_t *Nbpart) {
+void engine_exchange_strays(
+    struct engine *e, const size_t offset_parts, const int *restrict ind_part,
+    size_t *Npart, const size_t offset_gparts, const int *restrict ind_gpart,
+    size_t *Ngpart, const size_t offset_sparts, const int *restrict ind_spart,
+    size_t *Nspart, const size_t offset_bparts, const int *restrict ind_bpart,
+    size_t *Nbpart, const size_t offset_sinks, const int *restrict ind_sink,
+    size_t *Nsink) {
 
 #ifdef WITH_MPI
   struct space *s = e->s;
@@ -80,6 +91,7 @@ void engine_exchange_strays(struct engine *e, const size_t offset_parts,
     e->proxies[k].nr_gparts_out = 0;
     e->proxies[k].nr_sparts_out = 0;
     e->proxies[k].nr_bparts_out = 0;
+    e->proxies[k].nr_sinks_out = 0;
   }
 
   /* Put the parts into the corresponding proxies. */
@@ -204,6 +216,46 @@ void engine_exchange_strays(struct engine *e, const size_t offset_parts,
     /* Load the bpart into the proxy */
     proxy_bparts_load(&e->proxies[pid], &s->bparts[offset_bparts + k], 1);
 
+#ifdef WITH_CSDS
+    if (e->policy & engine_policy_csds) {
+      error("Not yet implemented.");
+    }
+#endif
+  }
+
+  /* Put the sinks into the corresponding proxies. */
+  for (size_t k = 0; k < *Nsink; k++) {
+    /* Ignore the particles we want to get rid of (inhibited, ...). */
+    if (ind_sink[k] == -1) continue;
+
+    /* Get the target node and proxy ID. */
+    const int node_id = e->s->cells_top[ind_sink[k]].nodeID;
+    if (node_id < 0 || node_id >= e->nr_nodes)
+      error("Bad node ID %i.", node_id);
+    const int pid = e->proxy_ind[node_id];
+    if (pid < 0) {
+      error(
+          "Do not have a proxy for the requested nodeID %i for part with "
+          "id=%lld, x=[%e,%e,%e].",
+          node_id, s->sinks[offset_sinks + k].id,
+          s->sinks[offset_sinks + k].x[0], s->sinks[offset_sinks + k].x[1],
+          s->sinks[offset_sinks + k].x[2]);
+    }
+
+    /* Re-link the associated gpart with the buffer offset of the sink. */
+    if (s->sinks[offset_sinks + k].gpart != NULL) {
+      s->sinks[offset_sinks + k].gpart->id_or_neg_offset =
+          -e->proxies[pid].nr_sinks_out;
+    }
+
+#ifdef SWIFT_DEBUG_CHECKS
+    if (s->sinks[offset_sinks + k].time_bin == time_bin_inhibited)
+      error("Attempting to exchange an inhibited particle");
+#endif
+
+    /* Load the sink into the proxy */
+    proxy_sinks_load(&e->proxies[pid], &s->sinks[offset_sinks + k], 1);
+
 #ifdef WITH_CSDS
     if (e->policy & engine_policy_csds) {
       error("Not yet implemented.");
@@ -252,8 +304,8 @@ void engine_exchange_strays(struct engine *e, const size_t offset_parts,
   }
 
   /* Launch the proxies. */
-  MPI_Request reqs_in[5 * engine_maxproxies];
-  MPI_Request reqs_out[5 * engine_maxproxies];
+  MPI_Request reqs_in[MPI_REQUEST_NUMBER_PARTICLE_TYPES * engine_maxproxies];
+  MPI_Request reqs_out[MPI_REQUEST_NUMBER_PARTICLE_TYPES * engine_maxproxies];
   for (int k = 0; k < e->nr_proxies; k++) {
     proxy_parts_exchange_first(&e->proxies[k]);
     reqs_in[k] = e->proxies[k].req_parts_count_in;
@@ -281,18 +333,23 @@ void engine_exchange_strays(struct engine *e, const size_t offset_parts,
   int count_gparts_in = 0;
   int count_sparts_in = 0;
   int count_bparts_in = 0;
+  int count_sinks_in = 0;
   for (int k = 0; k < e->nr_proxies; k++) {
     count_parts_in += e->proxies[k].nr_parts_in;
     count_gparts_in += e->proxies[k].nr_gparts_in;
     count_sparts_in += e->proxies[k].nr_sparts_in;
     count_bparts_in += e->proxies[k].nr_bparts_in;
+    count_sinks_in += e->proxies[k].nr_sinks_in;
+    message("Counting entering particles, k = %i, nr_proxies = %d", k,
+            e->nr_proxies);
   }
   if (e->verbose) {
     message(
-        "sent out %zu/%zu/%zu/%zu parts/gparts/sparts/bparts, got %i/%i/%i/%i "
+        "sent out %zu/%zu/%zu/%zu/%zu parts/gparts/sparts/bparts/sinks, got "
+        "%i/%i/%i/%i/%i "
         "back.",
-        *Npart, *Ngpart, *Nspart, *Nbpart, count_parts_in, count_gparts_in,
-        count_sparts_in, count_bparts_in);
+        *Npart, *Ngpart, *Nspart, *Nbpart, *Nsink, count_parts_in,
+        count_gparts_in, count_sparts_in, count_bparts_in, count_sinks_in);
   }
 
   /* Reallocate the particle arrays if necessary */
@@ -356,6 +413,24 @@ void engine_exchange_strays(struct engine *e, const size_t offset_parts,
     }
   }
 
+  if (offset_sinks + count_sinks_in > s->size_sinks) {
+    s->size_sinks = (offset_sinks + count_sinks_in) * engine_parts_size_grow;
+    struct sink *sinks_new = NULL;
+    if (swift_memalign("sinks", (void **)&sinks_new, sink_align,
+                       sizeof(struct sink) * s->size_sinks) != 0)
+      error("Failed to allocate new sink data.");
+    memcpy(sinks_new, s->sinks, sizeof(struct sink) * offset_sinks);
+    swift_free("sinks", s->sinks);
+    s->sinks = sinks_new;
+
+    /* Reset the links */
+    for (size_t k = 0; k < offset_sinks; k++) {
+      if (s->sinks[k].gpart != NULL) {
+        s->sinks[k].gpart->id_or_neg_offset = -k;
+      }
+    }
+  }
+
   if (offset_gparts + count_gparts_in > s->size_gparts) {
     s->size_gparts = (offset_gparts + count_gparts_in) * engine_parts_size_grow;
     struct gpart *gparts_new = NULL;
@@ -374,6 +449,8 @@ void engine_exchange_strays(struct engine *e, const size_t offset_parts,
         s->sparts[-s->gparts[k].id_or_neg_offset].gpart = &s->gparts[k];
       } else if (s->gparts[k].type == swift_type_black_hole) {
         s->bparts[-s->gparts[k].id_or_neg_offset].gpart = &s->gparts[k];
+      } else if (s->gparts[k].type == swift_type_sink) {
+        s->sinks[-s->gparts[k].id_or_neg_offset].gpart = &s->gparts[k];
       }
     }
   }
@@ -382,82 +459,113 @@ void engine_exchange_strays(struct engine *e, const size_t offset_parts,
   int nr_in = 0, nr_out = 0;
   for (int k = 0; k < e->nr_proxies; k++) {
     if (e->proxies[k].nr_parts_in > 0) {
-      reqs_in[5 * k] = e->proxies[k].req_parts_in;
-      reqs_in[5 * k + 1] = e->proxies[k].req_xparts_in;
+      reqs_in[MPI_REQUEST_NUMBER_PARTICLE_TYPES * k] =
+          e->proxies[k].req_parts_in;
+      reqs_in[MPI_REQUEST_NUMBER_PARTICLE_TYPES * k + 1] =
+          e->proxies[k].req_xparts_in;
       nr_in += 2;
     } else {
-      reqs_in[5 * k] = reqs_in[5 * k + 1] = MPI_REQUEST_NULL;
+      reqs_in[MPI_REQUEST_NUMBER_PARTICLE_TYPES * k] =
+          reqs_in[MPI_REQUEST_NUMBER_PARTICLE_TYPES * k + 1] = MPI_REQUEST_NULL;
     }
     if (e->proxies[k].nr_gparts_in > 0) {
-      reqs_in[5 * k + 2] = e->proxies[k].req_gparts_in;
+      reqs_in[MPI_REQUEST_NUMBER_PARTICLE_TYPES * k + 2] =
+          e->proxies[k].req_gparts_in;
       nr_in += 1;
     } else {
-      reqs_in[5 * k + 2] = MPI_REQUEST_NULL;
+      reqs_in[MPI_REQUEST_NUMBER_PARTICLE_TYPES * k + 2] = MPI_REQUEST_NULL;
     }
     if (e->proxies[k].nr_sparts_in > 0) {
-      reqs_in[5 * k + 3] = e->proxies[k].req_sparts_in;
+      reqs_in[MPI_REQUEST_NUMBER_PARTICLE_TYPES * k + 3] =
+          e->proxies[k].req_sparts_in;
       nr_in += 1;
     } else {
-      reqs_in[5 * k + 3] = MPI_REQUEST_NULL;
+      reqs_in[MPI_REQUEST_NUMBER_PARTICLE_TYPES * k + 3] = MPI_REQUEST_NULL;
     }
     if (e->proxies[k].nr_bparts_in > 0) {
-      reqs_in[5 * k + 4] = e->proxies[k].req_bparts_in;
+      reqs_in[MPI_REQUEST_NUMBER_PARTICLE_TYPES * k + 4] =
+          e->proxies[k].req_bparts_in;
+      nr_in += 1;
+    } else {
+      reqs_in[MPI_REQUEST_NUMBER_PARTICLE_TYPES * k + 4] = MPI_REQUEST_NULL;
+    }
+    if (e->proxies[k].nr_sinks_in > 0) {
+      reqs_in[MPI_REQUEST_NUMBER_PARTICLE_TYPES * k + 5] =
+          e->proxies[k].req_sinks_in;
       nr_in += 1;
     } else {
-      reqs_in[5 * k + 4] = MPI_REQUEST_NULL;
+      reqs_in[MPI_REQUEST_NUMBER_PARTICLE_TYPES * k + 5] = MPI_REQUEST_NULL;
     }
 
     if (e->proxies[k].nr_parts_out > 0) {
-      reqs_out[5 * k] = e->proxies[k].req_parts_out;
-      reqs_out[5 * k + 1] = e->proxies[k].req_xparts_out;
+      reqs_out[MPI_REQUEST_NUMBER_PARTICLE_TYPES * k] =
+          e->proxies[k].req_parts_out;
+      reqs_out[MPI_REQUEST_NUMBER_PARTICLE_TYPES * k + 1] =
+          e->proxies[k].req_xparts_out;
       nr_out += 2;
     } else {
-      reqs_out[5 * k] = reqs_out[5 * k + 1] = MPI_REQUEST_NULL;
+      reqs_out[MPI_REQUEST_NUMBER_PARTICLE_TYPES * k] =
+          reqs_out[MPI_REQUEST_NUMBER_PARTICLE_TYPES * k + 1] =
+              MPI_REQUEST_NULL;
     }
     if (e->proxies[k].nr_gparts_out > 0) {
-      reqs_out[5 * k + 2] = e->proxies[k].req_gparts_out;
+      reqs_out[MPI_REQUEST_NUMBER_PARTICLE_TYPES * k + 2] =
+          e->proxies[k].req_gparts_out;
       nr_out += 1;
     } else {
-      reqs_out[5 * k + 2] = MPI_REQUEST_NULL;
+      reqs_out[MPI_REQUEST_NUMBER_PARTICLE_TYPES * k + 2] = MPI_REQUEST_NULL;
     }
     if (e->proxies[k].nr_sparts_out > 0) {
-      reqs_out[5 * k + 3] = e->proxies[k].req_sparts_out;
+      reqs_out[MPI_REQUEST_NUMBER_PARTICLE_TYPES * k + 3] =
+          e->proxies[k].req_sparts_out;
       nr_out += 1;
     } else {
-      reqs_out[5 * k + 3] = MPI_REQUEST_NULL;
+      reqs_out[MPI_REQUEST_NUMBER_PARTICLE_TYPES * k + 3] = MPI_REQUEST_NULL;
     }
     if (e->proxies[k].nr_bparts_out > 0) {
-      reqs_out[5 * k + 4] = e->proxies[k].req_bparts_out;
+      reqs_out[MPI_REQUEST_NUMBER_PARTICLE_TYPES * k + 4] =
+          e->proxies[k].req_bparts_out;
       nr_out += 1;
     } else {
-      reqs_out[5 * k + 4] = MPI_REQUEST_NULL;
+      reqs_out[MPI_REQUEST_NUMBER_PARTICLE_TYPES * k + 4] = MPI_REQUEST_NULL;
+    }
+    if (e->proxies[k].nr_sinks_out > 0) {
+      reqs_out[MPI_REQUEST_NUMBER_PARTICLE_TYPES * k + 5] =
+          e->proxies[k].req_sinks_out;
+      nr_out += 1;
+    } else {
+      reqs_out[MPI_REQUEST_NUMBER_PARTICLE_TYPES * k + 5] = MPI_REQUEST_NULL;
     }
   }
 
   /* Wait for each part array to come in and collect the new
      parts from the proxies. */
-  int count_parts = 0, count_gparts = 0, count_sparts = 0, count_bparts = 0;
+  int count_parts = 0, count_gparts = 0, count_sparts = 0, count_bparts = 0,
+      count_sinks = 0;
   for (int k = 0; k < nr_in; k++) {
     int err, pid;
-    if ((err = MPI_Waitany(5 * e->nr_proxies, reqs_in, &pid,
-                           MPI_STATUS_IGNORE)) != MPI_SUCCESS) {
+    if ((err = MPI_Waitany(MPI_REQUEST_NUMBER_PARTICLE_TYPES * e->nr_proxies,
+                           reqs_in, &pid, MPI_STATUS_IGNORE)) != MPI_SUCCESS) {
       char buff[MPI_MAX_ERROR_STRING];
       int res;
       MPI_Error_string(err, buff, &res);
       error("MPI_Waitany failed (%s).", buff);
     }
     if (pid == MPI_UNDEFINED) break;
-    // message( "request from proxy %i has arrived." , pid / 5 );
-    pid = 5 * (pid / 5);
+    // message( "request from proxy %i has arrived." , pid /
+    // MPI_REQUEST_NUMBER_PARTICLE_TYPES );
+    pid = MPI_REQUEST_NUMBER_PARTICLE_TYPES *
+          (pid / MPI_REQUEST_NUMBER_PARTICLE_TYPES);
 
     /* If all the requests for a given proxy have arrived... */
     if (reqs_in[pid + 0] == MPI_REQUEST_NULL &&
         reqs_in[pid + 1] == MPI_REQUEST_NULL &&
         reqs_in[pid + 2] == MPI_REQUEST_NULL &&
         reqs_in[pid + 3] == MPI_REQUEST_NULL &&
-        reqs_in[pid + 4] == MPI_REQUEST_NULL) {
+        reqs_in[pid + 4] == MPI_REQUEST_NULL &&
+        reqs_in[pid + 5] == MPI_REQUEST_NULL) {
       /* Copy the particle data to the part/xpart/gpart arrays. */
-      struct proxy *prox = &e->proxies[pid / 5];
+      struct proxy *prox = &e->proxies[pid / MPI_REQUEST_NUMBER_PARTICLE_TYPES];
       memcpy(&s->parts[offset_parts + count_parts], prox->parts_in,
              sizeof(struct part) * prox->nr_parts_in);
       memcpy(&s->xparts[offset_parts + count_parts], prox->xparts_in,
@@ -468,6 +576,8 @@ void engine_exchange_strays(struct engine *e, const size_t offset_parts,
              sizeof(struct spart) * prox->nr_sparts_in);
       memcpy(&s->bparts[offset_bparts + count_bparts], prox->bparts_in,
              sizeof(struct bpart) * prox->nr_bparts_in);
+      memcpy(&s->sinks[offset_sinks + count_sinks], prox->sinks_in,
+             sizeof(struct sink) * prox->nr_sinks_in);
 
 #ifdef WITH_CSDS
       if (e->policy & engine_policy_csds) {
@@ -495,6 +605,12 @@ void engine_exchange_strays(struct engine *e, const size_t offset_parts,
         if (prox->nr_bparts_in > 0) {
           error("TODO");
         }
+
+        /* Log the sinks */
+        if (prox->nr_sinks_in > 0) {
+          /* Not implemented yet */
+          error("TODO");
+        }
       }
 #endif
       /* for (int k = offset; k < offset + count; k++)
@@ -522,6 +638,11 @@ void engine_exchange_strays(struct engine *e, const size_t offset_parts,
               &s->bparts[offset_bparts + count_bparts - gp->id_or_neg_offset];
           gp->id_or_neg_offset = s->bparts - bp;
           bp->gpart = gp;
+        } else if (gp->type == swift_type_sink) {
+          struct sink *sink =
+              &s->sinks[offset_sinks + count_sinks - gp->id_or_neg_offset];
+          gp->id_or_neg_offset = s->sinks - sink;
+          sink->gpart = gp;
         }
       }
 
@@ -530,13 +651,14 @@ void engine_exchange_strays(struct engine *e, const size_t offset_parts,
       count_gparts += prox->nr_gparts_in;
       count_sparts += prox->nr_sparts_in;
       count_bparts += prox->nr_bparts_in;
+      count_sinks += prox->nr_sinks_in;
     }
   }
 
   /* Wait for all the sends to have finished too. */
   if (nr_out > 0)
-    if (MPI_Waitall(5 * e->nr_proxies, reqs_out, MPI_STATUSES_IGNORE) !=
-        MPI_SUCCESS)
+    if (MPI_Waitall(MPI_REQUEST_NUMBER_PARTICLE_TYPES * e->nr_proxies, reqs_out,
+                    MPI_STATUSES_IGNORE) != MPI_SUCCESS)
       error("MPI_Waitall on sends failed.");
 
   /* Free the proxy memory */
@@ -553,6 +675,7 @@ void engine_exchange_strays(struct engine *e, const size_t offset_parts,
   *Ngpart = count_gparts;
   *Nspart = count_sparts;
   *Nbpart = count_bparts;
+  *Nsink = count_sinks;
 
 #else
   error("SWIFT was not compiled with MPI support.");
diff --git a/src/feedback/GEAR/feedback.c b/src/feedback/GEAR/feedback.c
index 46dfc6dea1ced3d51dc7eea992f1ea3c3657ad98..204477d474612d95419117d6d745844454c4330a 100644
--- a/src/feedback/GEAR/feedback.c
+++ b/src/feedback/GEAR/feedback.c
@@ -21,6 +21,7 @@
 #include "feedback.h"
 
 /* Local includes */
+#include "cooling.h"
 #include "cosmology.h"
 #include "engine.h"
 #include "error.h"
@@ -49,7 +50,7 @@ void feedback_update_part(struct part* p, struct xpart* xp,
   const struct pressure_floor_props* pressure_floor = e->pressure_floor_props;
 
   /* Turn off the cooling */
-  xp->cooling_data.time_last_event = e->time;
+  cooling_set_part_time_cooling_off(p, xp, e->time);
 
   /* Update mass */
   const float old_mass = hydro_get_mass(p);
diff --git a/src/part.c b/src/part.c
index 9d9c38f577f8675d7cb9367a2227bce689b892f0..f513153d61ba9b277a0b6b88ae9e4cf61c766e10 100644
--- a/src/part.c
+++ b/src/part.c
@@ -544,6 +544,7 @@ MPI_Datatype xpart_mpi_type;
 MPI_Datatype gpart_mpi_type;
 MPI_Datatype spart_mpi_type;
 MPI_Datatype bpart_mpi_type;
+MPI_Datatype sink_mpi_type;
 
 /**
  * @brief Registers MPI particle types.
@@ -581,6 +582,11 @@ void part_create_mpi_types(void) {
       MPI_Type_commit(&bpart_mpi_type) != MPI_SUCCESS) {
     error("Failed to create MPI type for bparts.");
   }
+  if (MPI_Type_contiguous(sizeof(struct sink) / sizeof(unsigned char), MPI_BYTE,
+                          &sink_mpi_type) != MPI_SUCCESS ||
+      MPI_Type_commit(&sink_mpi_type) != MPI_SUCCESS) {
+    error("Failed to create MPI type for sink.");
+  }
 }
 
 void part_free_mpi_types(void) {
@@ -590,5 +596,6 @@ void part_free_mpi_types(void) {
   MPI_Type_free(&gpart_mpi_type);
   MPI_Type_free(&spart_mpi_type);
   MPI_Type_free(&bpart_mpi_type);
+  MPI_Type_free(&sink_mpi_type);
 }
 #endif
diff --git a/src/part.h b/src/part.h
index b8fc625885a9f329633bc39476ecb7aac2228b79..c0e87bfde7c6525b7cdc05974d56fa4bb5be5bd9 100644
--- a/src/part.h
+++ b/src/part.h
@@ -171,6 +171,7 @@ extern MPI_Datatype xpart_mpi_type;
 extern MPI_Datatype gpart_mpi_type;
 extern MPI_Datatype spart_mpi_type;
 extern MPI_Datatype bpart_mpi_type;
+extern MPI_Datatype sink_mpi_type;
 
 void part_create_mpi_types(void);
 void part_free_mpi_types(void);
diff --git a/src/proxy.c b/src/proxy.c
index 22663d42a70c75b3966d0272d93a294480057b0b..3830162ada2135d28c68b3763661a18e17bcbab0 100644
--- a/src/proxy.c
+++ b/src/proxy.c
@@ -705,12 +705,24 @@ void proxy_parts_exchange_first(struct proxy *p) {
   p->buff_out[1] = p->nr_gparts_out;
   p->buff_out[2] = p->nr_sparts_out;
   p->buff_out[3] = p->nr_bparts_out;
-  if (MPI_Isend(p->buff_out, 4, MPI_INT, p->nodeID,
-                p->mynodeID * proxy_tag_shift + proxy_tag_count, MPI_COMM_WORLD,
-                &p->req_parts_count_out) != MPI_SUCCESS)
+  p->buff_out[4] = p->nr_sinks_out;
+
+#ifdef SWIFT_DEBUG_CHECKS
+  message("Number of particles out [%i , %i, %i, %i, %i]", p->nr_parts_out,
+          p->nr_gparts_out, p->nr_sparts_out, p->nr_bparts_out,
+          p->nr_sinks_out);
+#endif /* SWIFT_DEBUG_CHECKS */
+
+  if (MPI_Isend(p->buff_out, PROXY_EXCHANGE_NUMBER_PARTICLE_TYPES, MPI_INT,
+                p->nodeID, p->mynodeID * proxy_tag_shift + proxy_tag_count,
+                MPI_COMM_WORLD, &p->req_parts_count_out) != MPI_SUCCESS)
     error("Failed to isend nr of parts.");
-  /* message( "isent particle counts [%i, %i] from node %i to node %i." ,
-  p->buff_out[0], p->buff_out[1], p->mynodeID , p->nodeID ); fflush(stdout); */
+#ifdef SWIFT_DEBUG_CHECKS
+  message("isent particle counts [%i, %i, %i, %i, %i] from node %i to node %i.",
+          p->buff_out[0], p->buff_out[1], p->buff_out[2], p->buff_out[3],
+          p->buff_out[4], p->mynodeID, p->nodeID);
+  fflush(stdout);
+#endif /* SWIFT_DEBUG_CHECKS */
 
   /* Send the particle buffers. */
   if (p->nr_parts_out > 0) {
@@ -721,20 +733,28 @@ void proxy_parts_exchange_first(struct proxy *p) {
                   p->mynodeID * proxy_tag_shift + proxy_tag_xparts,
                   MPI_COMM_WORLD, &p->req_xparts_out) != MPI_SUCCESS)
       error("Failed to isend part data.");
-    // message( "isent particle data (%i) to node %i." , p->nr_parts_out ,
-    // p->nodeID ); fflush(stdout);
-    /*for (int k = 0; k < p->nr_parts_out; k++)
+#ifdef SWIFT_DEBUG_CHECKS
+    message("isent particle data (%i) to node %i.", p->nr_parts_out, p->nodeID);
+    fflush(stdout);
+    for (int k = 0; k < p->nr_parts_out; k++)
       message("sending particle %lli, x=[%.3e %.3e %.3e], h=%.3e, to node %i.",
               p->parts_out[k].id, p->parts_out[k].x[0], p->parts_out[k].x[1],
-              p->parts_out[k].x[2], p->parts_out[k].h, p->nodeID);*/
+              p->parts_out[k].x[2], p->parts_out[k].h, p->nodeID);
+#endif /* SWIFT_DEBUG_CHECKS */
   }
   if (p->nr_gparts_out > 0) {
     if (MPI_Isend(p->gparts_out, p->nr_gparts_out, gpart_mpi_type, p->nodeID,
                   p->mynodeID * proxy_tag_shift + proxy_tag_gparts,
                   MPI_COMM_WORLD, &p->req_gparts_out) != MPI_SUCCESS)
       error("Failed to isend gpart data.");
-    // message( "isent gpart data (%i) to node %i." , p->nr_gparts_out ,
-    // p->nodeID ); fflush(stdout);
+#ifdef SWIFT_DEBUG_CHECKS
+    message("isent gpart data (%i) to node %i.", p->nr_gparts_out, p->nodeID);
+    fflush(stdout);
+    for (int k = 0; k < p->nr_parts_out; k++)
+      message("sending gpart %lli, x=[%.3e %.3e %.3e], to node %i.",
+              p->gparts_out[k].id_or_neg_offset, p->gparts_out[k].x[0],
+              p->gparts_out[k].x[1], p->gparts_out[k].x[2], p->nodeID);
+#endif /* SWIFT_DEBUG_CHECKS */
   }
 
   if (p->nr_sparts_out > 0) {
@@ -742,23 +762,56 @@ void proxy_parts_exchange_first(struct proxy *p) {
                   p->mynodeID * proxy_tag_shift + proxy_tag_sparts,
                   MPI_COMM_WORLD, &p->req_sparts_out) != MPI_SUCCESS)
       error("Failed to isend spart data.");
-    // message( "isent spart data (%i) to node %i." , p->nr_sparts_out ,
-    // p->nodeID ); fflush(stdout);
+#ifdef SWIFT_DEBUG_CHECKS
+    message("isent spart data (%i) to node %i.", p->nr_sparts_out, p->nodeID);
+    fflush(stdout);
+    for (int k = 0; k < p->nr_sparts_out; k++)
+      message("sending spart %lli, x=[%.3e %.3e %.3e], h=%.3e, to node %i.",
+              p->sparts_out[k].id, p->sparts_out[k].x[0], p->sparts_out[k].x[1],
+              p->sparts_out[k].x[2], p->sparts_out[k].h, p->nodeID);
+#endif /* SWIFT_DEBUG_CHECKS */
   }
   if (p->nr_bparts_out > 0) {
     if (MPI_Isend(p->bparts_out, p->nr_bparts_out, bpart_mpi_type, p->nodeID,
                   p->mynodeID * proxy_tag_shift + proxy_tag_bparts,
                   MPI_COMM_WORLD, &p->req_bparts_out) != MPI_SUCCESS)
       error("Failed to isend bpart data.");
-    // message( "isent bpart data (%i) to node %i." , p->nr_bparts_out ,
-    // p->nodeID ); fflush(stdout);
+#ifdef SWIFT_DEBUG_CHECKS
+    message("isent bpart data (%i) to node %i.", p->nr_bparts_out, p->nodeID);
+    fflush(stdout);
+    for (int k = 0; k < p->nr_bparts_out; k++)
+      message("sending bpart %lli, x=[%.3e %.3e %.3e], h=%.3e, to node %i.",
+              p->bparts_out[k].id, p->bparts_out[k].x[0], p->bparts_out[k].x[1],
+              p->bparts_out[k].x[2], p->bparts_out[k].h, p->nodeID);
+#endif /* SWIFT_DEBUG_CHECKS */
+  }
+  if (p->nr_sinks_out > 0) {
+    if (MPI_Isend(p->sinks_out, p->nr_sinks_out, sink_mpi_type, p->nodeID,
+                  p->mynodeID * proxy_tag_shift + proxy_tag_sinks,
+                  MPI_COMM_WORLD, &p->req_sinks_out) != MPI_SUCCESS)
+      error("Failed to isend sink data.");
+#ifdef SWIFT_DEBUG_CHECKS
+    message("isent sink data (%i) to node %i.", p->nr_sinks_out, p->nodeID);
+    fflush(stdout);
+    for (int k = 0; k < p->nr_sinks_out; k++)
+      message("sending sinks %lli, x=[%.3e %.3e %.3e], h=%.3e, to node %i.",
+              p->sinks_out[k].id, p->sinks_out[k].x[0], p->sinks_out[k].x[1],
+              p->sinks_out[k].x[2], p->sinks_out[k].r_cut, p->nodeID);
+#endif /* SWIFT_DEBUG_CHECKS */
   }
 
   /* Receive the number of particles. */
-  if (MPI_Irecv(p->buff_in, 4, MPI_INT, p->nodeID,
-                p->nodeID * proxy_tag_shift + proxy_tag_count, MPI_COMM_WORLD,
-                &p->req_parts_count_in) != MPI_SUCCESS)
+  if (MPI_Irecv(p->buff_in, PROXY_EXCHANGE_NUMBER_PARTICLE_TYPES, MPI_INT,
+                p->nodeID, p->nodeID * proxy_tag_shift + proxy_tag_count,
+                MPI_COMM_WORLD, &p->req_parts_count_in) != MPI_SUCCESS)
     error("Failed to irecv nr of parts.");
+#ifdef SWIFT_DEBUG_CHECKS
+  message(
+      "irecv particle counts [%i, %i, %i, %i, %i] from node %i, I am node %i.",
+      p->buff_in[0], p->buff_in[1], p->buff_in[2], p->buff_in[3], p->buff_in[4],
+      p->nodeID, p->mynodeID);
+  fflush(stdout);
+#endif /* SWIFT_DEBUG_CHECKS */
 
 #else
   error("SWIFT was not compiled with MPI support.");
@@ -774,6 +827,7 @@ void proxy_parts_exchange_second(struct proxy *p) {
   p->nr_gparts_in = p->buff_in[1];
   p->nr_sparts_in = p->buff_in[2];
   p->nr_bparts_in = p->buff_in[3];
+  p->nr_sinks_in = p->buff_in[4];
 
   /* Is there enough space in the buffers? */
   if (p->nr_parts_in > p->size_parts_in) {
@@ -815,6 +869,15 @@ void proxy_parts_exchange_second(struct proxy *p) {
              "bparts_in", sizeof(struct bpart) * p->size_bparts_in)) == NULL)
       error("Failed to re-allocate bparts_in buffers.");
   }
+  if (p->nr_sinks_in > p->size_sinks_in) {
+    do {
+      p->size_sinks_in *= proxy_buffgrow;
+    } while (p->nr_sinks_in > p->size_sinks_in);
+    swift_free("sinks_in", p->sinks_in);
+    if ((p->sinks_in = (struct sink *)swift_malloc(
+             "sinks_in", sizeof(struct sink) * p->size_sinks_in)) == NULL)
+      error("Failed to re-allocate sinks_in buffers.");
+  }
 
   /* Receive the particle buffers. */
   if (p->nr_parts_in > 0) {
@@ -825,32 +888,73 @@ void proxy_parts_exchange_second(struct proxy *p) {
                   p->nodeID * proxy_tag_shift + proxy_tag_xparts,
                   MPI_COMM_WORLD, &p->req_xparts_in) != MPI_SUCCESS)
       error("Failed to irecv part data.");
-    // message( "irecv particle data (%i) from node %i." , p->nr_parts_in ,
-    // p->nodeID ); fflush(stdout);
+#ifdef SWIFT_DEBUG_CHECKS
+    message("irecv particle data (%i) from node %i.", p->nr_parts_in,
+            p->nodeID);
+    fflush(stdout);
+    for (int k = 0; k < p->nr_parts_in; k++)
+      message("receiving parts %lli, x=[%.3e %.3e %.3e], h=%.3e, from node %i.",
+              p->parts_in[k].id, p->parts_in[k].x[0], p->parts_in[k].x[1],
+              p->parts_in[k].x[2], p->parts_in[k].h, p->nodeID);
+#endif /* SWIFT_DEBUG_CHECKS */
   }
   if (p->nr_gparts_in > 0) {
     if (MPI_Irecv(p->gparts_in, p->nr_gparts_in, gpart_mpi_type, p->nodeID,
                   p->nodeID * proxy_tag_shift + proxy_tag_gparts,
                   MPI_COMM_WORLD, &p->req_gparts_in) != MPI_SUCCESS)
       error("Failed to irecv gpart data.");
-    // message( "irecv gpart data (%i) from node %i." , p->nr_gparts_in ,
-    // p->nodeID ); fflush(stdout);
+#ifdef SWIFT_DEBUG_CHECKS
+    message("irecv gpart data (%i) from node %i.", p->nr_gparts_in, p->nodeID);
+    fflush(stdout);
+    for (int k = 0; k < p->nr_gparts_in; k++)
+      message("receiving gparts %lli, x=[%.3e %.3e %.3e], from node %i.",
+              p->gparts_in[k].id_or_neg_offset, p->gparts_in[k].x[0],
+              p->gparts_in[k].x[1], p->gparts_in[k].x[2], p->nodeID);
+#endif /* SWIFT_DEBUG_CHECKS */
   }
   if (p->nr_sparts_in > 0) {
     if (MPI_Irecv(p->sparts_in, p->nr_sparts_in, spart_mpi_type, p->nodeID,
                   p->nodeID * proxy_tag_shift + proxy_tag_sparts,
                   MPI_COMM_WORLD, &p->req_sparts_in) != MPI_SUCCESS)
       error("Failed to irecv spart data.");
-    // message( "irecv spart data (%i) from node %i." , p->nr_sparts_in ,
-    // p->nodeID ); fflush(stdout);
+#ifdef SWIFT_DEBUG_CHECKS
+    message("irecv spart data (%i) from node %i.", p->nr_sparts_in, p->nodeID);
+    fflush(stdout);
+    for (int k = 0; k < p->nr_sparts_in; k++)
+      message(
+          "receiving sparts %lli, x=[%.3e %.3e %.3e], h=%.3e, from node %i.",
+          p->sparts_in[k].id, p->sparts_in[k].x[0], p->sparts_in[k].x[1],
+          p->sparts_in[k].x[2], p->sparts_in[k].h, p->nodeID);
+#endif
   }
   if (p->nr_bparts_in > 0) {
     if (MPI_Irecv(p->bparts_in, p->nr_bparts_in, bpart_mpi_type, p->nodeID,
                   p->nodeID * proxy_tag_shift + proxy_tag_bparts,
                   MPI_COMM_WORLD, &p->req_bparts_in) != MPI_SUCCESS)
       error("Failed to irecv bpart data.");
-    // message( "irecv bpart data (%i) from node %i." , p->nr_bparts_in ,
-    // p->nodeID ); fflush(stdout);
+#ifdef SWIFT_DEBUG_CHECKS
+    message("irecv bpart data (%i) from node %i.", p->nr_bparts_in, p->nodeID);
+    fflush(stdout);
+    for (int k = 0; k < p->nr_bparts_in; k++)
+      message(
+          "receiving bparts %lli, x=[%.3e %.3e %.3e], h=%.3e, from node %i.",
+          p->bparts_in[k].id, p->bparts_in[k].x[0], p->bparts_in[k].x[1],
+          p->bparts_in[k].x[2], p->bparts_in[k].h, p->nodeID);
+#endif /* SWIFT_DEBUG_CHECKS */
+  }
+  if (p->nr_sinks_in > 0) {
+    if (MPI_Irecv(p->sinks_in, p->nr_sinks_in, sink_mpi_type, p->nodeID,
+                  p->nodeID * proxy_tag_shift + proxy_tag_sinks, MPI_COMM_WORLD,
+                  &p->req_sinks_in) != MPI_SUCCESS)
+      error("Failed to irecv sink data.");
+#ifdef SWIFT_DEBUG_CHECKS
+    message("irecv sink data (%i) from node %i.", p->nr_sinks_in, p->nodeID);
+    fflush(stdout);
+    for (int k = 0; k < p->nr_sinks_in; k++)
+      message("receiving sinks %lli, x=[%.3e %.3e %.3e], h=%.3e, from node %i.",
+              p->sinks_in[k].id, p->sinks_in[k].x[0], p->sinks_in[k].x[1],
+              p->sinks_in[k].x[2], p->sinks_in[k].r_cut, p->nodeID);
+#endif /* SWIFT_DEBUG_CHECKS */
   }
 
 #else
@@ -987,6 +1091,36 @@ void proxy_bparts_load(struct proxy *p, const struct bpart *bparts, int N) {
   p->nr_bparts_out += N;
 }
 
+/**
+ * @brief Load sinks onto a proxy for exchange.
+ *
+ * @param p The #proxy.
+ * @param sinks Pointer to an array of #sink to send.
+ * @param N The number of sinks.
+ */
+void proxy_sinks_load(struct proxy *p, const struct sink *sinks, int N) {
+
+  /* Is there enough space in the buffer? */
+  if (p->nr_sinks_out + N > p->size_sinks_out) {
+    do {
+      p->size_sinks_out *= proxy_buffgrow;
+    } while (p->nr_sinks_out + N > p->size_sinks_out);
+    struct sink *tp;
+    if ((tp = (struct sink *)swift_malloc(
+             "sinks_out", sizeof(struct sink) * p->size_sinks_out)) == NULL)
+      error("Failed to re-allocate sinks_out buffers.");
+    memcpy(tp, p->sinks_out, sizeof(struct sink) * p->nr_sinks_out);
+    swift_free("sinks_out", p->sinks_out);
+    p->sinks_out = tp;
+  }
+
+  /* Copy the parts and xparts data to the buffer. */
+  memcpy(&p->sinks_out[p->nr_sinks_out], sinks, sizeof(struct sink) * N);
+
+  /* Increase the counters. */
+  p->nr_sinks_out += N;
+}
+
 /**
  * @brief Frees the memory allocated for the particle proxies and sets their
  * size back to the initial state.
@@ -1062,6 +1196,21 @@ void proxy_free_particle_buffers(struct proxy *p) {
              "bparts_in", sizeof(struct bpart) * p->size_bparts_in)) == NULL)
       error("Failed to allocate bparts_in buffers.");
   }
+
+  if (p->size_sinks_out > proxy_buffinit) {
+    swift_free("sinks_out", p->sinks_out);
+    p->size_sinks_out = proxy_buffinit;
+    if ((p->sinks_out = (struct sink *)swift_malloc(
+             "sinks_out", sizeof(struct sink) * p->size_sinks_out)) == NULL)
+      error("Failed to allocate sinks_out buffers.");
+  }
+  if (p->size_sinks_in > proxy_buffinit) {
+    swift_free("sinks_in", p->sinks_in);
+    p->size_sinks_in = proxy_buffinit;
+    if ((p->sinks_in = (struct sink *)swift_malloc(
+             "sinks_in", sizeof(struct sink) * p->size_sinks_in)) == NULL)
+      error("Failed to allocate sinks_in buffers.");
+  }
 }
 
 /**
@@ -1166,6 +1315,22 @@ void proxy_init(struct proxy *p, int mynodeID, int nodeID) {
       error("Failed to allocate bparts_out buffers.");
   }
   p->nr_bparts_out = 0;
+
+  /* Allocate the sinks send and receive buffers, if needed. */
+  if (p->sinks_in == NULL) {
+    p->size_sinks_in = proxy_buffinit;
+    if ((p->sinks_in = (struct sink *)swift_malloc(
+             "sinks_in", sizeof(struct sink) * p->size_sinks_in)) == NULL)
+      error("Failed to allocate sinks_in buffers.");
+  }
+  p->nr_sinks_in = 0;
+  if (p->sinks_out == NULL) {
+    p->size_sinks_out = proxy_buffinit;
+    if ((p->sinks_out = (struct sink *)swift_malloc(
+             "sinks_out", sizeof(struct sink) * p->size_sinks_out)) == NULL)
+      error("Failed to allocate sinks_out buffers.");
+  }
+  p->nr_sinks_out = 0;
 }
 
 /**
@@ -1184,11 +1349,13 @@ void proxy_clean(struct proxy *p) {
   swift_free("gparts_out", p->gparts_out);
   swift_free("sparts_out", p->sparts_out);
   swift_free("bparts_out", p->bparts_out);
+  swift_free("sinks_out", p->sinks_out);
   swift_free("parts_in", p->parts_in);
   swift_free("xparts_in", p->xparts_in);
   swift_free("gparts_in", p->gparts_in);
   swift_free("sparts_in", p->sparts_in);
   swift_free("bparts_in", p->bparts_in);
+  swift_free("sinks_in", p->sinks_in);
 }
 
 /**
diff --git a/src/proxy.h b/src/proxy.h
index d0d2bfb582828eefbbe56d5e7eeba850fa340ffc..46a322e3a49ff53f796353e90aa84852f855acd0 100644
--- a/src/proxy.h
+++ b/src/proxy.h
@@ -28,15 +28,21 @@
 #define proxy_buffgrow 1.5
 #define proxy_buffinit 100
 
+/* Number of particle types to exchange with proxies in
+   proxy_parts_exchange_first(). We have parts, gparts, sparts, bparts and
+   sinks to exchange, hence 5 types. */
+#define PROXY_EXCHANGE_NUMBER_PARTICLE_TYPES 5
+
 /* Proxy tag arithmetic. */
-#define proxy_tag_shift 8
+#define proxy_tag_shift 9
 #define proxy_tag_count 0
 #define proxy_tag_parts 1
 #define proxy_tag_xparts 2
 #define proxy_tag_gparts 3
 #define proxy_tag_sparts 4
 #define proxy_tag_bparts 5
-#define proxy_tag_cells 6
+#define proxy_tag_sinks 6
+#define proxy_tag_cells 7
 
 /**
  * @brief The different reasons a cell can be in a proxy
@@ -71,6 +77,7 @@ struct proxy {
   struct gpart *gparts_in, *gparts_out;
   struct spart *sparts_in, *sparts_out;
   struct bpart *bparts_in, *bparts_out;
+  struct sink *sinks_in, *sinks_out;
   int size_parts_in, size_parts_out;
   int nr_parts_in, nr_parts_out;
   int size_gparts_in, size_gparts_out;
@@ -79,9 +86,12 @@ struct proxy {
   int nr_sparts_in, nr_sparts_out;
   int size_bparts_in, size_bparts_out;
   int nr_bparts_in, nr_bparts_out;
+  int size_sinks_in, size_sinks_out;
+  int nr_sinks_in, nr_sinks_out;
 
   /* Buffer to hold the incomming/outgoing particle counts. */
-  int buff_out[4], buff_in[4];
+  int buff_out[PROXY_EXCHANGE_NUMBER_PARTICLE_TYPES],
+      buff_in[PROXY_EXCHANGE_NUMBER_PARTICLE_TYPES];
 
 /* MPI request handles. */
 #ifdef WITH_MPI
@@ -91,6 +101,7 @@ struct proxy {
   MPI_Request req_gparts_out, req_gparts_in;
   MPI_Request req_sparts_out, req_sparts_in;
   MPI_Request req_bparts_out, req_bparts_in;
+  MPI_Request req_sinks_out, req_sinks_in;
   MPI_Request req_cells_count_out, req_cells_count_in;
   MPI_Request req_cells_out, req_cells_in;
 #endif
@@ -104,6 +115,7 @@ void proxy_parts_load(struct proxy *p, const struct part *parts,
 void proxy_gparts_load(struct proxy *p, const struct gpart *gparts, int N);
 void proxy_sparts_load(struct proxy *p, const struct spart *sparts, int N);
 void proxy_bparts_load(struct proxy *p, const struct bpart *bparts, int N);
+void proxy_sinks_load(struct proxy *p, const struct sink *sinks, int N);
 void proxy_free_particle_buffers(struct proxy *p);
 void proxy_parts_exchange_first(struct proxy *p);
 void proxy_parts_exchange_second(struct proxy *p);
diff --git a/src/runner_doiact_functions_sinks.h b/src/runner_doiact_functions_sinks.h
index c21c17812849118d1630aeb894591da8c88fdbfc..6ff95ba1deefd310b28f4e24d30bc62d23b5663c 100644
--- a/src/runner_doiact_functions_sinks.h
+++ b/src/runner_doiact_functions_sinks.h
@@ -346,6 +346,10 @@ void DOPAIR1_SINKS_NAIVE(struct runner *r, struct cell *restrict ci,
  */
 void DOSELF1_BRANCH_SINKS(struct runner *r, struct cell *c) {
 
+#ifdef SWIFT_DEBUG_CHECKS_MPI_DOMAIN_DECOMPOSITION
+  return;
+#endif
+
   const struct engine *restrict e = r->e;
 
   /* Anything to do here? */
@@ -371,6 +375,10 @@ void DOSELF1_BRANCH_SINKS(struct runner *r, struct cell *c) {
  */
 void DOPAIR1_BRANCH_SINKS(struct runner *r, struct cell *ci, struct cell *cj) {
 
+#ifdef SWIFT_DEBUG_CHECKS_MPI_DOMAIN_DECOMPOSITION
+  return;
+#endif
+
   const struct engine *restrict e = r->e;
 
   const int ci_active = cell_is_active_sinks(ci, e);
@@ -417,6 +425,9 @@ void DOPAIR1_BRANCH_SINKS(struct runner *r, struct cell *ci, struct cell *cj) {
  */
 void DOSUB_PAIR1_SINKS(struct runner *r, struct cell *ci, struct cell *cj,
                        int timer) {
+#ifdef SWIFT_DEBUG_CHECKS_MPI_DOMAIN_DECOMPOSITION
+  return;
+#endif
 
   TIMER_TIC;
 
@@ -496,6 +507,9 @@ void DOSUB_PAIR1_SINKS(struct runner *r, struct cell *ci, struct cell *cj,
  * @param gettimer Do we have a timer ?
  */
 void DOSUB_SELF1_SINKS(struct runner *r, struct cell *ci, int timer) {
+#ifdef SWIFT_DEBUG_CHECKS_MPI_DOMAIN_DECOMPOSITION
+  return;
+#endif
 
   TIMER_TIC;
 
diff --git a/src/runner_others.c b/src/runner_others.c
index 86b2d6fcbade1dca24eefd5629fb11b333fb8772..82d58f22c46ec5aa0f6e8240e5bd2ef477981da0 100644
--- a/src/runner_others.c
+++ b/src/runner_others.c
@@ -198,6 +198,9 @@ void runner_do_cooling(struct runner *r, struct cell *c, int timer) {
  */
 void runner_do_star_formation_sink(struct runner *r, struct cell *c,
                                    int timer) {
+#ifdef SWIFT_DEBUG_CHECKS_MPI_DOMAIN_DECOMPOSITION
+  return;
+#endif
 
   struct engine *e = r->e;
   const struct cosmology *cosmo = e->cosmology;
@@ -567,6 +570,10 @@ void runner_do_star_formation(struct runner *r, struct cell *c, int timer) {
  */
 void runner_do_sink_formation(struct runner *r, struct cell *c) {
 
+#ifdef SWIFT_DEBUG_CHECKS_MPI_DOMAIN_DECOMPOSITION
+  return;
+#endif
+
   struct engine *e = r->e;
   const struct cosmology *cosmo = e->cosmology;
   const struct sink_props *sink_props = e->sink_properties;
diff --git a/src/runner_sinks.c b/src/runner_sinks.c
index fa614f2cbaa23217e2b61f704dbf31fc3039d0f5..d4124c789588bd4b2e56dfe35e0fd24893908f74 100644
--- a/src/runner_sinks.c
+++ b/src/runner_sinks.c
@@ -210,6 +210,9 @@ void runner_do_sinks_gas_swallow(struct runner *r, struct cell *c, int timer) {
  */
 void runner_do_sinks_gas_swallow_self(struct runner *r, struct cell *c,
                                       int timer) {
+#ifdef SWIFT_DEBUG_CHECKS_MPI_DOMAIN_DECOMPOSITION
+  return;
+#endif
 
 #ifdef SWIFT_DEBUG_CHECKS
   if (c->nodeID != r->e->nodeID) error("Running self task on foreign node");
@@ -230,6 +233,9 @@ void runner_do_sinks_gas_swallow_self(struct runner *r, struct cell *c,
  */
 void runner_do_sinks_gas_swallow_pair(struct runner *r, struct cell *ci,
                                       struct cell *cj, int timer) {
+#ifdef SWIFT_DEBUG_CHECKS_MPI_DOMAIN_DECOMPOSITION
+  return;
+#endif
 
   const struct engine *e = r->e;
 
@@ -399,6 +405,9 @@ void runner_do_sinks_sink_swallow(struct runner *r, struct cell *c, int timer) {
  */
 void runner_do_sinks_sink_swallow_self(struct runner *r, struct cell *c,
                                        int timer) {
+#ifdef SWIFT_DEBUG_CHECKS_MPI_DOMAIN_DECOMPOSITION
+  return;
+#endif
 
 #ifdef SWIFT_DEBUG_CHECKS
   if (c->nodeID != r->e->nodeID) error("Running self task on foreign node");
@@ -419,6 +428,9 @@ void runner_do_sinks_sink_swallow_self(struct runner *r, struct cell *c,
  */
 void runner_do_sinks_sink_swallow_pair(struct runner *r, struct cell *ci,
                                        struct cell *cj, int timer) {
+#ifdef SWIFT_DEBUG_CHECKS_MPI_DOMAIN_DECOMPOSITION
+  return;
+#endif
 
   const struct engine *e = r->e;
 
diff --git a/src/sink/GEAR/sink.h b/src/sink/GEAR/sink.h
index 51ec1b704f75e5510e9b02f6ad6977d40a7f929c..de6bf3636a3a756a5bbf31f35556920ef0c585b4 100644
--- a/src/sink/GEAR/sink.h
+++ b/src/sink/GEAR/sink.h
@@ -172,7 +172,15 @@ __attribute__((always_inline)) INLINE static void sink_init_part(
   cpd->E_rot_neighbours[0] = 0.f;
   cpd->E_rot_neighbours[1] = 0.f;
   cpd->E_rot_neighbours[2] = 0.f;
-  cpd->potential = 0.f;
+
+  /* Do not reset the potential to 0. Keep the value computed at the end of the
+  last step. This value is used in runner_iact_nonsym_sink() and
+  runner_iact_sink() to check which particle is at a potential minimum. If you
+  set this value to 0, then we break the check. This value is used instead of
+  gpart->potential because:
+  1) cpd->potential does not break MPI, while gpart->potential does
+  2) gpart->potential is not yet computed in runner_iact_X_sink(). */
+  /* cpd->potential = 0.f; */
   cpd->E_mec_bound = 0.f; /* Gravitationally bound particles will have
                              E_mec_bound < 0. This is checked before comparing
                              any other value with this one. So no need to put
diff --git a/src/sink/GEAR/sink_iact.h b/src/sink/GEAR/sink_iact.h
index fc75ba8842bb7ceaae6d789b277a76b21206c29f..fe3791cf964155d0ae7b34276cec09dc01f5a967 100644
--- a/src/sink/GEAR/sink_iact.h
+++ b/src/sink/GEAR/sink_iact.h
@@ -33,8 +33,6 @@
  * In GEAR: This function deactivates the sink formation ability of #part not
  * at a potential minimum.
  *
- * Note: This functions breaks MPI.
- *
  * @param r2 Comoving square distance between the two particles.
  * @param dx Comoving vector separating both particles (pi - pj).
  * @param hi Comoving smoothing-length of particle i.
@@ -58,12 +56,8 @@ __attribute__((always_inline)) INLINE static void runner_iact_sink(
 
   /* if the distance is less than the cut off radius */
   if (r < cut_off_radius) {
-
-    /*
-     * NOTE: Those lines break MPI
-     */
-    float potential_i = pi->gpart->potential;
-    float potential_j = pj->gpart->potential;
+    float potential_i = pi->sink_data.potential;
+    float potential_j = pj->sink_data.potential;
 
     /* prevent the particle with the largest potential to form a sink */
     if (potential_i > potential_j) {
@@ -107,9 +101,8 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_sink(
   const float r = sqrtf(r2);
 
   if (r < cut_off_radius) {
-
-    float potential_i = pi->gpart->potential;
-    float potential_j = pj->gpart->potential;
+    float potential_i = pi->sink_data.potential;
+    float potential_j = pj->sink_data.potential;
 
     /* if the potential is larger
      * prevent the particle to form a sink */
@@ -155,6 +148,9 @@ runner_iact_nonsym_sinks_gas_density(
  *
  * Note: Energies are computed with physical quantities, not the comoving ones.
  *
+ * MPI note: This functions invokes the gpart. Hence, it must be performed only
+ * on the local node (similarly to runner_iact_nonsym_bh_bh_repos()).
+ *
  * @param r2 Comoving square distance between the two particles.
  * @param dx Comoving vector separating both particles (pi - pj).
  * @param ri Comoving cut off radius of particle i.
@@ -286,6 +282,9 @@ runner_iact_nonsym_sinks_sink_swallow(
  *
  * Note: Energies are computed with physical quantities, not the comoving ones.
  *
+ * MPI note: This functions invokes the gpart. Hence, it must be performed only
+ * on the local node (similarly to runner_iact_nonsym_bh_gas_repos()).
+ *
  * @param r2 Comoving square distance between the two particles.
  * @param dx Comoving vector separating both particles (pi - pj).
  * @param ri Comoving cut off radius of particle i.
diff --git a/src/space.c b/src/space.c
index 72125200b25aa0e01edd66aeed508c89e325caf9..95d029c73da5828759b39a971fb1dee12cbef0c2 100644
--- a/src/space.c
+++ b/src/space.c
@@ -150,6 +150,11 @@ void space_free_foreign_parts(struct space *s, const int clear_cell_pointers) {
     s->size_bparts_foreign = 0;
     s->bparts_foreign = NULL;
   }
+  if (s->sinks_foreign != NULL) {
+    swift_free("sinks_foreign", s->sinks_foreign);
+    s->size_sinks_foreign = 0;
+    s->sinks_foreign = NULL;
+  }
   if (clear_cell_pointers) {
     for (int k = 0; k < s->e->nr_proxies; k++) {
       for (int j = 0; j < s->e->proxies[k].nr_cells_in; j++) {
@@ -2175,6 +2180,7 @@ void space_check_drift_point(struct space *s, integertime_t ti_drift,
   space_map_cells_pre(s, 1, cell_check_part_drift_point, &ti_drift);
   space_map_cells_pre(s, 1, cell_check_gpart_drift_point, &ti_drift);
   space_map_cells_pre(s, 1, cell_check_spart_drift_point, &ti_drift);
+  space_map_cells_pre(s, 1, cell_check_sink_drift_point, &ti_drift);
   if (multipole)
     space_map_cells_pre(s, 1, cell_check_multipole_drift_point, &ti_drift);
 #else
@@ -2321,6 +2327,55 @@ void space_check_bpart_swallow_mapper(void *map_data, int nr_bparts,
 #endif
 }
 
+/**
+ * @brief #threadpool mapper function for the swallow debugging check
+ */
+void space_check_part_sink_swallow_mapper(void *map_data, int nr_parts,
+                                          void *extra_data) {
+#ifdef SWIFT_DEBUG_CHECKS
+  /* Unpack the data */
+  struct part *restrict parts = (struct part *)map_data;
+
+  /* Verify that all particles have been swallowed or are untouched */
+  for (int k = 0; k < nr_parts; k++) {
+
+    if (parts[k].time_bin == time_bin_inhibited) continue;
+
+    const long long swallow_id = sink_get_part_swallow_id(&parts[k].sink_data);
+
+    if (swallow_id != -1)
+      error("Particle has not been swallowed! id=%lld", parts[k].id);
+  }
+#else
+  error("Calling debugging code without debugging flag activated.");
+#endif
+}
+
+/**
+ * @brief #threadpool mapper function for the swallow debugging check
+ */
+void space_check_sink_sink_swallow_mapper(void *map_data, int nr_sinks,
+                                          void *extra_data) {
+#ifdef SWIFT_DEBUG_CHECKS
+  /* Unpack the data */
+  struct sink *restrict sinks = (struct sink *)map_data;
+
+  /* Verify that all particles have been swallowed or are untouched */
+  for (int k = 0; k < nr_sinks; k++) {
+
+    if (sinks[k].time_bin == time_bin_inhibited) continue;
+
+    const long long swallow_id =
+        sink_get_sink_swallow_id(&sinks[k].merger_data);
+
+    if (swallow_id != -1)
+      error("Sink particle has not been swallowed! id=%lld", sinks[k].id);
+  }
+#else
+  error("Calling debugging code without debugging flag activated.");
+#endif
+}
+
 /**
  * @brief Checks that all particles have their swallow flag in a "no swallow"
  * state.
@@ -2339,6 +2394,16 @@ void space_check_swallow(struct space *s) {
   threadpool_map(&s->e->threadpool, space_check_bpart_swallow_mapper, s->bparts,
                  s->nr_bparts, sizeof(struct bpart), threadpool_auto_chunk_size,
                  /*extra_data=*/NULL);
+
+  threadpool_map(&s->e->threadpool, space_check_part_sink_swallow_mapper,
+                 s->parts, s->nr_parts, sizeof(struct part),
+                 threadpool_auto_chunk_size,
+                 /*extra_data=*/NULL);
+
+  threadpool_map(&s->e->threadpool, space_check_sink_sink_swallow_mapper,
+                 s->sinks, s->nr_sinks, sizeof(struct sink),
+                 threadpool_auto_chunk_size,
+                 /*extra_data=*/NULL);
 #else
   error("Calling debugging code without debugging flag activated.");
 #endif
@@ -2437,6 +2502,7 @@ void space_clean(struct space *s) {
   swift_free("sparts_foreign", s->sparts_foreign);
   swift_free("gparts_foreign", s->gparts_foreign);
   swift_free("bparts_foreign", s->bparts_foreign);
+  swift_free("sinks_foreign", s->sinks_foreign);
 #endif
   free(s->cells_sub);
   free(s->multipoles_sub);
@@ -2611,6 +2677,8 @@ void space_struct_restore(struct space *s, FILE *stream) {
   s->size_sparts_foreign = 0;
   s->bparts_foreign = NULL;
   s->size_bparts_foreign = 0;
+  s->sinks_foreign = NULL;
+  s->size_sinks_foreign = 0;
 #endif
 
   /* More things to read. */
@@ -2727,9 +2795,10 @@ void space_write_cell(const struct space *s, FILE *f, const struct cell *c) {
 
   /* Write line for current cell */
   fprintf(f, "%lld,%lld,%i,", c->cellID, parent, c->nodeID);
-  fprintf(f, "%i,%i,%i,%s,%s,%g,%g,%g,%g,%g,%g, ", c->hydro.count,
-          c->stars.count, c->grav.count, superID, hydro_superID, c->loc[0],
-          c->loc[1], c->loc[2], c->width[0], c->width[1], c->width[2]);
+  fprintf(f, "%i,%i,%i,%i,%s,%s,%g,%g,%g,%g,%g,%g, ", c->hydro.count,
+          c->stars.count, c->grav.count, c->sinks.count, superID, hydro_superID,
+          c->loc[0], c->loc[1], c->loc[2], c->width[0], c->width[1],
+          c->width[2]);
   fprintf(f, "%g, %g, %i, %i\n", c->hydro.h_max, c->stars.h_max, c->depth,
           c->maxdepth);
 
@@ -2761,7 +2830,7 @@ void space_write_cell_hierarchy(const struct space *s, int j) {
   if (engine_rank == 0) {
     fprintf(f, "name,parent,mpi_rank,");
     fprintf(f,
-            "hydro_count,stars_count,gpart_count,super,hydro_super,"
+            "hydro_count,stars_count,gpart_count,sinks_count,super,hydro_super,"
             "loc1,loc2,loc3,width1,width2,width3,");
     fprintf(f, "hydro_h_max,stars_h_max,depth,maxdepth\n");
 
diff --git a/src/space.h b/src/space.h
index df58eeda4b4bca6d9909786247877cf1caafdec2..8a85277f82d6d9169f6f984d02671f870b9a2961 100644
--- a/src/space.h
+++ b/src/space.h
@@ -349,6 +349,10 @@ struct space {
   struct bpart *bparts_foreign;
   size_t nr_bparts_foreign, size_bparts_foreign;
 
+  /*! Buffers for sink-parts that we will receive from foreign cells. */
+  struct sink *sinks_foreign;
+  size_t nr_sinks_foreign, size_sinks_foreign;
+
 #endif
 };
 
diff --git a/src/space_cell_index.c b/src/space_cell_index.c
index c9d7cdd07fdcce9a2333d40e9d94fa10e064a75d..c0ad4f2df00160cc341d585cf6295c2728e4795a 100644
--- a/src/space_cell_index.c
+++ b/src/space_cell_index.c
@@ -692,8 +692,8 @@ void space_sinks_get_cell_index_mapper(void *map_data, int nr_sinks,
   if (count_extra_sink) atomic_add(&data->count_extra_sink, count_extra_sink);
 
   /* Write back the minimal part mass and velocity sum */
-  atomic_min_f(&s->min_spart_mass, min_mass);
-  atomic_add_f(&s->sum_spart_vel_norm, sum_vel_norm);
+  atomic_min_f(&s->min_sink_mass, min_mass);
+  atomic_add_f(&s->sum_sink_vel_norm, sum_vel_norm);
 }
 
 /**
diff --git a/src/space_extras.c b/src/space_extras.c
index 9d8a88952e5a3d2a670ba63f96001dc27eda26c7..64ea69647ffc1f88ce600703a931a53626dea3d5 100644
--- a/src/space_extras.c
+++ b/src/space_extras.c
@@ -359,6 +359,7 @@ void space_allocate_extras(struct space *s, int verbose) {
       bzero(&s->sinks[i], sizeof(struct sink));
       s->sinks[i].time_bin = time_bin_not_created;
       s->sinks[i].id = -42;
+      sink_mark_sink_as_not_swallowed(&s->sinks[i].merger_data);
     }
 
     /* Put the spare particles in their correct cell */
diff --git a/src/space_first_init.c b/src/space_first_init.c
index fd36583715849c662ac56ae47d28ceff4396074a..3232e445f0fb21fb1dfeae14d91786efa2ed8688 100644
--- a/src/space_first_init.c
+++ b/src/space_first_init.c
@@ -484,6 +484,9 @@ void space_first_init_sinks_mapper(void *restrict map_data, int count,
     /* Initialize the sinks */
     sink_first_init_sink(&sink[k], props, e);
 
+    /* And the sink merger markers */
+    sink_mark_sink_as_not_swallowed(&sink[k].merger_data);
+
     /* Also initialize the chemistry */
     chemistry_first_init_sink(chemistry, &sink[k]);
 
diff --git a/src/space_rebuild.c b/src/space_rebuild.c
index 36d784c8b34c393d4260fbd54ae5fa02b5c4c771..7d458f6858ea64ea9970a376d177c2211cc5ea0a 100644
--- a/src/space_rebuild.c
+++ b/src/space_rebuild.c
@@ -491,17 +491,20 @@ void space_rebuild(struct space *s, int repartitioned, int verbose) {
     size_t nr_gparts_exchanged = s->nr_gparts - nr_gparts;
     size_t nr_sparts_exchanged = s->nr_sparts - nr_sparts;
     size_t nr_bparts_exchanged = s->nr_bparts - nr_bparts;
+    size_t nr_sinks_exchanged = s->nr_sinks - nr_sinks;
     engine_exchange_strays(s->e, nr_parts, &h_index[nr_parts],
                            &nr_parts_exchanged, nr_gparts, &g_index[nr_gparts],
                            &nr_gparts_exchanged, nr_sparts, &s_index[nr_sparts],
                            &nr_sparts_exchanged, nr_bparts, &b_index[nr_bparts],
-                           &nr_bparts_exchanged);
+                           &nr_bparts_exchanged, nr_sinks,
+                           &sink_index[nr_sinks], &nr_sinks_exchanged);
 
     /* Set the new particle counts. */
     s->nr_parts = nr_parts + nr_parts_exchanged;
     s->nr_gparts = nr_gparts + nr_gparts_exchanged;
     s->nr_sparts = nr_sparts + nr_sparts_exchanged;
     s->nr_bparts = nr_bparts + nr_bparts_exchanged;
+    s->nr_sinks = nr_sinks + nr_sinks_exchanged;
 
   } else {
 #ifdef SWIFT_DEBUG_CHECKS
@@ -511,6 +514,8 @@ void space_rebuild(struct space *s, int repartitioned, int verbose) {
       error("Number of sparts changing after repartition");
     if (s->nr_gparts != nr_gparts)
       error("Number of gparts changing after repartition");
+    if (s->nr_sinks != nr_sinks)
+      error("Number of sinks changing after repartition");
 #endif
   }
 
@@ -521,6 +526,7 @@ void space_rebuild(struct space *s, int repartitioned, int verbose) {
       cell_spart_counts[k] = 0;
       cell_gpart_counts[k] = 0;
       cell_bpart_counts[k] = 0;
+      cell_sink_counts[k] = 0;
     }
   }
 
@@ -547,16 +553,27 @@ void space_rebuild(struct space *s, int repartitioned, int verbose) {
   }
 
   /* Re-allocate the index array for the bparts if needed.. */
-  if (s->nr_bparts + 1 > s_index_size) {
+  if (s->nr_bparts + 1 > b_index_size) {
     int *bind_new;
     if ((bind_new = (int *)swift_malloc(
              "b_index", sizeof(int) * (s->nr_bparts + 1))) == NULL)
-      error("Failed to allocate temporary s-particle indices.");
+      error("Failed to allocate temporary b-particle indices.");
     memcpy(bind_new, b_index, sizeof(int) * nr_bparts);
     swift_free("b_index", b_index);
     b_index = bind_new;
   }
 
+  /* Re-allocate the index array for the sinks if needed.. */
+  if (s->nr_sinks + 1 > sink_index_size) {
+    int *sink_ind_new;
+    if ((sink_ind_new = (int *)swift_malloc(
+             "sink_index", sizeof(int) * (s->nr_sinks + 1))) == NULL)
+      error("Failed to allocate temporary sink-particle indices.");
+    memcpy(sink_ind_new, sink_index, sizeof(int) * nr_sinks);
+    swift_free("sink_index", sink_index);
+    sink_index = sink_ind_new;
+  }
+
   const int cdim[3] = {s->cdim[0], s->cdim[1], s->cdim[2]};
   const double ih[3] = {s->iwidth[0], s->iwidth[1], s->iwidth[2]};
 
@@ -602,6 +619,20 @@ void space_rebuild(struct space *s, int repartitioned, int verbose) {
   }
   nr_bparts = s->nr_bparts;
 
+  /* Assign each received sink to its cell. */
+  for (size_t k = nr_sinks; k < s->nr_sinks; k++) {
+    const struct sink *const sink = &s->sinks[k];
+    sink_index[k] = cell_getid(cdim, sink->x[0] * ih[0], sink->x[1] * ih[1],
+                               sink->x[2] * ih[2]);
+    cell_sink_counts[sink_index[k]]++;
+#ifdef SWIFT_DEBUG_CHECKS
+    if (cells_top[sink_index[k]].nodeID != local_nodeID)
+      error("Received sink-part that does not belong to me (nodeID=%i).",
+            cells_top[sink_index[k]].nodeID);
+#endif
+  }
+  nr_sinks = s->nr_sinks;
+
 #else /* WITH_MPI */
 
   /* Update the part, spart and bpart counters */
@@ -716,14 +747,14 @@ void space_rebuild(struct space *s, int repartitioned, int verbose) {
       error("Inhibited particle sorted into a cell!");
 
     /* New cell index */
-    const int new_bind =
+    const int new_sink_ind =
         cell_getid(s->cdim, sink->x[0] * s->iwidth[0],
                    sink->x[1] * s->iwidth[1], sink->x[2] * s->iwidth[2]);
 
     /* New cell of this sink */
-    const struct cell *c = &s->cells_top[new_bind];
+    const struct cell *c = &s->cells_top[new_sink_ind];
 
-    if (sink_index[k] != new_bind)
+    if (sink_index[k] != new_sink_ind)
       error("sink's new cell index not matching sorted index.");
 
     if (sink->x[0] < c->loc[0] || sink->x[0] > c->loc[0] + c->width[0] ||
@@ -931,6 +962,7 @@ void space_rebuild(struct space *s, int repartitioned, int verbose) {
 
       /* Store the state at rebuild time */
       c->stars.parts_rebuild = c->stars.parts;
+      c->sinks.parts_rebuild = c->sinks.parts;
       c->grav.parts_rebuild = c->grav.parts;
 
       c->hydro.count_total = c->hydro.count + space_extra_parts;
diff --git a/src/space_recycle.c b/src/space_recycle.c
index 1a7a42c830e3636815feea2b4ad5e1d70bdccb45..b510eb9dced0f3ee4e9eee47a0d8c434962e0c03 100644
--- a/src/space_recycle.c
+++ b/src/space_recycle.c
@@ -193,6 +193,7 @@ void space_rebuild_recycle_mapper(void *map_data, int num_elements,
     c->grav.parts = NULL;
     c->grav.parts_rebuild = NULL;
     c->sinks.parts = NULL;
+    c->sinks.parts_rebuild = NULL;
     c->stars.parts = NULL;
     c->stars.parts_rebuild = NULL;
     c->black_holes.parts = NULL;
diff --git a/src/space_regrid.c b/src/space_regrid.c
index 487fe7c0e38495ac85622156615308cd4179ec01..dc86468e335b3cc2e50d6250327f532bc64e22eb 100644
--- a/src/space_regrid.c
+++ b/src/space_regrid.c
@@ -64,7 +64,8 @@ void space_regrid(struct space *s, int verbose) {
         if (c->black_holes.h_max > h_max) {
           h_max = c->black_holes.h_max;
         }
-        if (c->sinks.r_cut_max > h_max) {
+        /* Note: For sinks, r_cut <=> h*kernel_gamma */
+        if (c->sinks.r_cut_max > h_max * kernel_gamma) {
           h_max = c->sinks.r_cut_max / kernel_gamma;
         }
       }
@@ -82,7 +83,9 @@ void space_regrid(struct space *s, int verbose) {
         if (c->nodeID == engine_rank && c->black_holes.h_max > h_max) {
           h_max = c->black_holes.h_max;
         }
-        if (c->nodeID == engine_rank && c->sinks.r_cut_max > h_max) {
+        /* Note: For sinks, r_cut <=> h*kernel_gamma */
+        if (c->nodeID == engine_rank &&
+            c->sinks.r_cut_max > h_max * kernel_gamma) {
           h_max = c->sinks.r_cut_max / kernel_gamma;
         }
       }
diff --git a/src/space_unique_id.c b/src/space_unique_id.c
index bfcb733cc6daa698e2744251d7f76b5dc93068e0..481d8a362799e310422e6020361d8ea7fc1ab913 100644
--- a/src/space_unique_id.c
+++ b/src/space_unique_id.c
@@ -82,9 +82,10 @@ void space_update_unique_id(struct space *s) {
 #endif  // WITH_MPI
 
   /* Compute the size of each batch. */
-  const long long batch_size = (space_extra_parts + space_extra_sparts +
-                                space_extra_gparts + space_extra_bparts) *
-                               s->nr_cells;
+  const long long batch_size =
+      (space_extra_parts + space_extra_sparts + space_extra_gparts +
+       space_extra_bparts + space_extra_sinks) *
+      s->nr_cells;
 
   /* Get a new batch. */
   if (require_new_batch) {
@@ -210,9 +211,10 @@ void space_init_unique_id(struct space *s, int nr_nodes) {
   s->unique_id.global_next_id++;
 
   /* Compute the size of each batch. */
-  const long long batch_size = (space_extra_parts + space_extra_sparts +
-                                space_extra_gparts + space_extra_bparts) *
-                               s->nr_cells;
+  const long long batch_size =
+      (space_extra_parts + space_extra_sparts + space_extra_gparts +
+       space_extra_bparts + space_extra_sinks) *
+      s->nr_cells;
 
   /* Compute the initial batchs (each rank has 2 batchs). */
   if (s->unique_id.global_next_id > LLONG_MAX - 2 * engine_rank * batch_size) {
diff --git a/swift.c b/swift.c
index b63941cd63538e3226669bfed06bdb1837c73411..41c96e0afbc4ca5ad2a119e2089397a5fcbd540e 100644
--- a/swift.c
+++ b/swift.c
@@ -528,11 +528,17 @@ int main(int argc, char *argv[]) {
 #endif
 
 #ifdef WITH_MPI
+#ifdef SWIFT_DEBUG_CHECKS
+  if (with_sinks) {
+    pretime_message("Warning: sink particles are are WIP yet with MPI.");
+  }
+#else
   if (with_sinks) {
     pretime_message("Error: sink particles are not available yet with MPI.");
     return 1;
   }
-#endif
+#endif /* SWIFT_DEBUG_CHECKS */
+#endif /* WITH_MPI */
 
   if (with_sinks && with_star_formation) {
     pretime_message(
diff --git a/tests/difffloat.py b/tests/difffloat.py
index cfa16970730bc365b284a78f8a757bd459a9b741..6f60a66535b39e9aa4d06951cc088f975435d46a 100644
--- a/tests/difffloat.py
+++ b/tests/difffloat.py
@@ -18,6 +18,7 @@
 ##############################################################################
 
 from numpy import *
+
 del min
 import sys
 
diff --git a/theory/SinkParticles/plot_imf_image.py b/theory/SinkParticles/plot_imf_image.py
index 25da38cab2b804a651c5f745063e6ba101b38a52..bc1da9cccf1c3fe60af2661e4cf65a96fb949338 100644
--- a/theory/SinkParticles/plot_imf_image.py
+++ b/theory/SinkParticles/plot_imf_image.py
@@ -14,18 +14,17 @@ import matplotlib.pyplot as plt
 import matplotlib
 
 # For swift doc, use the following and not the styleheet
-plt.rcParams['text.usetex'] = True
-plt.rcParams['font.family'] = 'serif'
-plt.rcParams['font.serif'] = ['Computer Modern Roman']
+plt.rcParams["text.usetex"] = True
+plt.rcParams["font.family"] = "serif"
+plt.rcParams["font.serif"] = ["Computer Modern Roman"]
 
 mmin = 0.5
 mmax = 300
 
-matplotlib.rcParams.update({'font.size': 16})
+matplotlib.rcParams.update({"font.size": 16})
 
 figsize = (6.4, 4.8)
-fig, ax = plt.subplots(num=1, ncols=1, nrows=1,
-                       figsize=figsize, layout="tight")
+fig, ax = plt.subplots(num=1, ncols=1, nrows=1, figsize=figsize, layout="tight")
 ax.set_xlim([0.3, 400])
 ax.set_ylim([1, 5e4])
 
@@ -34,34 +33,34 @@ ax.get_xaxis().set_major_formatter(matplotlib.ticker.ScalarFormatter())
 
 ax.set_xlabel("$M_{\star}$ $[M_\odot]$")
 ax.set_ylabel("d$N/$d$M$ [arbitrary units]")
-ax.set_xscale('log')
-ax.set_yscale('log')
+ax.set_xscale("log")
+ax.set_yscale("log")
 
 # theoretical imf
 s = -1.3
-bins = 10**np.linspace(np.log10(mmin), np.log10(mmax), 100)
-n = 0.9*10000*bins**s
+bins = 10 ** np.linspace(np.log10(mmin), np.log10(mmax), 100)
+n = 0.9 * 10000 * bins ** s
 ax.plot(bins, n, "k--")
 
-bins = 10**np.linspace(np.log10(mmin), np.log10(8), 100)
-n = 0.9*10000*bins**s
+bins = 10 ** np.linspace(np.log10(mmin), np.log10(8), 100)
+n = 0.9 * 10000 * bins ** s
 ax.fill_between(bins, 0.1, n, color="red", alpha=0.1)
 
-bins = 10**np.linspace(np.log10(8), np.log10(mmax), 100)
-n = 0.9*10000*bins**s
+bins = 10 ** np.linspace(np.log10(8), np.log10(mmax), 100)
+n = 0.9 * 10000 * bins ** s
 ax.fill_between(bins, 0.1, n, color="blue", alpha=0.1)
 
-ax.text(2, 1e2, r"$M_{\rm c}$", horizontalalignment='center')
-ax.text(50, 2, r"$M_{\rm d}$", horizontalalignment='center')
+ax.text(2, 1e2, r"$M_{\rm c}$", horizontalalignment="center")
+ax.text(50, 2, r"$M_{\rm d}$", horizontalalignment="center")
 
 # Add limit
-ax.vlines(x=8, ymin=0, ymax=600, color='k', linestyle='-')
+ax.vlines(x=8, ymin=0, ymax=600, color="k", linestyle="-")
 
 # Add text to the vertical line
-ax.text(8, 800, r"$m_{t}$", horizontalalignment='center')
+ax.text(8, 800, r"$m_{t}$", horizontalalignment="center")
 
 # fig.patch.set_facecolor('none')  # Remove figure background
 # ax.set_facecolor('none')         # Remove axes background
 
-plt.savefig('sink_imf.png', dpi=300, bbox_inches='tight')
+plt.savefig("sink_imf.png", dpi=300, bbox_inches="tight")
 plt.close()
diff --git a/tools/data/cell_hierarchy.html b/tools/data/cell_hierarchy.html
index 6c9bcdb995be7970948cf9b9544ae0a59d41caf0..051451091d70d7e6bcb000b44b71f73c2779caa6 100644
--- a/tools/data/cell_hierarchy.html
+++ b/tools/data/cell_hierarchy.html
@@ -162,6 +162,7 @@
 		      "MPI rank:" + n.mpi_rank + "<br/>" + 
 		      "Part: " + n.hydro_count + "<br/>" + 
 		      "Spart: " + n.stars_count + "<br/>" +
+		      "Sink: " + n.sinks_count + "<br/>" +
 		      "Super: " + n.super + "<br/>" +
 		      "Super Hydro: " + n.hydro_super + "<br/>" +
 		      "Loc: " + n.loc1 + ", " + n.loc2 + ", " + n.loc3 + "<br/>" +
diff --git a/tools/plot_task_dependencies.py b/tools/plot_task_dependencies.py
index 17013ca2f131ddf648d81f4fa70158df65bbd610..fa9fdb7fd1e5a04eb340f9fee0801918a6f3370c 100755
--- a/tools/plot_task_dependencies.py
+++ b/tools/plot_task_dependencies.py
@@ -208,7 +208,12 @@ def task_is_hydro(name):
         return True
     if "_part" in name:
         return True
-    if "density" in name and "stars" not in name and "sink" not in name and "bh" not in name:
+    if (
+        "density" in name
+        and "stars" not in name
+        and "sink" not in name
+        and "bh" not in name
+    ):
         return True
     if "rho" in name and "bpart" not in name:
         return True