diff --git a/src/hydro/Gizmo/MFM/hydro.h b/src/hydro/Gizmo/MFM/hydro.h
index bfbee24307c4c719ed596d4a460a1801757a4a59..1f81722abe644083f7b8ada58d5220ff09de0a07 100644
--- a/src/hydro/Gizmo/MFM/hydro.h
+++ b/src/hydro/Gizmo/MFM/hydro.h
@@ -36,343 +36,6 @@
 
 #include <float.h>
 
-/**
- * @brief Finishes the volume calculation.
- *
- * Multiplies the density and number of neighbours by the appropiate constants
- * and adds the self-contribution term. Calculates the volume and uses it to
- * update the primitive variables (based on the conserved variables). The latter
- * should only be done for active particles. This is okay, since this method is
- * only called for active particles.
- *
- * Multiplies the components of the matrix E with the appropriate constants and
- * inverts it. Initializes the variables used during the gradient loop. This
- * cannot be done in hydro_prepare_force, since that method is called for all
- * particles, and not just the active ones. If we would initialize the
- * variables there, gradients for passive particles would be zero, while we
- * actually use the old gradients in the flux calculation between active and
- * passive particles.
- *
- * @param p The particle to act upon.
- * @param cosmo The cosmological model.
- */
-__attribute__((always_inline)) INLINE static void hydro_end_density(
-    struct part* restrict p, const struct cosmology* cosmo) {
-
-  /* Some smoothing length multiples. */
-  const float h = p->h;
-  const float ih = 1.0f / h;
-  const float ihdim = pow_dimension(ih);
-  const float ihdim_plus_one = ihdim * ih;
-
-  /* Final operation on the density. */
-  p->density.wcount += kernel_root;
-  p->density.wcount *= ihdim;
-
-  p->density.wcount_dh -= hydro_dimension * kernel_root;
-  p->density.wcount_dh *= ihdim_plus_one;
-
-  /* Final operation on the geometry. */
-  /* we multiply with the smoothing kernel normalization ih3 and calculate the
-   * volume */
-  const float volume_inv = ihdim * (p->geometry.volume + kernel_root);
-  const float volume = 1.0f / volume_inv;
-  p->geometry.volume = volume;
-
-  /* we multiply with the smoothing kernel normalization */
-  p->geometry.matrix_E[0][0] = ihdim * p->geometry.matrix_E[0][0];
-  p->geometry.matrix_E[0][1] = ihdim * p->geometry.matrix_E[0][1];
-  p->geometry.matrix_E[0][2] = ihdim * p->geometry.matrix_E[0][2];
-  p->geometry.matrix_E[1][0] = ihdim * p->geometry.matrix_E[1][0];
-  p->geometry.matrix_E[1][1] = ihdim * p->geometry.matrix_E[1][1];
-  p->geometry.matrix_E[1][2] = ihdim * p->geometry.matrix_E[1][2];
-  p->geometry.matrix_E[2][0] = ihdim * p->geometry.matrix_E[2][0];
-  p->geometry.matrix_E[2][1] = ihdim * p->geometry.matrix_E[2][1];
-  p->geometry.matrix_E[2][2] = ihdim * p->geometry.matrix_E[2][2];
-
-  p->geometry.centroid[0] *= kernel_norm;
-  p->geometry.centroid[1] *= kernel_norm;
-  p->geometry.centroid[2] *= kernel_norm;
-
-  const float wcount_inv = 1.0f / p->density.wcount;
-  p->geometry.centroid[0] *= wcount_inv;
-  p->geometry.centroid[1] *= wcount_inv;
-  p->geometry.centroid[2] *= wcount_inv;
-
-  /* Check the condition number to see if we have a stable geometry. */
-  float condition_number_E = 0.0f;
-  int i, j;
-  for (i = 0; i < 3; ++i) {
-    for (j = 0; j < 3; ++j) {
-      condition_number_E +=
-          p->geometry.matrix_E[i][j] * p->geometry.matrix_E[i][j];
-    }
-  }
-
-  invert_dimension_by_dimension_matrix(p->geometry.matrix_E);
-
-  float condition_number_Einv = 0.0f;
-  for (i = 0; i < 3; ++i) {
-    for (j = 0; j < 3; ++j) {
-      condition_number_Einv +=
-          p->geometry.matrix_E[i][j] * p->geometry.matrix_E[i][j];
-    }
-  }
-
-  float condition_number =
-      hydro_dimension_inv * sqrtf(condition_number_E * condition_number_Einv);
-
-  if (condition_number > const_gizmo_max_condition_number &&
-      p->geometry.wcorr > const_gizmo_min_wcorr) {
-#ifdef GIZMO_PATHOLOGICAL_ERROR
-    error("Condition number larger than %g (%g)!",
-          const_gizmo_max_condition_number, condition_number);
-#endif
-#ifdef GIZMO_PATHOLOGICAL_WARNING
-    message("Condition number too large: %g (> %g, p->id: %llu)!",
-            condition_number, const_gizmo_max_condition_number, p->id);
-#endif
-    /* add a correction to the number of neighbours for this particle */
-    p->geometry.wcorr *= const_gizmo_w_correction_factor;
-  }
-
-  /* compute primitive variables */
-  /* eqns (3)-(5) */
-  const float m = p->conserved.mass;
-
-#ifdef SWIFT_DEBUG_CHECKS
-  if (m < 0.0f) {
-    error("Mass is negative!");
-  }
-
-  if (volume == 0.0f) {
-    error("Volume is 0!");
-  }
-#endif
-
-  // MATTHIEU: Bert is this correct? Do we need cosmology terms here?
-  float momentum[3];
-  momentum[0] = p->conserved.momentum[0];
-  momentum[1] = p->conserved.momentum[1];
-  momentum[2] = p->conserved.momentum[2];
-  p->rho = m * volume_inv;
-  if (m == 0.0f) {
-    p->v[0] = 0.0f;
-    p->v[1] = 0.0f;
-    p->v[2] = 0.0f;
-  } else {
-    const float m_inv = 1.0f / m;
-    p->v[0] = momentum[0] * m_inv;
-    p->v[1] = momentum[1] * m_inv;
-    p->v[2] = momentum[2] * m_inv;
-  }
-
-#ifdef EOS_ISOTHERMAL_GAS
-  /* although the pressure is not formally used anywhere if an isothermal eos
-     has been selected, we still make sure it is set to the correct value */
-  p->P = gas_pressure_from_internal_energy(p->rho, 0.0f);
-#else
-
-  float energy = p->conserved.energy;
-
-#ifdef GIZMO_TOTAL_ENERGY
-  /* subtract the kinetic energy; we want the thermal energy */
-  energy -= 0.5f * (momentum[0] * p->v[0] + momentum[1] * p->v[1] +
-                    momentum[2] * p->v[2]);
-#endif
-
-  /* energy contains the total thermal energy, we want the specific energy.
-     this is why we divide by the volume, and not by the density */
-  p->P = hydro_gamma_minus_one * energy * volume_inv;
-#endif
-
-  /* sanity checks */
-  gizmo_check_physical_quantities("density", "pressure", p->rho, p->v[0],
-                                  p->v[1], p->v[2], p->P);
-
-  /* Add a correction factor to wcount (to force a neighbour number increase if
-     the geometry matrix is close to singular) */
-  p->density.wcount *= p->geometry.wcorr;
-  p->density.wcount_dh *= p->geometry.wcorr;
-}
-
-/**
- * @brief Sets all particle fields to sensible values when the #part has 0 ngbs.
- *
- * @param p The particle to act upon
- * @param xp The extended particle data to act upon
- * @param cosmo The cosmological model.
- */
-__attribute__((always_inline)) INLINE static void hydro_part_has_no_neighbours(
-    struct part* restrict p, struct xpart* restrict xp,
-    const struct cosmology* cosmo) {
-
-  /* Some smoothing length multiples. */
-  const float h = p->h;
-  const float h_inv = 1.0f / h;                 /* 1/h */
-  const float h_inv_dim = pow_dimension(h_inv); /* 1/h^d */
-
-  /* Re-set problematic values */
-  p->density.wcount = kernel_root * h_inv_dim;
-  p->density.wcount_dh = 0.0f;
-  p->geometry.volume = 1.0f;
-  p->geometry.matrix_E[0][0] = 1.0f;
-  p->geometry.matrix_E[0][1] = 0.0f;
-  p->geometry.matrix_E[0][2] = 0.0f;
-  p->geometry.matrix_E[1][0] = 0.0f;
-  p->geometry.matrix_E[1][1] = 1.0f;
-  p->geometry.matrix_E[1][2] = 0.0f;
-  p->geometry.matrix_E[2][0] = 0.0f;
-  p->geometry.matrix_E[2][1] = 0.0f;
-  p->geometry.matrix_E[2][2] = 1.0f;
-  /* centroid is relative w.r.t. particle position */
-  /* by setting the centroid to 0.0f, we make sure no velocity correction is
-     applied */
-  p->geometry.centroid[0] = 0.0f;
-  p->geometry.centroid[1] = 0.0f;
-  p->geometry.centroid[2] = 0.0f;
-}
-
-/**
- * @brief Prepare a particle for the gradient calculation.
- *
- * This function is called after the density loop and before the gradient loop.
- *
- * We use it to set the physical timestep for the particle and to copy the
- * actual velocities, which we need to boost our interfaces during the flux
- * calculation. We also initialize the variables used for the time step
- * calculation.
- *
- * @param p The particle to act upon.
- * @param xp The extended particle data to act upon.
- * @param cosmo The cosmological model.
- * @param hydro_props Hydrodynamic properties.
- */
-__attribute__((always_inline)) INLINE static void hydro_prepare_gradient(
-    struct part* restrict p, struct xpart* restrict xp,
-    const struct cosmology* cosmo, const struct hydro_props* hydro_props) {
-
-  /* Initialize time step criterion variables */
-  p->timestepvars.vmax = 0.0f;
-
-  hydro_gradients_init(p);
-
-  // MATTHIEU: Bert is this correct? Do we need cosmology terms here?
-}
-
-/**
- * @brief Resets the variables that are required for a gradient calculation.
- *
- * This function is called after hydro_prepare_gradient.
- *
- * @param p The particle to act upon.
- * @param xp The extended particle data to act upon.
- * @param cosmo The cosmological model.
- */
-__attribute__((always_inline)) INLINE static void hydro_reset_gradient(
-    struct part* restrict p) {}
-
-/**
- * @brief Finishes the gradient calculation.
- *
- * Just a wrapper around hydro_gradients_finalize, which can be an empty method,
- * in which case no gradients are used.
- *
- * This method also initializes the force loop variables.
- *
- * @param p The particle to act upon.
- */
-__attribute__((always_inline)) INLINE static void hydro_end_gradient(
-    struct part* p) {
-
-  hydro_gradients_finalize(p);
-
-#ifdef GIZMO_LLOYD_ITERATION
-  /* reset the gradients to zero, as we don't want them */
-  hydro_gradients_init(p);
-#endif
-}
-
-/**
- * @brief Prepare a particle for the force calculation.
- *
- * This function is called in the ghost task to convert some quantities coming
- * from the density loop over neighbours into quantities ready to be used in the
- * force loop over neighbours. Quantities are typically read from the density
- * sub-structure and written to the force sub-structure.
- * Examples of calculations done here include the calculation of viscosity term
- * constants, thermal conduction terms, hydro conversions, etc.
- *
- * @param p The particle to act upon
- * @param xp The extended particle data to act upon
- * @param cosmo The current cosmological model.
- * @param hydro_props Hydrodynamic properties.
- * @param dt_alpha The time-step used to evolve non-cosmological quantities such
- *                 as the artificial viscosity.
- */
-__attribute__((always_inline)) INLINE static void hydro_prepare_force(
-    struct part* restrict p, struct xpart* restrict xp,
-    const struct cosmology* cosmo, const struct hydro_props* hydro_props,
-    const float dt_alpha) {
-
-  /* Initialise values that are used in the force loop */
-  p->flux.momentum[0] = 0.0f;
-  p->flux.momentum[1] = 0.0f;
-  p->flux.momentum[2] = 0.0f;
-  p->flux.energy = 0.0f;
-}
-
-/**
- * @brief Reset acceleration fields of a particle
- *
- * This is actually not necessary for GIZMO, since we just set the accelerations
- * after the flux calculation.
- *
- * @param p The particle to act upon.
- */
-__attribute__((always_inline)) INLINE static void hydro_reset_acceleration(
-    struct part* p) {
-
-  /* Reset the acceleration. */
-  p->a_hydro[0] = 0.0f;
-  p->a_hydro[1] = 0.0f;
-  p->a_hydro[2] = 0.0f;
-
-  /* Reset the time derivatives. */
-  p->force.h_dt = 0.0f;
-}
-
-/**
- * @brief Sets the values to be predicted in the drifts to their values at a
- * kick time
- *
- * @param p The particle.
- * @param xp The extended data of this particle.
- * @param cosmo The cosmological model.
- */
-__attribute__((always_inline)) INLINE static void hydro_reset_predicted_values(
-    struct part* restrict p, const struct xpart* restrict xp,
-    const struct cosmology* cosmo) {
-  // MATTHIEU: Do we need something here?
-}
-
-/**
- * @brief Converts the hydrodynamic variables from the initial condition file to
- * conserved variables that can be used during the integration
- *
- * We no longer do this, as the mass needs to be provided in the initial
- * condition file, and the mass alone is enough to initialize all conserved
- * variables. This is now done in hydro_first_init_part.
- *
- * @param p The particle to act upon.
- */
-__attribute__((always_inline)) INLINE static void hydro_convert_quantities(
-    struct part* p, struct xpart* xp, const struct cosmology* cosmo,
-    const struct hydro_props* hydro_props) {
-
-  p->conserved.energy /= cosmo->a_factor_internal_energy;
-}
-
 /**
  * @brief Extra operations to be done during the drift
  *
diff --git a/src/hydro/Gizmo/MFM/hydro_getters.h b/src/hydro/Gizmo/MFM/hydro_getters.h
index 9ae88b199607c5b4bfa7d3aeed24ae688cebdbee..c7353797002552566666f11179afb418af9185e7 100644
--- a/src/hydro/Gizmo/MFM/hydro_getters.h
+++ b/src/hydro/Gizmo/MFM/hydro_getters.h
@@ -40,6 +40,17 @@ hydro_part_get_primitive_variables(const struct part* restrict p, float* W) {
   W[4] = p->P;
 }
 
+/**
+ * @brief Get the degenerate case correction factor for the given particle.
+ *
+ * @param p Particle.
+ * @return Degenerate case correction factor.
+ */
+__attribute__((always_inline)) INLINE static float hydro_part_get_wcorr(
+    const struct part* restrict p) {
+  return p->geometry.wcorr;
+}
+
 /**
  * @brief Get the gradients of the primitive variables for the given particle.
  *
diff --git a/src/hydro/Gizmo/MFM/hydro_setters.h b/src/hydro/Gizmo/MFM/hydro_setters.h
index dc19cb1b9f2b8f4950d907c2902ebf1bf3f6d0d3..a503833daccdce24124dfa25c64575230e3e5327 100644
--- a/src/hydro/Gizmo/MFM/hydro_setters.h
+++ b/src/hydro/Gizmo/MFM/hydro_setters.h
@@ -67,6 +67,20 @@ __attribute__((always_inline)) INLINE static void hydro_part_set_wcorr(
   p->geometry.wcorr = wcorr;
 }
 
+/**
+ * @brief Reset the fluxes for the given particle.
+ *
+ * @param p Particle.
+ */
+__attribute__((always_inline)) INLINE static void hydro_part_reset_fluxes(
+    struct part* restrict p) {
+
+  p->flux.momentum[0] = 0.0f;
+  p->flux.momentum[1] = 0.0f;
+  p->flux.momentum[2] = 0.0f;
+  p->flux.energy = 0.0f;
+}
+
 /**
  * @brief Update the fluxes for the particle with the given contributions,
  * assuming the particle is to the left of the interparticle interface.
diff --git a/src/hydro/Gizmo/MFV/hydro.h b/src/hydro/Gizmo/MFV/hydro.h
index f6673fbba3dca6ca6f6f6be4cb845a0950f43540..30e06c9f771c38431e4bdf25fcc303d5469815da 100644
--- a/src/hydro/Gizmo/MFV/hydro.h
+++ b/src/hydro/Gizmo/MFV/hydro.h
@@ -37,357 +37,6 @@
 
 #include <float.h>
 
-/**
- * @brief Finishes the volume calculation.
- *
- * Multiplies the density and number of neighbours by the appropiate constants
- * and adds the self-contribution term. Calculates the volume and uses it to
- * update the primitive variables (based on the conserved variables). The latter
- * should only be done for active particles. This is okay, since this method is
- * only called for active particles.
- *
- * Multiplies the components of the matrix E with the appropriate constants and
- * inverts it. Initializes the variables used during the gradient loop. This
- * cannot be done in hydro_prepare_force, since that method is called for all
- * particles, and not just the active ones. If we would initialize the
- * variables there, gradients for passive particles would be zero, while we
- * actually use the old gradients in the flux calculation between active and
- * passive particles.
- *
- * @param p The particle to act upon.
- * @param cosmo The cosmological model.
- */
-__attribute__((always_inline)) INLINE static void hydro_end_density(
-    struct part* restrict p, const struct cosmology* cosmo) {
-
-  /* Some smoothing length multiples. */
-  const float h = p->h;
-  const float ih = 1.0f / h;
-  const float ihdim = pow_dimension(ih);
-  const float ihdim_plus_one = ihdim * ih;
-
-  /* Final operation on the density. */
-  p->density.wcount += kernel_root;
-  p->density.wcount *= ihdim;
-
-  p->density.wcount_dh -= hydro_dimension * kernel_root;
-  p->density.wcount_dh *= ihdim_plus_one;
-
-  /* Final operation on the geometry. */
-  /* we multiply with the smoothing kernel normalization ih3 and calculate the
-   * volume */
-  const float volume = 1.f / (ihdim * (p->geometry.volume + kernel_root));
-  p->geometry.volume = volume;
-
-  /* we multiply with the smoothing kernel normalization */
-  p->geometry.matrix_E[0][0] = ihdim * p->geometry.matrix_E[0][0];
-  p->geometry.matrix_E[0][1] = ihdim * p->geometry.matrix_E[0][1];
-  p->geometry.matrix_E[0][2] = ihdim * p->geometry.matrix_E[0][2];
-  p->geometry.matrix_E[1][0] = ihdim * p->geometry.matrix_E[1][0];
-  p->geometry.matrix_E[1][1] = ihdim * p->geometry.matrix_E[1][1];
-  p->geometry.matrix_E[1][2] = ihdim * p->geometry.matrix_E[1][2];
-  p->geometry.matrix_E[2][0] = ihdim * p->geometry.matrix_E[2][0];
-  p->geometry.matrix_E[2][1] = ihdim * p->geometry.matrix_E[2][1];
-  p->geometry.matrix_E[2][2] = ihdim * p->geometry.matrix_E[2][2];
-
-  p->geometry.centroid[0] *= kernel_norm;
-  p->geometry.centroid[1] *= kernel_norm;
-  p->geometry.centroid[2] *= kernel_norm;
-
-  p->geometry.centroid[0] /= p->density.wcount;
-  p->geometry.centroid[1] /= p->density.wcount;
-  p->geometry.centroid[2] /= p->density.wcount;
-
-  /* Check the condition number to see if we have a stable geometry. */
-  float condition_number_E = 0.0f;
-  int i, j;
-  for (i = 0; i < 3; ++i) {
-    for (j = 0; j < 3; ++j) {
-      condition_number_E +=
-          p->geometry.matrix_E[i][j] * p->geometry.matrix_E[i][j];
-    }
-  }
-
-  invert_dimension_by_dimension_matrix(p->geometry.matrix_E);
-
-  float condition_number_Einv = 0.0f;
-  for (i = 0; i < 3; ++i) {
-    for (j = 0; j < 3; ++j) {
-      condition_number_Einv +=
-          p->geometry.matrix_E[i][j] * p->geometry.matrix_E[i][j];
-    }
-  }
-
-  float condition_number =
-      hydro_dimension_inv * sqrtf(condition_number_E * condition_number_Einv);
-
-  if (condition_number > const_gizmo_max_condition_number &&
-      p->density.wcorr > const_gizmo_min_wcorr) {
-#ifdef GIZMO_PATHOLOGICAL_ERROR
-    error("Condition number larger than %g (%g)!",
-          const_gizmo_max_condition_number, condition_number);
-#endif
-#ifdef GIZMO_PATHOLOGICAL_WARNING
-    message("Condition number too large: %g (> %g, p->id: %llu)!",
-            condition_number, const_gizmo_max_condition_number, p->id);
-#endif
-    /* add a correction to the number of neighbours for this particle */
-    p->density.wcorr *= const_gizmo_w_correction_factor;
-  }
-
-  hydro_gradients_init(p);
-
-  /* compute primitive variables */
-  /* eqns (3)-(5) */
-  const float m = p->conserved.mass;
-
-#ifdef SWIFT_DEBUG_CHECKS
-  if (m < 0.) {
-    error("Mass is negative!");
-  }
-
-  if (volume == 0.) {
-    error("Volume is 0!");
-  }
-#endif
-
-  // MATTHIEU: Bert is this correct? Do we need cosmology terms here?
-  float momentum[3];
-  momentum[0] = p->conserved.momentum[0];
-  momentum[1] = p->conserved.momentum[1];
-  momentum[2] = p->conserved.momentum[2];
-  p->primitives.rho = m / volume;
-  if (m == 0.) {
-    p->primitives.v[0] = 0.;
-    p->primitives.v[1] = 0.;
-    p->primitives.v[2] = 0.;
-  } else {
-    p->primitives.v[0] = momentum[0] / m;
-    p->primitives.v[1] = momentum[1] / m;
-    p->primitives.v[2] = momentum[2] / m;
-  }
-
-#ifdef EOS_ISOTHERMAL_GAS
-  /* although the pressure is not formally used anywhere if an isothermal eos
-     has been selected, we still make sure it is set to the correct value */
-  p->primitives.P = gas_pressure_from_internal_energy(p->primitives.rho, 0.);
-#else
-
-  float energy = p->conserved.energy;
-
-#ifdef GIZMO_TOTAL_ENERGY
-  /* subtract the kinetic energy; we want the thermal energy */
-  energy -= 0.5f * (momentum[0] * p->primitives.v[0] +
-                    momentum[1] * p->primitives.v[1] +
-                    momentum[2] * p->primitives.v[2]);
-#endif
-
-  /* energy contains the total thermal energy, we want the specific energy.
-     this is why we divide by the volume, and not by the density */
-  p->primitives.P = hydro_gamma_minus_one * energy / volume;
-#endif
-
-  /* sanity checks */
-  gizmo_check_physical_quantities("density", "pressure", p->primitives.rho,
-                                  p->primitives.v[0], p->primitives.v[1],
-                                  p->primitives.v[2], p->primitives.P);
-
-#ifdef GIZMO_LLOYD_ITERATION
-  /* overwrite primitive variables to make sure they still have safe values */
-  p->primitives.rho = 1.;
-  p->primitives.v[0] = 0.;
-  p->primitives.v[1] = 0.;
-  p->primitives.v[2] = 0.;
-  p->primitives.P = 1.;
-#endif
-
-  /* Add a correction factor to wcount (to force a neighbour number increase if
-     the geometry matrix is close to singular) */
-  p->density.wcount *= p->density.wcorr;
-  p->density.wcount_dh *= p->density.wcorr;
-}
-
-/**
- * @brief Sets all particle fields to sensible values when the #part has 0 ngbs.
- *
- * @param p The particle to act upon
- * @param xp The extended particle data to act upon
- * @param cosmo The cosmological model.
- */
-__attribute__((always_inline)) INLINE static void hydro_part_has_no_neighbours(
-    struct part* restrict p, struct xpart* restrict xp,
-    const struct cosmology* cosmo) {
-
-  /* Some smoothing length multiples. */
-  const float h = p->h;
-  const float h_inv = 1.0f / h;                 /* 1/h */
-  const float h_inv_dim = pow_dimension(h_inv); /* 1/h^d */
-
-  /* Re-set problematic values */
-  p->density.wcount = kernel_root * h_inv_dim;
-  p->density.wcount_dh = 0.f;
-  p->geometry.volume = 1.0f;
-  p->geometry.matrix_E[0][0] = 1.0f;
-  p->geometry.matrix_E[0][1] = 0.0f;
-  p->geometry.matrix_E[0][2] = 0.0f;
-  p->geometry.matrix_E[1][0] = 0.0f;
-  p->geometry.matrix_E[1][1] = 1.0f;
-  p->geometry.matrix_E[1][2] = 0.0f;
-  p->geometry.matrix_E[2][0] = 0.0f;
-  p->geometry.matrix_E[2][1] = 0.0f;
-  p->geometry.matrix_E[2][2] = 1.0f;
-  /* centroid is relative w.r.t. particle position */
-  /* by setting the centroid to 0.0f, we make sure no velocity correction is
-     applied */
-  p->geometry.centroid[0] = 0.0f;
-  p->geometry.centroid[1] = 0.0f;
-  p->geometry.centroid[2] = 0.0f;
-}
-
-/**
- * @brief Prepare a particle for the gradient calculation.
- *
- * This function is called after the density loop and before the gradient loop.
- *
- * We use it to set the physical timestep for the particle and to copy the
- * actual velocities, which we need to boost our interfaces during the flux
- * calculation. We also initialize the variables used for the time step
- * calculation.
- *
- * @param p The particle to act upon.
- * @param xp The extended particle data to act upon.
- * @param cosmo The cosmological model.
- * @param hydro_props Hydrodynamic properties.
- */
-__attribute__((always_inline)) INLINE static void hydro_prepare_gradient(
-    struct part* restrict p, struct xpart* restrict xp,
-    const struct cosmology* cosmo, const struct hydro_props* hydro_props) {
-
-  /* Initialize time step criterion variables */
-  p->timestepvars.vmax = 0.;
-
-  // MATTHIEU: Bert is this correct? Do we need cosmology terms here?
-
-  /* Set the actual velocity of the particle */
-  hydro_velocities_prepare_force(p, xp);
-}
-
-/**
- * @brief Finishes the gradient calculation.
- *
- * Just a wrapper around hydro_gradients_finalize, which can be an empty method,
- * in which case no gradients are used.
- *
- * @param p The particle to act upon.
- */
-__attribute__((always_inline)) INLINE static void hydro_end_gradient(
-    struct part* p) {
-
-  hydro_gradients_finalize(p);
-
-#ifdef GIZMO_LLOYD_ITERATION
-  /* reset the gradients to zero, as we don't want them */
-  hydro_gradients_init(p);
-#endif
-}
-
-/**
- * @brief Prepare a particle for the force calculation.
- *
- * This function is called in the ghost task to convert some quantities coming
- * from the density loop over neighbours into quantities ready to be used in the
- * force loop over neighbours. Quantities are typically read from the density
- * sub-structure and written to the force sub-structure.
- * Examples of calculations done here include the calculation of viscosity term
- * constants, thermal conduction terms, hydro conversions, etc.
- *
- * @param p The particle to act upon
- * @param xp The extended particle data to act upon
- * @param cosmo The current cosmological model.
- * @param hydro_props Hydrodynamic properties.
- * @param dt_alpha The time-step used to evolve non-cosmological quantities such
- *                 as the artificial viscosity.
- */
-__attribute__((always_inline)) INLINE static void hydro_prepare_force(
-    struct part* restrict p, struct xpart* restrict xp,
-    const struct cosmology* cosmo, const struct hydro_props* hydro_props,
-    const float dt_alpha) {
-
-  /* Initialise values that are used in the force loop */
-  p->gravity.mflux[0] = 0.0f;
-  p->gravity.mflux[1] = 0.0f;
-  p->gravity.mflux[2] = 0.0f;
-
-  p->conserved.flux.mass = 0.0f;
-  p->conserved.flux.momentum[0] = 0.0f;
-  p->conserved.flux.momentum[1] = 0.0f;
-  p->conserved.flux.momentum[2] = 0.0f;
-  p->conserved.flux.energy = 0.0f;
-}
-
-/**
- * @brief Reset acceleration fields of a particle
- *
- * This is actually not necessary for GIZMO, since we just set the accelerations
- * after the flux calculation.
- *
- * @param p The particle to act upon.
- */
-__attribute__((always_inline)) INLINE static void hydro_reset_acceleration(
-    struct part* p) {
-
-  /* Reset the acceleration. */
-  p->a_hydro[0] = 0.0f;
-  p->a_hydro[1] = 0.0f;
-  p->a_hydro[2] = 0.0f;
-
-  /* Reset the time derivatives. */
-  p->force.h_dt = 0.0f;
-}
-
-/**
- * @brief Resets the variables that are required for a gradient calculation.
- *
- * This function is called after hydro_prepare_gradient.
- *
- * @param p The particle to act upon.
- * @param xp The extended particle data to act upon.
- * @param cosmo The cosmological model.
- */
-__attribute__((always_inline)) INLINE static void hydro_reset_gradient(
-    struct part* restrict p) {}
-
-/**
- * @brief Sets the values to be predicted in the drifts to their values at a
- * kick time
- *
- * @param p The particle.
- * @param xp The extended data of this particle.
- * @param cosmo The cosmological model.
- */
-__attribute__((always_inline)) INLINE static void hydro_reset_predicted_values(
-    struct part* restrict p, const struct xpart* restrict xp,
-    const struct cosmology* cosmo) {
-  // MATTHIEU: Apply the entropy floor here.
-}
-
-/**
- * @brief Converts the hydrodynamic variables from the initial condition file to
- * conserved variables that can be used during the integration
- *
- * We no longer do this, as the mass needs to be provided in the initial
- * condition file, and the mass alone is enough to initialize all conserved
- * variables. This is now done in hydro_first_init_part.
- *
- * @param p The particle to act upon.
- */
-__attribute__((always_inline)) INLINE static void hydro_convert_quantities(
-    struct part* p, struct xpart* xp, const struct cosmology* cosmo,
-    const struct hydro_props* hydro_props) {
-
-  p->conserved.energy /= cosmo->a_factor_internal_energy;
-}
-
 /**
  * @brief Extra operations to be done during the drift
  *
diff --git a/src/hydro/Gizmo/MFV/hydro_getters.h b/src/hydro/Gizmo/MFV/hydro_getters.h
index c66b675d673cd81809427bddc4343851dff85867..94aca11276ef2f67bea930f780663c4546ee578a 100644
--- a/src/hydro/Gizmo/MFV/hydro_getters.h
+++ b/src/hydro/Gizmo/MFV/hydro_getters.h
@@ -40,6 +40,17 @@ hydro_part_get_primitive_variables(const struct part* restrict p, float* W) {
   W[4] = p->primitives.P;
 }
 
+/**
+ * @brief Get the degenerate case correction factor for the given particle.
+ *
+ * @param p Particle.
+ * @return Degenerate case correction factor.
+ */
+__attribute__((always_inline)) INLINE static float hydro_part_get_wcorr(
+    const struct part* restrict p) {
+  return p->density.wcorr;
+}
+
 /**
  * @brief Get the gradients of the primitive variables for the given particle.
  *
diff --git a/src/hydro/Gizmo/MFV/hydro_setters.h b/src/hydro/Gizmo/MFV/hydro_setters.h
index 9e5cc7d6202d3800526828e25b2cf8232380f991..770336ea63ee325b71fdbd5c2648bc9e2ff9189c 100644
--- a/src/hydro/Gizmo/MFV/hydro_setters.h
+++ b/src/hydro/Gizmo/MFV/hydro_setters.h
@@ -67,6 +67,25 @@ __attribute__((always_inline)) INLINE static void hydro_part_set_wcorr(
   p->density.wcorr = wcorr;
 }
 
+/**
+ * @brief Reset the fluxes for the given particle.
+ *
+ * @param p Particle.
+ */
+__attribute__((always_inline)) INLINE static void hydro_part_reset_fluxes(
+    struct part* restrict p) {
+
+  p->conserved.flux.mass = 0.0f;
+  p->conserved.flux.momentum[0] = 0.0f;
+  p->conserved.flux.momentum[1] = 0.0f;
+  p->conserved.flux.momentum[2] = 0.0f;
+  p->conserved.flux.energy = 0.0f;
+
+  p->gravity.mflux[0] = 0.0f;
+  p->gravity.mflux[1] = 0.0f;
+  p->gravity.mflux[2] = 0.0f;
+}
+
 /**
  * @brief Update the fluxes for the particle with the given contributions,
  * assuming the particle is to the left of the interparticle interface.
diff --git a/src/hydro/Gizmo/hydro.h b/src/hydro/Gizmo/hydro.h
index 3f729e5eb6dd0aafbf741ad38c4a3502427a5931..4b59f498acba5dbc010273d3693e3eb0456ca3d7 100644
--- a/src/hydro/Gizmo/hydro.h
+++ b/src/hydro/Gizmo/hydro.h
@@ -22,6 +22,7 @@
 //#define GIZMO_LLOYD_ITERATION
 
 #include "hydro_getters.h"
+#include "hydro_gradients.h"
 #include "hydro_setters.h"
 #include "hydro_space.h"
 
@@ -213,6 +214,354 @@ __attribute__((always_inline)) INLINE static void hydro_init_part(
   p->geometry.centroid[2] = 0.0f;
 }
 
+/**
+ * @brief Finishes the volume calculation.
+ *
+ * Multiplies the density and number of neighbours by the appropiate constants
+ * and adds the self-contribution term. Calculates the volume and uses it to
+ * update the primitive variables (based on the conserved variables). The latter
+ * should only be done for active particles. This is okay, since this method is
+ * only called for active particles.
+ *
+ * Multiplies the components of the matrix E with the appropriate constants and
+ * inverts it. Initializes the variables used during the gradient loop. This
+ * cannot be done in hydro_prepare_force, since that method is called for all
+ * particles, and not just the active ones. If we would initialize the
+ * variables there, gradients for passive particles would be zero, while we
+ * actually use the old gradients in the flux calculation between active and
+ * passive particles.
+ *
+ * @param p The particle to act upon.
+ * @param cosmo The cosmological model.
+ */
+__attribute__((always_inline)) INLINE static void hydro_end_density(
+    struct part* restrict p, const struct cosmology* cosmo) {
+
+  /* Some smoothing length multiples. */
+  const float h = p->h;
+  const float ih = 1.0f / h;
+  const float ihdim = pow_dimension(ih);
+  const float ihdim_plus_one = ihdim * ih;
+
+  /* Final operation on the density. */
+  p->density.wcount += kernel_root;
+  p->density.wcount *= ihdim;
+
+  p->density.wcount_dh -= hydro_dimension * kernel_root;
+  p->density.wcount_dh *= ihdim_plus_one;
+
+  /* Final operation on the geometry. */
+  /* we multiply with the smoothing kernel normalization ih3 and calculate the
+   * volume */
+  const float volume_inv = ihdim * (p->geometry.volume + kernel_root);
+  const float volume = 1.0f / volume_inv;
+  p->geometry.volume = volume;
+
+  /* we multiply with the smoothing kernel normalization */
+  p->geometry.matrix_E[0][0] = ihdim * p->geometry.matrix_E[0][0];
+  p->geometry.matrix_E[0][1] = ihdim * p->geometry.matrix_E[0][1];
+  p->geometry.matrix_E[0][2] = ihdim * p->geometry.matrix_E[0][2];
+  p->geometry.matrix_E[1][0] = ihdim * p->geometry.matrix_E[1][0];
+  p->geometry.matrix_E[1][1] = ihdim * p->geometry.matrix_E[1][1];
+  p->geometry.matrix_E[1][2] = ihdim * p->geometry.matrix_E[1][2];
+  p->geometry.matrix_E[2][0] = ihdim * p->geometry.matrix_E[2][0];
+  p->geometry.matrix_E[2][1] = ihdim * p->geometry.matrix_E[2][1];
+  p->geometry.matrix_E[2][2] = ihdim * p->geometry.matrix_E[2][2];
+
+  p->geometry.centroid[0] *= kernel_norm;
+  p->geometry.centroid[1] *= kernel_norm;
+  p->geometry.centroid[2] *= kernel_norm;
+
+  const float wcount_inv = 1.0f / p->density.wcount;
+  p->geometry.centroid[0] *= wcount_inv;
+  p->geometry.centroid[1] *= wcount_inv;
+  p->geometry.centroid[2] *= wcount_inv;
+
+  /* Check the condition number to see if we have a stable geometry. */
+  float condition_number_E = 0.0f;
+  int i, j;
+  for (i = 0; i < 3; ++i) {
+    for (j = 0; j < 3; ++j) {
+      condition_number_E +=
+          p->geometry.matrix_E[i][j] * p->geometry.matrix_E[i][j];
+    }
+  }
+
+  invert_dimension_by_dimension_matrix(p->geometry.matrix_E);
+
+  float condition_number_Einv = 0.0f;
+  for (i = 0; i < 3; ++i) {
+    for (j = 0; j < 3; ++j) {
+      condition_number_Einv +=
+          p->geometry.matrix_E[i][j] * p->geometry.matrix_E[i][j];
+    }
+  }
+
+  const float condition_number =
+      hydro_dimension_inv * sqrtf(condition_number_E * condition_number_Einv);
+
+  if (condition_number > const_gizmo_max_condition_number &&
+      hydro_part_get_wcorr(p) > const_gizmo_min_wcorr) {
+#ifdef GIZMO_PATHOLOGICAL_ERROR
+    error("Condition number larger than %g (%g)!",
+          const_gizmo_max_condition_number, condition_number);
+#endif
+#ifdef GIZMO_PATHOLOGICAL_WARNING
+    message("Condition number too large: %g (> %g, p->id: %llu)!",
+            condition_number, const_gizmo_max_condition_number, p->id);
+#endif
+    /* add a correction to the number of neighbours for this particle */
+    hydro_part_set_wcorr(
+        p, const_gizmo_w_correction_factor * hydro_part_get_wcorr(p));
+  }
+
+  /* need to figure out whether or not to move this to hydro_prepare_gradient */
+  hydro_gradients_init(p);
+
+  /* compute primitive variables */
+  /* eqns (3)-(5) */
+  const float Q[5] = {p->conserved.mass, p->conserved.momentum[0],
+                      p->conserved.momentum[1], p->conserved.momentum[2],
+                      p->conserved.energy};
+
+#ifdef SWIFT_DEBUG_CHECKS
+  if (Q[0] < 0.) {
+    error("Mass is negative!");
+  }
+
+  if (volume == 0.) {
+    error("Volume is 0!");
+  }
+#endif
+
+  float W[5];
+
+  W[0] = Q[0] * volume_inv;
+  if (Q[0] == 0.0f) {
+    W[1] = 0.;
+    W[2] = 0.;
+    W[3] = 0.;
+  } else {
+    const float m_inv = 1.0f / Q[0];
+    W[1] = Q[1] * m_inv;
+    W[2] = Q[2] * m_inv;
+    W[3] = Q[3] * m_inv;
+  }
+
+#ifdef EOS_ISOTHERMAL_GAS
+  /* although the pressure is not formally used anywhere if an isothermal eos
+     has been selected, we still make sure it is set to the correct value */
+  W[4] = gas_pressure_from_internal_energy(W[0], 0.0f);
+#else
+
+#ifdef GIZMO_TOTAL_ENERGY
+  /* subtract the kinetic energy; we want the thermal energy */
+  Q[4] -= 0.5f * (Q[1] * W[1] + Q[2] * W[2] + Q[3] * W[3]);
+#endif
+
+  /* energy contains the total thermal energy, we want the specific energy.
+     this is why we divide by the volume, and not by the density */
+  W[4] = hydro_gamma_minus_one * Q[4] * volume_inv;
+#endif
+
+  /* sanity checks */
+  gizmo_check_physical_quantities("density", "pressure", W[0], W[1], W[2], W[3],
+                                  W[4]);
+
+#ifdef GIZMO_LLOYD_ITERATION
+  /* overwrite primitive variables to make sure they still have safe values */
+  W[0] = 1.0f;
+  W[1] = 0.0f;
+  W[2] = 0.0f;
+  W[3] = 0.0f;
+  W[4] = 1.0f;
+#endif
+
+  hydro_part_set_primitive_variables(p, W);
+
+  /* Add a correction factor to wcount (to force a neighbour number increase if
+     the geometry matrix is close to singular) */
+  p->density.wcount *= hydro_part_get_wcorr(p);
+  p->density.wcount_dh *= hydro_part_get_wcorr(p);
+}
+
+/**
+ * @brief Sets all particle fields to sensible values when the #part has 0 ngbs.
+ *
+ * @param p The particle to act upon
+ * @param xp The extended particle data to act upon
+ * @param cosmo The cosmological model.
+ */
+__attribute__((always_inline)) INLINE static void hydro_part_has_no_neighbours(
+    struct part* restrict p, struct xpart* restrict xp,
+    const struct cosmology* cosmo) {
+
+  /* Some smoothing length multiples. */
+  const float h = p->h;
+  const float h_inv = 1.0f / h;                 /* 1/h */
+  const float h_inv_dim = pow_dimension(h_inv); /* 1/h^d */
+
+  /* Re-set problematic values */
+  p->density.wcount = kernel_root * h_inv_dim;
+  p->density.wcount_dh = 0.f;
+  p->geometry.volume = 1.0f;
+  p->geometry.matrix_E[0][0] = 1.0f;
+  p->geometry.matrix_E[0][1] = 0.0f;
+  p->geometry.matrix_E[0][2] = 0.0f;
+  p->geometry.matrix_E[1][0] = 0.0f;
+  p->geometry.matrix_E[1][1] = 1.0f;
+  p->geometry.matrix_E[1][2] = 0.0f;
+  p->geometry.matrix_E[2][0] = 0.0f;
+  p->geometry.matrix_E[2][1] = 0.0f;
+  p->geometry.matrix_E[2][2] = 1.0f;
+  /* centroid is relative w.r.t. particle position */
+  /* by setting the centroid to 0.0f, we make sure no velocity correction is
+     applied */
+  p->geometry.centroid[0] = 0.0f;
+  p->geometry.centroid[1] = 0.0f;
+  p->geometry.centroid[2] = 0.0f;
+}
+
+/**
+ * @brief Prepare a particle for the gradient calculation.
+ *
+ * This function is called after the density loop and before the gradient loop.
+ *
+ * We use it to set the physical timestep for the particle and to copy the
+ * actual velocities, which we need to boost our interfaces during the flux
+ * calculation. We also initialize the variables used for the time step
+ * calculation.
+ *
+ * @param p The particle to act upon.
+ * @param xp The extended particle data to act upon.
+ * @param cosmo The cosmological model.
+ * @param hydro_props Hydrodynamic properties.
+ */
+__attribute__((always_inline)) INLINE static void hydro_prepare_gradient(
+    struct part* restrict p, struct xpart* restrict xp,
+    const struct cosmology* cosmo, const struct hydro_props* hydro_props) {
+
+  /* Initialize time step criterion variables */
+  p->timestepvars.vmax = 0.;
+
+  /* not sure if we need to do this here or in end_density() */
+  hydro_gradients_init(p);
+
+#if defined(GIZMO_MFV_SPH)
+  /* Set the actual velocity of the particle */
+  hydro_velocities_prepare_force(p, xp);
+#endif
+}
+
+/**
+ * @brief Resets the variables that are required for a gradient calculation.
+ *
+ * This function is called after hydro_prepare_gradient.
+ *
+ * @param p The particle to act upon.
+ * @param xp The extended particle data to act upon.
+ * @param cosmo The cosmological model.
+ */
+__attribute__((always_inline)) INLINE static void hydro_reset_gradient(
+    struct part* restrict p) {}
+
+/**
+ * @brief Finishes the gradient calculation.
+ *
+ * Just a wrapper around hydro_gradients_finalize, which can be an empty method,
+ * in which case no gradients are used.
+ *
+ * This method also initializes the force loop variables.
+ *
+ * @param p The particle to act upon.
+ */
+__attribute__((always_inline)) INLINE static void hydro_end_gradient(
+    struct part* p) {
+
+  hydro_gradients_finalize(p);
+
+#ifdef GIZMO_LLOYD_ITERATION
+  /* reset the gradients to zero, as we don't want them */
+  hydro_gradients_init(p);
+#endif
+}
+
+/**
+ * @brief Prepare a particle for the force calculation.
+ *
+ * This function is called in the ghost task to convert some quantities coming
+ * from the density loop over neighbours into quantities ready to be used in the
+ * force loop over neighbours. Quantities are typically read from the density
+ * sub-structure and written to the force sub-structure.
+ * Examples of calculations done here include the calculation of viscosity term
+ * constants, thermal conduction terms, hydro conversions, etc.
+ *
+ * @param p The particle to act upon
+ * @param xp The extended particle data to act upon
+ * @param cosmo The current cosmological model.
+ * @param hydro_props Hydrodynamic properties.
+ * @param dt_alpha The time-step used to evolve non-cosmological quantities such
+ *                 as the artificial viscosity.
+ */
+__attribute__((always_inline)) INLINE static void hydro_prepare_force(
+    struct part* restrict p, struct xpart* restrict xp,
+    const struct cosmology* cosmo, const struct hydro_props* hydro_props,
+    const float dt_alpha) {
+
+  hydro_part_reset_fluxes(p);
+}
+
+/**
+ * @brief Reset acceleration fields of a particle
+ *
+ * This is actually not necessary for GIZMO, since we just set the accelerations
+ * after the flux calculation.
+ *
+ * @param p The particle to act upon.
+ */
+__attribute__((always_inline)) INLINE static void hydro_reset_acceleration(
+    struct part* p) {
+
+  /* Reset the acceleration. */
+  p->a_hydro[0] = 0.0f;
+  p->a_hydro[1] = 0.0f;
+  p->a_hydro[2] = 0.0f;
+
+  /* Reset the time derivatives. */
+  p->force.h_dt = 0.0f;
+}
+
+/**
+ * @brief Sets the values to be predicted in the drifts to their values at a
+ * kick time
+ *
+ * @param p The particle.
+ * @param xp The extended data of this particle.
+ * @param cosmo The cosmological model.
+ */
+__attribute__((always_inline)) INLINE static void hydro_reset_predicted_values(
+    struct part* restrict p, const struct xpart* restrict xp,
+    const struct cosmology* cosmo) {
+  // MATTHIEU: Apply the entropy floor here.
+}
+
+/**
+ * @brief Converts the hydrodynamic variables from the initial condition file to
+ * conserved variables that can be used during the integration
+ *
+ * We no longer do this, as the mass needs to be provided in the initial
+ * condition file, and the mass alone is enough to initialize all conserved
+ * variables. This is now done in hydro_first_init_part.
+ *
+ * @param p The particle to act upon.
+ */
+__attribute__((always_inline)) INLINE static void hydro_convert_quantities(
+    struct part* p, struct xpart* xp, const struct cosmology* cosmo,
+    const struct hydro_props* hydro_props) {
+
+  p->conserved.energy /= cosmo->a_factor_internal_energy;
+}
+
 #if defined(GIZMO_MFV_SPH)
 #include "MFV/hydro.h"
 #define SPH_IMPLEMENTATION "GIZMO MFV (Hopkins 2015)"