diff --git a/.gitignore b/.gitignore
index 672a71c3ed03ec73df5dbc917572c8f87a0967d1..8c3ede8f3125f5024c1fe01a405024d1cf5a7f19 100644
--- a/.gitignore
+++ b/.gitignore
@@ -119,6 +119,7 @@ tests/testPotentialPair
 tests/testEOS
 tests/testEOS*.txt
 tests/testEOS*.png
+tests/testUtilities
 
 theory/latex/swift.pdf
 theory/SPH/Kernels/kernels.pdf
diff --git a/configure.ac b/configure.ac
index 0640d98aaaa1494da52def5a4118a9204436e608..56018272debbb9e9ccb2f425eff45b97c358aec9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -855,7 +855,7 @@ fi
 # Hydro scheme.
 AC_ARG_WITH([hydro],
    [AS_HELP_STRING([--with-hydro=<scheme>],
-      [Hydro dynamics to use @<:@gadget2, minimal, pressure-entropy, pressure-energy, default, gizmo, shadowfax debug default: gadget2@:>@]
+      [Hydro dynamics to use @<:@gadget2, minimal, pressure-entropy, pressure-energy, default, gizmo-mfv, gizmo-mfm, shadowfax, minimal-multi-mat, debug default: gadget2@:>@]
    )],
    [with_hydro="$withval"],
    [with_hydro="gadget2"]
@@ -885,8 +885,11 @@ case "$with_hydro" in
    default)
       AC_DEFINE([DEFAULT_SPH], [1], [Default SPH])
    ;;
-   gizmo)
-      AC_DEFINE([GIZMO_SPH], [1], [GIZMO SPH])
+   gizmo-mfv)
+      AC_DEFINE([GIZMO_MFV_SPH], [1], [GIZMO MFV SPH])
+   ;;
+   gizmo-mfm)
+      AC_DEFINE([GIZMO_MFM_SPH], [1], [GIZMO MFM SPH])
    ;;
    shadowfax)
       AC_DEFINE([SHADOWFAX_SPH], [1], [Shadowfax SPH])
diff --git a/examples/MoonFormingImpact/moon_forming_impact.yml b/examples/MoonFormingImpact/moon_forming_impact.yml
index 7d726bc02ba4fb6c8dd02f74907ffc48c3ed9431..323adf7f3ac73f41b45b50eaa76a95033dca35d7 100644
--- a/examples/MoonFormingImpact/moon_forming_impact.yml
+++ b/examples/MoonFormingImpact/moon_forming_impact.yml
@@ -42,3 +42,7 @@ Gravity:
 InitialConditions:
                                         # The initial conditions file to read
     file_name:  moon_forming_impact.hdf5
+
+# Parameters related to the equation of state
+EoS:
+    planetary_use_Til:    1                       # Whether to prepare the Tillotson EOS
diff --git a/examples/UranusImpact/uranus_impact.yml b/examples/UranusImpact/uranus_impact.yml
index aae9f66847a9f9b55984ea5d2ea1c79099c01e95..fabddca00f80fcdd79ff6114ff0544cd251046f4 100644
--- a/examples/UranusImpact/uranus_impact.yml
+++ b/examples/UranusImpact/uranus_impact.yml
@@ -41,3 +41,11 @@ Gravity:
 # Parameters related to the initial conditions
 InitialConditions:
     file_name:      uranus_impact.hdf5  # The initial conditions file to read
+
+# Parameters related to the equation of state
+EoS:
+    planetary_use_HM80:   1                       # Whether to prepare the Hubbard & MacFarlane (1980) EOS
+                                        # Table file paths
+    planetary_HM80_HHe_table_file:    /gpfs/data/dc-kege1/gihr_data/P_rho_u_HHe.txt
+    planetary_HM80_ice_table_file:    /gpfs/data/dc-kege1/gihr_data/P_rho_u_ice.txt
+    planetary_HM80_rock_table_file:   /gpfs/data/dc-kege1/gihr_data/P_rho_u_roc.txt
diff --git a/examples/parameter_example.yml b/examples/parameter_example.yml
index c9bc9811803051b274cd09cdcf6b58d1a65a0d7d..791db2758290e400d4ed9ffe5b8e0d4303057874 100644
--- a/examples/parameter_example.yml
+++ b/examples/parameter_example.yml
@@ -131,7 +131,16 @@ DomainDecomposition:
 # Parameters related to the equation of state ------------------------------------------
 
 EoS:
-  isothermal_internal_energy: 20.26784 # Thermal energy per unit mass for the case of isothermal equation of state (in internal units).
+  isothermal_internal_energy: 20.26784  # Thermal energy per unit mass for the case of isothermal equation of state (in internal units).
+
+  planetary_use_Til:    1   # (Optional) Whether to prepare the Tillotson EOS
+  planetary_use_HM80:   0   # (Optional) Whether to prepare the Hubbard & MacFarlane (1980) EOS
+  planetary_use_ANEOS:  0   # (Optional) Whether to prepare the ANEOS EOS
+  planetary_use_SESAME: 0   # (Optional) Whether to prepare the SESAME EOS
+                            # (Optional) Table file paths
+  planetary_HM80_HHe_table_file:    HM80_HHe.txt
+  planetary_HM80_ice_table_file:    HM80_ice.txt
+  planetary_HM80_rock_table_file:   HM80_rock.txt
 
 # Parameters related to external potentials --------------------------------------------
 
diff --git a/src/Makefile.am b/src/Makefile.am
index 677a4e9524a733de92d176992a67f7a18653c82d..374d2c4569efe0e07ca1b2558b679b33564da432 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -47,7 +47,7 @@ include_HEADERS = space.h runner.h queue.h task.h lock.h cell.h part.h const.h \
     sourceterms.h sourceterms_struct.h statistics.h memswap.h cache.h runner_doiact_vec.h profiler.h \
     dump.h logger.h active.h timeline.h xmf.h gravity_properties.h gravity_derivatives.h \
     gravity_softened_derivatives.h vector_power.h collectgroup.h hydro_space.h sort_part.h \
-    chemistry.h chemistry_io.h chemistry_struct.h cosmology.h restart.h space_getsid.h
+    chemistry.h chemistry_io.h chemistry_struct.h cosmology.h restart.h space_getsid.h utilities.h
 
 # Common source files
 AM_SOURCES = space.c runner.c queue.c task.c cell.c engine.c \
@@ -81,17 +81,28 @@ nobase_noinst_HEADERS = align.h approx_math.h atomic.h barrier.h cycle.h error.h
                  hydro/Gadget2/hydro_debug.h hydro/Gadget2/hydro_part.h \
 		 hydro/PressureEntropy/hydro.h hydro/PressureEntropy/hydro_iact.h hydro/PressureEntropy/hydro_io.h \
                  hydro/PressureEntropy/hydro_debug.h hydro/PressureEntropy/hydro_part.h \
-		 hydro/Gizmo/hydro.h hydro/Gizmo/hydro_iact.h \
-                 hydro/Gizmo/hydro_io.h hydro/Gizmo/hydro_debug.h \
-                 hydro/Gizmo/hydro_part.h \
-                 hydro/Gizmo/hydro_gradients_gizmo.h \
-                 hydro/Gizmo/hydro_gradients.h \
-                 hydro/Gizmo/hydro_gradients_sph.h \
-                 hydro/Gizmo/hydro_slope_limiters_cell.h \
-                 hydro/Gizmo/hydro_slope_limiters_face.h \
-                 hydro/Gizmo/hydro_slope_limiters.h \
-                 hydro/Gizmo/hydro_unphysical.h \
-                 hydro/Gizmo/hydro_velocities.h \
+		 hydro/GizmoMFV/hydro.h hydro/GizmoMFV/hydro_iact.h \
+                 hydro/GizmoMFV/hydro_io.h hydro/GizmoMFV/hydro_debug.h \
+                 hydro/GizmoMFV/hydro_part.h \
+                 hydro/GizmoMFV/hydro_gradients_gizmo.h \
+                 hydro/GizmoMFV/hydro_gradients.h \
+                 hydro/GizmoMFV/hydro_gradients_sph.h \
+                 hydro/GizmoMFV/hydro_slope_limiters_cell.h \
+                 hydro/GizmoMFV/hydro_slope_limiters_face.h \
+                 hydro/GizmoMFV/hydro_slope_limiters.h \
+                 hydro/GizmoMFV/hydro_unphysical.h \
+                 hydro/GizmoMFV/hydro_velocities.h \
+		 hydro/GizmoMFM/hydro.h hydro/GizmoMFM/hydro_iact.h \
+                 hydro/GizmoMFM/hydro_io.h hydro/GizmoMFM/hydro_debug.h \
+                 hydro/GizmoMFM/hydro_part.h \
+                 hydro/GizmoMFM/hydro_gradients_gizmo.h \
+                 hydro/GizmoMFM/hydro_gradients.h \
+                 hydro/GizmoMFM/hydro_gradients_sph.h \
+                 hydro/GizmoMFM/hydro_slope_limiters_cell.h \
+                 hydro/GizmoMFM/hydro_slope_limiters_face.h \
+                 hydro/GizmoMFM/hydro_slope_limiters.h \
+                 hydro/GizmoMFM/hydro_unphysical.h \
+                 hydro/GizmoMFM/hydro_velocities.h \
                  hydro/Shadowswift/hydro_debug.h \
                  hydro/Shadowswift/hydro_gradients.h hydro/Shadowswift/hydro.h \
                  hydro/Shadowswift/hydro_iact.h \
diff --git a/src/const.h b/src/const.h
index 928835c5ae0ac70d641243b0d183c2c0652cdc8a..6c5b5299c08efb7935b046ecfd0b3d67b7dc4c7a 100644
--- a/src/const.h
+++ b/src/const.h
@@ -53,7 +53,8 @@
 /* This option disables particle movement */
 //#define GIZMO_FIX_PARTICLES
 /* Try to keep cells regular by adding a correction velocity. */
-#define GIZMO_STEER_MOTION
+//#define GIZMO_STEER_MOTION
+/* Use the total energy instead of the thermal energy as conserved variable. */
 //#define GIZMO_TOTAL_ENERGY
 
 /* Options to control handling of unphysical values (GIZMO_SPH only). */
diff --git a/src/debug.c b/src/debug.c
index 2ca6a9bf832e2da1860d4f89f032c8a4f7bef86b..93d14952f523be5f1d1fa90484e9e7951f8e3f6e 100644
--- a/src/debug.c
+++ b/src/debug.c
@@ -50,8 +50,10 @@
 #include "./hydro/PressureEnergy/hydro_debug.h"
 #elif defined(DEFAULT_SPH)
 #include "./hydro/Default/hydro_debug.h"
-#elif defined(GIZMO_SPH)
-#include "./hydro/Gizmo/hydro_debug.h"
+#elif defined(GIZMO_MFV_SPH)
+#include "./hydro/GizmoMFV/hydro_debug.h"
+#elif defined(GIZMO_MFM_SPH)
+#include "./hydro/GizmoMFM/hydro_debug.h"
 #elif defined(SHADOWFAX_SPH)
 #include "./hydro/Shadowswift/hydro_debug.h"
 #elif defined(MINIMAL_MULTI_MAT_SPH)
diff --git a/src/equation_of_state/planetary/equation_of_state.h b/src/equation_of_state/planetary/equation_of_state.h
index fcc1c959152801253d465915d8b28b1552c913b8..d7a7f64f87bb126094163ada16dbd05e48d8cf8d 100644
--- a/src/equation_of_state/planetary/equation_of_state.h
+++ b/src/equation_of_state/planetary/equation_of_state.h
@@ -25,7 +25,7 @@
  *
  * For any/all of the planetary EOS. Each EOS type's functions are set in its
  * own header file: `equation_of_state/planetary/<eos_type>.h`.
- * See `material_id` for the available choices.
+ * See `eos_planetary_material_id` for the available choices.
  *
  * Not all functions are implemented for all EOS types, so not all can be used
  * with all hydro formulations yet.
@@ -95,7 +95,7 @@ enum eos_planetary_material_id {
   eos_planetary_id_ANEOS_iron =
       eos_planetary_type_ANEOS * eos_planetary_type_factor,
 
-  /*! ANEOS forsterite */
+  /*! MANEOS forsterite */
   eos_planetary_id_MANEOS_forsterite =
       eos_planetary_type_ANEOS * eos_planetary_type_factor + 1,
 
@@ -1077,46 +1077,62 @@ __attribute__((always_inline)) INLINE static void eos_init(
     struct eos_parameters *e, const struct phys_const *phys_const,
     const struct unit_system *us, const struct swift_params *params) {
 
+  // Table file names
+  char HM80_HHe_table_file[PARSER_MAX_LINE_SIZE];
+  char HM80_ice_table_file[PARSER_MAX_LINE_SIZE];
+  char HM80_rock_table_file[PARSER_MAX_LINE_SIZE];
+
   // Set the parameters and material IDs, load tables, etc. for each material
+  // and convert to internal units
   // Tillotson
-  set_Til_iron(&e->Til_iron, eos_planetary_id_Til_iron);
-  set_Til_granite(&e->Til_granite, eos_planetary_id_Til_granite);
-  set_Til_water(&e->Til_water, eos_planetary_id_Til_water);
+  if (parser_get_opt_param_int(params, "EoS:planetary_use_Til", 0)) {
+    set_Til_iron(&e->Til_iron, eos_planetary_id_Til_iron);
+    set_Til_granite(&e->Til_granite, eos_planetary_id_Til_granite);
+    set_Til_water(&e->Til_water, eos_planetary_id_Til_water);
+
+    convert_units_Til(&e->Til_iron, us);
+    convert_units_Til(&e->Til_granite, us);
+    convert_units_Til(&e->Til_water, us);
+  }
 
   // Hubbard & MacFarlane (1980)
-  set_HM80_HHe(&e->HM80_HHe, eos_planetary_id_HM80_HHe);
-  set_HM80_ice(&e->HM80_ice, eos_planetary_id_HM80_ice);
-  set_HM80_rock(&e->HM80_rock, eos_planetary_id_HM80_rock);
-
-  load_HM80_table(&e->HM80_HHe, HM80_HHe_table_file);
-  load_HM80_table(&e->HM80_ice, HM80_ice_table_file);
-  load_HM80_table(&e->HM80_rock, HM80_rock_table_file);
+  if (parser_get_opt_param_int(params, "EoS:planetary_use_HM80", 0)) {
+    set_HM80_HHe(&e->HM80_HHe, eos_planetary_id_HM80_HHe);
+    set_HM80_ice(&e->HM80_ice, eos_planetary_id_HM80_ice);
+    set_HM80_rock(&e->HM80_rock, eos_planetary_id_HM80_rock);
+
+    parser_get_param_string(params, "EoS:planetary_HM80_HHe_table_file",
+                            HM80_HHe_table_file);
+    parser_get_param_string(params, "EoS:planetary_HM80_ice_table_file",
+                            HM80_ice_table_file);
+    parser_get_param_string(params, "EoS:planetary_HM80_rock_table_file",
+                            HM80_rock_table_file);
+
+    load_HM80_table(&e->HM80_HHe, HM80_HHe_table_file);
+    load_HM80_table(&e->HM80_ice, HM80_ice_table_file);
+    load_HM80_table(&e->HM80_rock, HM80_rock_table_file);
+
+    convert_units_HM80(&e->HM80_HHe, us);
+    convert_units_HM80(&e->HM80_ice, us);
+    convert_units_HM80(&e->HM80_rock, us);
+  }
 
   // ANEOS
-  set_ANEOS_iron(&e->ANEOS_iron, eos_planetary_id_ANEOS_iron);
-  set_MANEOS_forsterite(&e->MANEOS_forsterite,
-                        eos_planetary_id_MANEOS_forsterite);
-
-  // SESAME
-  set_SESAME_iron(&e->SESAME_iron, eos_planetary_id_SESAME_iron);
-
-  // Convert to internal units
-  // Tillotson
-  convert_units_Til(&e->Til_iron, us);
-  convert_units_Til(&e->Til_granite, us);
-  convert_units_Til(&e->Til_water, us);
-
-  // Hubbard & MacFarlane (1980)
-  convert_units_HM80(&e->HM80_HHe, us);
-  convert_units_HM80(&e->HM80_ice, us);
-  convert_units_HM80(&e->HM80_rock, us);
+  if (parser_get_opt_param_int(params, "EoS:planetary_use_ANEOS", 0)) {
+    set_ANEOS_iron(&e->ANEOS_iron, eos_planetary_id_ANEOS_iron);
+    set_MANEOS_forsterite(&e->MANEOS_forsterite,
+                          eos_planetary_id_MANEOS_forsterite);
 
-  // ANEOS
-  convert_units_ANEOS(&e->ANEOS_iron, us);
-  convert_units_ANEOS(&e->MANEOS_forsterite, us);
+    convert_units_ANEOS(&e->ANEOS_iron, us);
+    convert_units_ANEOS(&e->MANEOS_forsterite, us);
+  }
 
   // SESAME
-  convert_units_SESAME(&e->SESAME_iron, us);
+  if (parser_get_opt_param_int(params, "EoS:planetary_use_SESAME", 0)) {
+    set_SESAME_iron(&e->SESAME_iron, eos_planetary_id_SESAME_iron);
+
+    convert_units_SESAME(&e->SESAME_iron, us);
+  }
 }
 
 /**
diff --git a/src/equation_of_state/planetary/hm80.h b/src/equation_of_state/planetary/hm80.h
index b0669c129b2b4d642ae27e58f2f2bec221e3df9b..0131bab6c447e5a8898e29e13dc3f8f6e1c897c6 100644
--- a/src/equation_of_state/planetary/hm80.h
+++ b/src/equation_of_state/planetary/hm80.h
@@ -41,19 +41,13 @@
 
 // Hubbard & MacFarlane (1980) parameters
 struct HM80_params {
-  float **table_P_rho_u;
+  float *table_P_rho_u;
   int num_rho, num_u;
   float log_rho_min, log_rho_max, log_rho_step, inv_log_rho_step, log_u_min,
       log_u_max, log_u_step, inv_log_u_step, bulk_mod;
   enum eos_planetary_material_id mat_id;
 };
 
-// Table file names
-/// to be read in from the parameter file instead once finished testing...
-#define HM80_HHe_table_file "/gpfs/data/dc-kege1/gihr_data/P_rho_u_HHe.txt"
-#define HM80_ice_table_file "/gpfs/data/dc-kege1/gihr_data/P_rho_u_ice.txt"
-#define HM80_rock_table_file "/gpfs/data/dc-kege1/gihr_data/P_rho_u_roc.txt"
-
 // Parameter values for each material (cgs units)
 INLINE static void set_HM80_HHe(struct HM80_params *mat,
                                 enum eos_planetary_material_id mat_id) {
@@ -107,17 +101,15 @@ INLINE static void set_HM80_rock(struct HM80_params *mat,
 // Read the table from file
 INLINE static void load_HM80_table(struct HM80_params *mat, char *table_file) {
   // Allocate table memory
-  mat->table_P_rho_u = (float **)malloc(mat->num_rho * sizeof(float *));
-  for (int i = 0; i < mat->num_rho; i++) {
-    mat->table_P_rho_u[i] = (float *)malloc(mat->num_u * sizeof(float));
-  }
+  mat->table_P_rho_u =
+      (float *)malloc(mat->num_rho * mat->num_u * sizeof(float *));
 
   // Load table contents from file
   FILE *f = fopen(table_file, "r");
   int c;
   for (int i = 0; i < mat->num_rho; i++) {
     for (int j = 0; j < mat->num_u; j++) {
-      c = fscanf(f, "%f", &mat->table_P_rho_u[i][j]);
+      c = fscanf(f, "%f", &mat->table_P_rho_u[i * mat->num_rho + j]);
       if (c != 1) {
         error("Failed to read EOS table");
       }
@@ -147,7 +139,7 @@ INLINE static void convert_units_HM80(struct HM80_params *mat,
   // Table Pressures in Mbar
   for (int i = 0; i < mat->num_rho; i++) {
     for (int j = 0; j < mat->num_u; j++) {
-      mat->table_P_rho_u[i][j] *=
+      mat->table_P_rho_u[i * mat->num_rho + j] *=
           Mbar_to_Ba / units_cgs_conversion_factor(us, UNIT_CONV_PRESSURE);
     }
   }
@@ -194,7 +186,6 @@ INLINE static float HM80_soundspeed_from_entropy(
 // gas_entropy_from_internal_energy
 INLINE static float HM80_entropy_from_internal_energy(
     float density, float u, const struct HM80_params *mat) {
-  error("This EOS function is not yet implemented!");
 
   return 0;
 }
@@ -205,7 +196,7 @@ INLINE static float HM80_pressure_from_internal_energy(
 
   float P;
 
-  if (u <= 0) {
+  if (u <= 0.f) {
     return 0.f;
   }
 
@@ -226,32 +217,35 @@ INLINE static float HM80_pressure_from_internal_energy(
   // Return zero pressure if below the table minimum/a
   // Extrapolate the pressure for low densities
   if (rho_idx < 0) {  // Too-low rho
-    P = expf(logf((1 - intp_u) * mat->table_P_rho_u[0][u_idx] +
-                  intp_u * mat->table_P_rho_u[0][u_idx + 1]) +
+    P = expf(logf((1 - intp_u) * mat->table_P_rho_u[u_idx] +
+                  intp_u * mat->table_P_rho_u[u_idx + 1]) +
              log_rho - mat->log_rho_min);
     if (u_idx < 0) {  // and too-low u
-      P = 0;
+      P = 0.f;
     }
   } else if (u_idx < 0) {  // Too-low u
-    P = 0;
+    P = 0.f;
   }
   // Return an edge value if above the table maximum/a
   else if (rho_idx >= mat->num_rho - 1) {  // Too-high rho
     if (u_idx >= mat->num_u - 1) {         // and too-high u
-      P = mat->table_P_rho_u[mat->num_rho - 1][mat->num_u - 1];
+      P = mat->table_P_rho_u[(mat->num_rho - 1) * mat->num_u + mat->num_u - 1];
     } else {
-      P = mat->table_P_rho_u[mat->num_rho - 1][u_idx];
+      P = mat->table_P_rho_u[(mat->num_rho - 1) * mat->num_u + u_idx];
     }
   } else if (u_idx >= mat->num_u - 1) {  // Too-high u
-    P = mat->table_P_rho_u[rho_idx][mat->num_u - 1];
+    P = mat->table_P_rho_u[rho_idx * mat->num_u + mat->num_u - 1];
   }
   // Normal interpolation within the table
   else {
     P = (1.f - intp_rho) *
-            ((1.f - intp_u) * mat->table_P_rho_u[rho_idx][u_idx] +
-             intp_u * mat->table_P_rho_u[rho_idx][u_idx + 1]) +
-        intp_rho * ((1 - intp_u) * mat->table_P_rho_u[rho_idx + 1][u_idx] +
-                    intp_u * mat->table_P_rho_u[rho_idx + 1][u_idx + 1]);
+            ((1.f - intp_u) * mat->table_P_rho_u[rho_idx * mat->num_u + u_idx] +
+             intp_u * mat->table_P_rho_u[rho_idx * mat->num_u + u_idx + 1]) +
+        intp_rho *
+            ((1 - intp_u) *
+                 mat->table_P_rho_u[(rho_idx + 1) * mat->num_u + u_idx] +
+             intp_u *
+                 mat->table_P_rho_u[(rho_idx + 1) * mat->num_u + u_idx + 1]);
   }
 
   return P;
diff --git a/src/equation_of_state/planetary/tillotson.h b/src/equation_of_state/planetary/tillotson.h
index ed280079b040776dfc20480c50fbc9a3b6ff4470..d5b6d5c35d5edf9e114fe7f010c4f5b1e2327a83 100644
--- a/src/equation_of_state/planetary/tillotson.h
+++ b/src/equation_of_state/planetary/tillotson.h
@@ -147,7 +147,6 @@ INLINE static float Til_soundspeed_from_entropy(float density, float entropy,
 // gas_entropy_from_internal_energy
 INLINE static float Til_entropy_from_internal_energy(
     float density, float u, const struct Til_params *mat) {
-  error("This EOS function is not yet implemented!");
 
   return 0;
 }
diff --git a/src/hydro.h b/src/hydro.h
index cc6fa46ad374b39f5c9777874d2d85608b5eb2d6..950f63526a1590fa0fdcf2bfb5e650a2dfe14431 100644
--- a/src/hydro.h
+++ b/src/hydro.h
@@ -49,10 +49,14 @@
 #include "./hydro/Default/hydro.h"
 #include "./hydro/Default/hydro_iact.h"
 #define SPH_IMPLEMENTATION "Default version of SPH"
-#elif defined(GIZMO_SPH)
-#include "./hydro/Gizmo/hydro.h"
-#include "./hydro/Gizmo/hydro_iact.h"
-#define SPH_IMPLEMENTATION "GIZMO (Hopkins 2015)"
+#elif defined(GIZMO_MFV_SPH)
+#include "./hydro/GizmoMFV/hydro.h"
+#include "./hydro/GizmoMFV/hydro_iact.h"
+#define SPH_IMPLEMENTATION "GIZMO MFV (Hopkins 2015)"
+#elif defined(GIZMO_MFM_SPH)
+#include "./hydro/GizmoMFM/hydro.h"
+#include "./hydro/GizmoMFM/hydro_iact.h"
+#define SPH_IMPLEMENTATION "GIZMO MFM (Hopkins 2015)"
 #elif defined(SHADOWFAX_SPH)
 #include "./hydro/Shadowswift/hydro.h"
 #include "./hydro/Shadowswift/hydro_iact.h"
diff --git a/src/hydro/Gizmo/hydro.h b/src/hydro/GizmoMFM/hydro.h
similarity index 99%
rename from src/hydro/Gizmo/hydro.h
rename to src/hydro/GizmoMFM/hydro.h
index 079e66669eb4e3b574742b09ca6b7e80d5386fb7..9c4be6af359d7236e483b712065b357c6ed35402 100644
--- a/src/hydro/Gizmo/hydro.h
+++ b/src/hydro/GizmoMFM/hydro.h
@@ -17,8 +17,8 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  *
  ******************************************************************************/
-#ifndef SWIFT_GIZMO_HYDRO_H
-#define SWIFT_GIZMO_HYDRO_H
+#ifndef SWIFT_GIZMO_MFM_HYDRO_H
+#define SWIFT_GIZMO_MFM_HYDRO_H
 
 #include "adiabatic_index.h"
 #include "approx_math.h"
@@ -972,4 +972,4 @@ hydro_set_init_internal_energy(struct part* p, float u_init) {
   p->primitives.P = hydro_gamma_minus_one * p->primitives.rho * u_init;
 }
 
-#endif /* SWIFT_GIZMO_HYDRO_H */
+#endif /* SWIFT_GIZMO_MFM_HYDRO_H */
diff --git a/src/hydro/Gizmo/hydro_debug.h b/src/hydro/GizmoMFM/hydro_debug.h
similarity index 96%
rename from src/hydro/Gizmo/hydro_debug.h
rename to src/hydro/GizmoMFM/hydro_debug.h
index 0516068d3452e179c076f40a7c2db859be1c73c6..6603bc216b986b40513383120587d3caec1adc87 100644
--- a/src/hydro/Gizmo/hydro_debug.h
+++ b/src/hydro/GizmoMFM/hydro_debug.h
@@ -16,8 +16,8 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  *
  ******************************************************************************/
-#ifndef SWIFT_GIZMO_HYDRO_DEBUG_H
-#define SWIFT_GIZMO_HYDRO_DEBUG_H
+#ifndef SWIFT_GIZMO_MFM_HYDRO_DEBUG_H
+#define SWIFT_GIZMO_MFM_HYDRO_DEBUG_H
 
 __attribute__((always_inline)) INLINE static void hydro_debug_particle(
     const struct part* p, const struct xpart* xp) {
@@ -78,4 +78,4 @@ __attribute__((always_inline)) INLINE static void hydro_debug_particle(
       p->timestepvars.vmax, p->density.wcount_dh, p->density.wcount);
 }
 
-#endif /* SWIFT_GIZMO_HYDRO_DEBUG_H */
+#endif /* SWIFT_GIZMO_MFM_HYDRO_DEBUG_H */
diff --git a/src/hydro/Gizmo/hydro_gradients.h b/src/hydro/GizmoMFM/hydro_gradients.h
similarity index 97%
rename from src/hydro/Gizmo/hydro_gradients.h
rename to src/hydro/GizmoMFM/hydro_gradients.h
index c5d95e4dab4f574dd20e8355aacdd176530ec63d..964a2adcfe09b95c2a221af540e5e3ff0830dd67 100644
--- a/src/hydro/Gizmo/hydro_gradients.h
+++ b/src/hydro/GizmoMFM/hydro_gradients.h
@@ -17,8 +17,8 @@
  *
  ******************************************************************************/
 
-#ifndef SWIFT_HYDRO_GIZMO_GRADIENTS_H
-#define SWIFT_HYDRO_GIZMO_GRADIENTS_H
+#ifndef SWIFT_HYDRO_GIZMO_MFM_GRADIENTS_H
+#define SWIFT_HYDRO_GIZMO_MFM_GRADIENTS_H
 
 #include "hydro_slope_limiters.h"
 #include "hydro_unphysical.h"
@@ -156,4 +156,4 @@ __attribute__((always_inline)) INLINE static void hydro_gradients_predict(
                                   Wj[3], Wj[4]);
 }
 
-#endif /* SWIFT_HYDRO_GIZMO_GRADIENTS_H */
+#endif /* SWIFT_HYDRO_GIZMO_MFM_GRADIENTS_H */
diff --git a/src/hydro/Gizmo/hydro_gradients_gizmo.h b/src/hydro/GizmoMFM/hydro_gradients_gizmo.h
similarity index 99%
rename from src/hydro/Gizmo/hydro_gradients_gizmo.h
rename to src/hydro/GizmoMFM/hydro_gradients_gizmo.h
index 9f23f82e870cffb82a73964707bd28fa68ed00d7..1c3b68bb28375259628e09f16730710fbbd80149 100644
--- a/src/hydro/Gizmo/hydro_gradients_gizmo.h
+++ b/src/hydro/GizmoMFM/hydro_gradients_gizmo.h
@@ -22,8 +22,8 @@
  *
  * @param p Particle.
  */
-#ifndef SWIFT_GIZMO_HYDRO_GRADIENTS_H
-#define SWIFT_GIZMO_HYDRO_GRADIENTS_H
+#ifndef SWIFT_GIZMO_MFM_HYDRO_GRADIENTS_H
+#define SWIFT_GIZMO_MFM_HYDRO_GRADIENTS_H
 
 __attribute__((always_inline)) INLINE static void hydro_gradients_init(
     struct part *p) {
@@ -485,4 +485,4 @@ __attribute__((always_inline)) INLINE static void hydro_gradients_finalize(
   hydro_slope_limit_cell(p);
 }
 
-#endif /* SWIFT_GIZMO_HYDRO_GRADIENTS_H */
+#endif /* SWIFT_GIZMO_MFM_HYDRO_GRADIENTS_H */
diff --git a/src/hydro/Gizmo/hydro_gradients_sph.h b/src/hydro/GizmoMFM/hydro_gradients_sph.h
similarity index 98%
rename from src/hydro/Gizmo/hydro_gradients_sph.h
rename to src/hydro/GizmoMFM/hydro_gradients_sph.h
index fbaa056443df56691f1414f2d661ba9edc459734..169bed74f0b1b7e966f9880248f811d100bec13b 100644
--- a/src/hydro/Gizmo/hydro_gradients_sph.h
+++ b/src/hydro/GizmoMFM/hydro_gradients_sph.h
@@ -22,8 +22,8 @@
  *
  * @param p Particle.
  */
-#ifndef SWIFT_GIZMO_HYDRO_SPH_GRADIENTS_H
-#define SWIFT_GIZMO_HYDRO_SPH_GRADIENTS_H
+#ifndef SWIFT_GIZMO_MFM_HYDRO_SPH_GRADIENTS_H
+#define SWIFT_GIZMO_MFM_HYDRO_SPH_GRADIENTS_H
 
 __attribute__((always_inline)) INLINE static void hydro_gradients_init(
     struct part *p) {
@@ -253,4 +253,4 @@ __attribute__((always_inline)) INLINE static void hydro_gradients_finalize(
   hydro_slope_limit_cell(p);
 }
 
-#endif /* SWIFT_GIZMO_HYDRO_SPH_GRADIENTS_H */
+#endif /* SWIFT_GIZMO_MFM_HYDRO_SPH_GRADIENTS_H */
diff --git a/src/hydro/GizmoMFM/hydro_iact.h b/src/hydro/GizmoMFM/hydro_iact.h
new file mode 100644
index 0000000000000000000000000000000000000000..a1a82e514baa60d5895343ea84ef1c3aedc8a6b7
--- /dev/null
+++ b/src/hydro/GizmoMFM/hydro_iact.h
@@ -0,0 +1,517 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Coypright (c) 2012 Pedro Gonnet (pedro.gonnet@durham.ac.uk)
+ *                    Matthieu Schaller (matthieu.schaller@durham.ac.uk)
+ *                    Bert Vandenbroucke (bert.vandenbroucke@ugent.be)
+ *
+ * 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/>.
+ *
+ ******************************************************************************/
+#ifndef SWIFT_GIZMO_MFM_HYDRO_IACT_H
+#define SWIFT_GIZMO_MFM_HYDRO_IACT_H
+
+#include "adiabatic_index.h"
+#include "hydro_gradients.h"
+#include "riemann.h"
+
+#define GIZMO_VOLUME_CORRECTION
+
+/**
+ * @brief Calculate the volume interaction between particle i and particle j
+ *
+ * The volume is in essence the same as the weighted number of neighbours in a
+ * classical SPH density calculation.
+ *
+ * We also calculate the components of the matrix E, which is used for second
+ * order accurate gradient calculations and for the calculation of the interface
+ * surface areas.
+ *
+ * @param r2 Comoving squared distance between particle i and particle j.
+ * @param dx Comoving distance vector between the particles (dx = pi->x -
+ * pj->x).
+ * @param hi Comoving smoothing-length of particle i.
+ * @param hj Comoving smoothing-length of particle j.
+ * @param pi Particle i.
+ * @param pj Particle j.
+ * @param a Current scale factor.
+ * @param H Current Hubble parameter.
+ */
+__attribute__((always_inline)) INLINE static void runner_iact_density(
+    float r2, const float *dx, float hi, float hj, struct part *restrict pi,
+    struct part *restrict pj, float a, float H) {
+
+  float wi, wj, wi_dx, wj_dx;
+
+  /* Get r and h inverse. */
+  const float r = sqrtf(r2);
+
+  /* Compute density of pi. */
+  const float hi_inv = 1.f / hi;
+  const float xi = r * hi_inv;
+  kernel_deval(xi, &wi, &wi_dx);
+
+  pi->density.wcount += wi;
+  pi->density.wcount_dh -= (hydro_dimension * wi + xi * wi_dx);
+
+  /* these are eqns. (1) and (2) in the summary */
+  pi->geometry.volume += wi;
+  for (int k = 0; k < 3; k++)
+    for (int l = 0; l < 3; l++)
+      pi->geometry.matrix_E[k][l] += dx[k] * dx[l] * wi;
+
+  pi->geometry.centroid[0] -= dx[0] * wi;
+  pi->geometry.centroid[1] -= dx[1] * wi;
+  pi->geometry.centroid[2] -= dx[2] * wi;
+
+  /* Compute density of pj. */
+  const float hj_inv = 1.f / hj;
+  const float xj = r * hj_inv;
+  kernel_deval(xj, &wj, &wj_dx);
+
+  pj->density.wcount += wj;
+  pj->density.wcount_dh -= (hydro_dimension * wj + xj * wj_dx);
+
+  /* these are eqns. (1) and (2) in the summary */
+  pj->geometry.volume += wj;
+  for (int k = 0; k < 3; k++)
+    for (int l = 0; l < 3; l++)
+      pj->geometry.matrix_E[k][l] += dx[k] * dx[l] * wj;
+
+  pj->geometry.centroid[0] += dx[0] * wj;
+  pj->geometry.centroid[1] += dx[1] * wj;
+  pj->geometry.centroid[2] += dx[2] * wj;
+}
+
+/**
+ * @brief Calculate the volume interaction between particle i and particle j:
+ * non-symmetric version
+ *
+ * The volume is in essence the same as the weighted number of neighbours in a
+ * classical SPH density calculation.
+ *
+ * We also calculate the components of the matrix E, which is used for second
+ * order accurate gradient calculations and for the calculation of the interface
+ * surface areas.
+ *
+ * @param r2 Comoving squared distance between particle i and particle j.
+ * @param dx Comoving distance vector between the particles (dx = pi->x -
+ * pj->x).
+ * @param hi Comoving smoothing-length of particle i.
+ * @param hj Comoving smoothing-length of particle j.
+ * @param pi Particle i.
+ * @param pj Particle j.
+ * @param a Current scale factor.
+ * @param H Current Hubble parameter.
+ */
+__attribute__((always_inline)) INLINE static void runner_iact_nonsym_density(
+    float r2, const float *dx, float hi, float hj, struct part *restrict pi,
+    const struct part *restrict pj, float a, float H) {
+
+  float wi, wi_dx;
+
+  /* Get r and h inverse. */
+  const float r = sqrtf(r2);
+
+  const float hi_inv = 1.f / hi;
+  const float xi = r * hi_inv;
+  kernel_deval(xi, &wi, &wi_dx);
+
+  pi->density.wcount += wi;
+  pi->density.wcount_dh -= (hydro_dimension * wi + xi * wi_dx);
+
+  /* these are eqns. (1) and (2) in the summary */
+  pi->geometry.volume += wi;
+  for (int k = 0; k < 3; k++)
+    for (int l = 0; l < 3; l++)
+      pi->geometry.matrix_E[k][l] += dx[k] * dx[l] * wi;
+
+  pi->geometry.centroid[0] -= dx[0] * wi;
+  pi->geometry.centroid[1] -= dx[1] * wi;
+  pi->geometry.centroid[2] -= dx[2] * wi;
+}
+
+/**
+ * @brief Calculate the gradient interaction between particle i and particle j
+ *
+ * This method wraps around hydro_gradients_collect, which can be an empty
+ * method, in which case no gradients are used.
+ *
+ * @param r2 Comoving squared distance between particle i and particle j.
+ * @param dx Comoving distance vector between the particles (dx = pi->x -
+ * pj->x).
+ * @param hi Comoving smoothing-length of particle i.
+ * @param hj Comoving smoothing-length of particle j.
+ * @param pi Particle i.
+ * @param pj Particle j.
+ * @param a Current scale factor.
+ * @param H Current Hubble parameter.
+ */
+__attribute__((always_inline)) INLINE static void runner_iact_gradient(
+    float r2, const float *dx, float hi, float hj, struct part *restrict pi,
+    struct part *restrict pj, float a, float H) {
+
+  hydro_gradients_collect(r2, dx, hi, hj, pi, pj);
+}
+
+/**
+ * @brief Calculate the gradient interaction between particle i and particle j:
+ * non-symmetric version
+ *
+ * This method wraps around hydro_gradients_nonsym_collect, which can be an
+ * empty method, in which case no gradients are used.
+ *
+ * @param r2 Comoving squared distance between particle i and particle j.
+ * @param dx Comoving distance vector between the particles (dx = pi->x -
+ * pj->x).
+ * @param hi Comoving smoothing-length of particle i.
+ * @param hj Comoving smoothing-length of particle j.
+ * @param pi Particle i.
+ * @param pj Particle j.
+ * @param a Current scale factor.
+ * @param H Current Hubble parameter.
+ */
+__attribute__((always_inline)) INLINE static void runner_iact_nonsym_gradient(
+    float r2, const float *dx, float hi, float hj, struct part *restrict pi,
+    struct part *restrict pj, float a, float H) {
+
+  hydro_gradients_nonsym_collect(r2, dx, hi, hj, pi, pj);
+}
+
+/**
+ * @brief Common part of the flux calculation between particle i and j
+ *
+ * Since the only difference between the symmetric and non-symmetric version
+ * of the flux calculation  is in the update of the conserved variables at the
+ * very end (which is not done for particle j if mode is 0), both
+ * runner_iact_force and runner_iact_nonsym_force call this method, with an
+ * appropriate mode.
+ *
+ * This method calculates the surface area of the interface between particle i
+ * and particle j, as well as the interface position and velocity. These are
+ * then used to reconstruct and predict the primitive variables, which are then
+ * fed to a Riemann solver that calculates a flux. This flux is used to update
+ * the conserved variables of particle i or both particles.
+ *
+ * This method also calculates the maximal velocity used to calculate the time
+ * step.
+ *
+ * @param r2 Comoving squared distance between particle i and particle j.
+ * @param dx Comoving distance vector between the particles (dx = pi->x -
+ * pj->x).
+ * @param hi Comoving smoothing-length of particle i.
+ * @param hj Comoving smoothing-length of particle j.
+ * @param pi Particle i.
+ * @param pj Particle j.
+ * @param a Current scale factor.
+ * @param H Current Hubble parameter.
+ */
+__attribute__((always_inline)) INLINE static void runner_iact_fluxes_common(
+    float r2, const float *dx, float hi, float hj, struct part *restrict pi,
+    struct part *restrict pj, int mode, float a, float H) {
+
+  const float r_inv = 1.f / sqrtf(r2);
+  const float r = r2 * r_inv;
+
+  /* Initialize local variables */
+  float Bi[3][3];
+  float Bj[3][3];
+  float vi[3], vj[3];
+  for (int k = 0; k < 3; k++) {
+    for (int l = 0; l < 3; l++) {
+      Bi[k][l] = pi->geometry.matrix_E[k][l];
+      Bj[k][l] = pj->geometry.matrix_E[k][l];
+    }
+    vi[k] = pi->v[k]; /* particle velocities */
+    vj[k] = pj->v[k];
+  }
+  const float Vi = pi->geometry.volume;
+  const float Vj = pj->geometry.volume;
+  float Wi[5], Wj[5];
+  Wi[0] = pi->primitives.rho;
+  Wi[1] = pi->primitives.v[0];
+  Wi[2] = pi->primitives.v[1];
+  Wi[3] = pi->primitives.v[2];
+  Wi[4] = pi->primitives.P;
+  Wj[0] = pj->primitives.rho;
+  Wj[1] = pj->primitives.v[0];
+  Wj[2] = pj->primitives.v[1];
+  Wj[3] = pj->primitives.v[2];
+  Wj[4] = pj->primitives.P;
+
+  /* calculate the maximal signal velocity */
+  float vmax;
+  if (Wi[0] > 0.0f && Wj[0] > 0.0f) {
+    const float ci = gas_soundspeed_from_pressure(Wi[0], Wi[4]);
+    const float cj = gas_soundspeed_from_pressure(Wj[0], Wj[4]);
+    vmax = ci + cj;
+  } else
+    vmax = 0.0f;
+
+  float dvdr = (pi->v[0] - pj->v[0]) * dx[0] + (pi->v[1] - pj->v[1]) * dx[1] +
+               (pi->v[2] - pj->v[2]) * dx[2];
+
+  /* Velocity on the axis linking the particles */
+  float dvdotdx = (Wi[1] - Wj[1]) * dx[0] + (Wi[2] - Wj[2]) * dx[1] +
+                  (Wi[3] - Wj[3]) * dx[2];
+  dvdotdx = min(dvdotdx, dvdr);
+
+  /* We only care about this velocity for particles moving towards each others
+   */
+  dvdotdx = min(dvdotdx, 0.f);
+
+  /* Get the signal velocity */
+  /* the magical factor 3 also appears in Gadget2 */
+  vmax -= 3.f * dvdotdx * r_inv;
+
+  /* Store the signal velocity */
+  pi->timestepvars.vmax = max(pi->timestepvars.vmax, vmax);
+  if (mode == 1) pj->timestepvars.vmax = max(pj->timestepvars.vmax, vmax);
+
+  /* Compute kernel of pi. */
+  float wi, wi_dx;
+  const float hi_inv = 1.f / hi;
+  const float hi_inv_dim = pow_dimension(hi_inv);
+  const float xi = r * hi_inv;
+  kernel_deval(xi, &wi, &wi_dx);
+
+  /* Compute kernel of pj. */
+  float wj, wj_dx;
+  const float hj_inv = 1.f / hj;
+  const float hj_inv_dim = pow_dimension(hj_inv);
+  const float xj = r * hj_inv;
+  kernel_deval(xj, &wj, &wj_dx);
+
+  /* Compute h_dt. We are going to use an SPH-like estimate of div_v for that */
+  const float hidp1 = pow_dimension_plus_one(hi_inv);
+  const float hjdp1 = pow_dimension_plus_one(hj_inv);
+  const float wi_dr = hidp1 * wi_dx;
+  const float wj_dr = hjdp1 * wj_dx;
+  dvdr *= r_inv;
+  if (pj->primitives.rho > 0.)
+    pi->force.h_dt -= pj->conserved.mass * dvdr / pj->primitives.rho * wi_dr;
+  if (mode == 1 && pi->primitives.rho > 0.)
+    pj->force.h_dt -= pi->conserved.mass * dvdr / pi->primitives.rho * wj_dr;
+
+  /* Compute (square of) area */
+  /* eqn. (7) */
+  float Anorm2 = 0.0f;
+  float A[3];
+  if (pi->density.wcorr > const_gizmo_min_wcorr &&
+      pj->density.wcorr > const_gizmo_min_wcorr) {
+    /* in principle, we use Vi and Vj as weights for the left and right
+       contributions to the generalized surface vector.
+       However, if Vi and Vj are very different (because they have very
+       different
+       smoothing lengths), then the expressions below are more stable. */
+    float Xi = Vi;
+    float Xj = Vj;
+#ifdef GIZMO_VOLUME_CORRECTION
+    if (fabsf(Vi - Vj) / min(Vi, Vj) > 1.5f * hydro_dimension) {
+      Xi = (Vi * hj + Vj * hi) / (hi + hj);
+      Xj = Xi;
+    }
+#endif
+    for (int k = 0; k < 3; k++) {
+      /* we add a minus sign since dx is pi->x - pj->x */
+      A[k] = -Xi * (Bi[k][0] * dx[0] + Bi[k][1] * dx[1] + Bi[k][2] * dx[2]) *
+                 wi * hi_inv_dim -
+             Xj * (Bj[k][0] * dx[0] + Bj[k][1] * dx[1] + Bj[k][2] * dx[2]) *
+                 wj * hj_inv_dim;
+      Anorm2 += A[k] * A[k];
+    }
+  } else {
+    /* ill condition gradient matrix: revert to SPH face area */
+    const float Anorm =
+        -(hidp1 * Vi * Vi * wi_dx + hjdp1 * Vj * Vj * wj_dx) * r_inv;
+    A[0] = -Anorm * dx[0];
+    A[1] = -Anorm * dx[1];
+    A[2] = -Anorm * dx[2];
+    Anorm2 = Anorm * Anorm * r2;
+  }
+
+  /* if the interface has no area, nothing happens and we return */
+  /* continuing results in dividing by zero and NaN's... */
+  if (Anorm2 == 0.f) return;
+
+  /* Compute the area */
+  const float Anorm_inv = 1. / sqrtf(Anorm2);
+  const float Anorm = Anorm2 * Anorm_inv;
+
+#ifdef SWIFT_DEBUG_CHECKS
+  /* For stability reasons, we do require A and dx to have opposite
+     directions (basically meaning that the surface normal for the surface
+     always points from particle i to particle j, as it would in a real
+     moving-mesh code). If not, our scheme is no longer upwind and hence can
+     become unstable. */
+  const float dA_dot_dx = A[0] * dx[0] + A[1] * dx[1] + A[2] * dx[2];
+  /* In GIZMO, Phil Hopkins reverts to an SPH integration scheme if this
+     happens. We curently just ignore this case and display a message. */
+  const float rdim = pow_dimension(r);
+  if (dA_dot_dx > 1.e-6f * rdim) {
+    message("Ill conditioned gradient matrix (%g %g %g %g %g)!", dA_dot_dx,
+            Anorm, Vi, Vj, r);
+  }
+#endif
+
+  /* compute the normal vector of the interface */
+  const float n_unit[3] = {A[0] * Anorm_inv, A[1] * Anorm_inv,
+                           A[2] * Anorm_inv};
+
+  /* Compute interface position (relative to pi, since we don't need the actual
+   * position) eqn. (8) */
+  const float xfac = -hi / (hi + hj);
+  const float xij_i[3] = {xfac * dx[0], xfac * dx[1], xfac * dx[2]};
+
+  /* Compute interface velocity */
+  /* eqn. (9) */
+  float xijdotdx = xij_i[0] * dx[0] + xij_i[1] * dx[1] + xij_i[2] * dx[2];
+  xijdotdx *= r_inv * r_inv;
+  const float vij[3] = {vi[0] + (vi[0] - vj[0]) * xijdotdx,
+                        vi[1] + (vi[1] - vj[1]) * xijdotdx,
+                        vi[2] + (vi[2] - vj[2]) * xijdotdx};
+
+  /* complete calculation of position of interface */
+  /* NOTE: dx is not necessarily just pi->x - pj->x but can also contain
+           correction terms for periodicity. If we do the interpolation,
+           we have to use xij w.r.t. the actual particle.
+           => we need a separate xij for pi and pj... */
+  /* tldr: we do not need the code below, but we do need the same code as above
+     but then with i and j swapped */
+  //    for ( k = 0 ; k < 3 ; k++ )
+  //      xij[k] += pi->x[k];
+
+  /* Boost the primitive variables to the frame of reference of the interface */
+  /* Note that velocities are indices 1-3 in W */
+  Wi[1] -= vij[0];
+  Wi[2] -= vij[1];
+  Wi[3] -= vij[2];
+  Wj[1] -= vij[0];
+  Wj[2] -= vij[1];
+  Wj[3] -= vij[2];
+
+  hydro_gradients_predict(pi, pj, hi, hj, dx, r, xij_i, Wi, Wj);
+
+  /* we don't need to rotate, we can use the unit vector in the Riemann problem
+   * itself (see GIZMO) */
+
+  float totflux[5];
+  riemann_solve_for_middle_state_flux(Wi, Wj, n_unit, vij, totflux);
+
+  /* Multiply with the interface surface area */
+  totflux[0] *= Anorm;
+  totflux[1] *= Anorm;
+  totflux[2] *= Anorm;
+  totflux[3] *= Anorm;
+  totflux[4] *= Anorm;
+
+  /* Store mass flux */
+  const float mflux_i = totflux[0];
+  pi->gravity.mflux[0] += mflux_i * dx[0];
+  pi->gravity.mflux[1] += mflux_i * dx[1];
+  pi->gravity.mflux[2] += mflux_i * dx[2];
+
+  /* Update conserved variables */
+  /* eqn. (16) */
+  pi->conserved.flux.mass -= totflux[0];
+  pi->conserved.flux.momentum[0] -= totflux[1];
+  pi->conserved.flux.momentum[1] -= totflux[2];
+  pi->conserved.flux.momentum[2] -= totflux[3];
+  pi->conserved.flux.energy -= totflux[4];
+
+#ifndef GIZMO_TOTAL_ENERGY
+  const float ekin_i = 0.5f * (pi->primitives.v[0] * pi->primitives.v[0] +
+                               pi->primitives.v[1] * pi->primitives.v[1] +
+                               pi->primitives.v[2] * pi->primitives.v[2]);
+  pi->conserved.flux.energy += totflux[1] * pi->primitives.v[0];
+  pi->conserved.flux.energy += totflux[2] * pi->primitives.v[1];
+  pi->conserved.flux.energy += totflux[3] * pi->primitives.v[2];
+  pi->conserved.flux.energy -= totflux[0] * ekin_i;
+#endif
+
+  /* Note that this used to be much more complicated in early implementations of
+   * the GIZMO scheme, as we wanted manifest conservation of conserved variables
+   * and had to do symmetric flux exchanges. Now we don't care about manifest
+   * conservation anymore and just assume the current fluxes are representative
+   * for the flux over the entire time step. */
+  if (mode == 1) {
+    /* Store mass flux */
+    const float mflux_j = totflux[0];
+    pj->gravity.mflux[0] -= mflux_j * dx[0];
+    pj->gravity.mflux[1] -= mflux_j * dx[1];
+    pj->gravity.mflux[2] -= mflux_j * dx[2];
+
+    pj->conserved.flux.mass += totflux[0];
+    pj->conserved.flux.momentum[0] += totflux[1];
+    pj->conserved.flux.momentum[1] += totflux[2];
+    pj->conserved.flux.momentum[2] += totflux[3];
+    pj->conserved.flux.energy += totflux[4];
+
+#ifndef GIZMO_TOTAL_ENERGY
+    const float ekin_j = 0.5f * (pj->primitives.v[0] * pj->primitives.v[0] +
+                                 pj->primitives.v[1] * pj->primitives.v[1] +
+                                 pj->primitives.v[2] * pj->primitives.v[2]);
+    pj->conserved.flux.energy -= totflux[1] * pj->primitives.v[0];
+    pj->conserved.flux.energy -= totflux[2] * pj->primitives.v[1];
+    pj->conserved.flux.energy -= totflux[3] * pj->primitives.v[2];
+    pj->conserved.flux.energy += totflux[0] * ekin_j;
+#endif
+  }
+}
+
+/**
+ * @brief Flux calculation between particle i and particle j
+ *
+ * This method calls runner_iact_fluxes_common with mode 1.
+ *
+ * @param r2 Comoving squared distance between particle i and particle j.
+ * @param dx Comoving distance vector between the particles (dx = pi->x -
+ * pj->x).
+ * @param hi Comoving smoothing-length of particle i.
+ * @param hj Comoving smoothing-length of particle j.
+ * @param pi Particle i.
+ * @param pj Particle j.
+ * @param a Current scale factor.
+ * @param H Current Hubble parameter.
+ */
+__attribute__((always_inline)) INLINE static void runner_iact_force(
+    float r2, const float *dx, float hi, float hj, struct part *restrict pi,
+    struct part *restrict pj, float a, float H) {
+
+  runner_iact_fluxes_common(r2, dx, hi, hj, pi, pj, 1, a, H);
+}
+
+/**
+ * @brief Flux calculation between particle i and particle j: non-symmetric
+ * version
+ *
+ * This method calls runner_iact_fluxes_common with mode 0.
+ *
+ * @param r2 Comoving squared distance between particle i and particle j.
+ * @param dx Comoving distance vector between the particles (dx = pi->x -
+ * pj->x).
+ * @param hi Comoving smoothing-length of particle i.
+ * @param hj Comoving smoothing-length of particle j.
+ * @param pi Particle i.
+ * @param pj Particle j.
+ * @param a Current scale factor.
+ * @param H Current Hubble parameter.
+ */
+__attribute__((always_inline)) INLINE static void runner_iact_nonsym_force(
+    float r2, const float *dx, float hi, float hj, struct part *restrict pi,
+    struct part *restrict pj, float a, float H) {
+
+  runner_iact_fluxes_common(r2, dx, hi, hj, pi, pj, 0, a, H);
+}
+
+#endif /* SWIFT_GIZMO_MFM_HYDRO_IACT_H */
diff --git a/src/hydro/Gizmo/hydro_io.h b/src/hydro/GizmoMFM/hydro_io.h
similarity index 98%
rename from src/hydro/Gizmo/hydro_io.h
rename to src/hydro/GizmoMFM/hydro_io.h
index 7aa56b3bde5247f4839b8f4f60cdb3de67253392..171132eacfcd43feeec57d3c16b5a458171b1d79 100644
--- a/src/hydro/Gizmo/hydro_io.h
+++ b/src/hydro/GizmoMFM/hydro_io.h
@@ -16,8 +16,8 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  *
  ******************************************************************************/
-#ifndef SWIFT_GIZMO_HYDRO_IO_H
-#define SWIFT_GIZMO_HYDRO_IO_H
+#ifndef SWIFT_GIZMO_MFM_HYDRO_IO_H
+#define SWIFT_GIZMO_MFM_HYDRO_IO_H
 
 #include "adiabatic_index.h"
 #include "hydro.h"
@@ -241,4 +241,4 @@ void hydro_write_flavour(hid_t h_grpsph) {
  */
 int writeEntropyFlag() { return 0; }
 
-#endif /* SWIFT_GIZMO_HYDRO_IO_H */
+#endif /* SWIFT_GIZMO_MFM_HYDRO_IO_H */
diff --git a/src/hydro/Gizmo/hydro_part.h b/src/hydro/GizmoMFM/hydro_part.h
similarity index 97%
rename from src/hydro/Gizmo/hydro_part.h
rename to src/hydro/GizmoMFM/hydro_part.h
index d5bc3f84238fecbf3b2f120f031996f55bbd65fe..857c429ec933ad3eea730e8f0b6f830782cdf77b 100644
--- a/src/hydro/Gizmo/hydro_part.h
+++ b/src/hydro/GizmoMFM/hydro_part.h
@@ -16,8 +16,8 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  *
  ******************************************************************************/
-#ifndef SWIFT_GIZMO_HYDRO_PART_H
-#define SWIFT_GIZMO_HYDRO_PART_H
+#ifndef SWIFT_GIZMO_MFM_HYDRO_PART_H
+#define SWIFT_GIZMO_MFM_HYDRO_PART_H
 
 #include "chemistry_struct.h"
 #include "cooling_struct.h"
@@ -210,4 +210,4 @@ struct part {
 
 } SWIFT_STRUCT_ALIGN;
 
-#endif /* SWIFT_GIZMO_HYDRO_PART_H */
+#endif /* SWIFT_GIZMO_MFM_HYDRO_PART_H */
diff --git a/src/hydro/Gizmo/hydro_slope_limiters.h b/src/hydro/GizmoMFM/hydro_slope_limiters.h
similarity index 100%
rename from src/hydro/Gizmo/hydro_slope_limiters.h
rename to src/hydro/GizmoMFM/hydro_slope_limiters.h
diff --git a/src/hydro/Gizmo/hydro_slope_limiters_cell.h b/src/hydro/GizmoMFM/hydro_slope_limiters_cell.h
similarity index 98%
rename from src/hydro/Gizmo/hydro_slope_limiters_cell.h
rename to src/hydro/GizmoMFM/hydro_slope_limiters_cell.h
index 599be632b64e3b06ab1e0339a6ad4b560b2abece..7dec6f499da31de1f10652a31781a788166957cc 100644
--- a/src/hydro/Gizmo/hydro_slope_limiters_cell.h
+++ b/src/hydro/GizmoMFM/hydro_slope_limiters_cell.h
@@ -16,8 +16,8 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  *
  ******************************************************************************/
-#ifndef SWIFT_GIZMO_SLOPE_LIMITER_CELL_H
-#define SWIFT_GIZMO_SLOPE_LIMITER_CELL_H
+#ifndef SWIFT_GIZMO_MFM_SLOPE_LIMITER_CELL_H
+#define SWIFT_GIZMO_MFM_SLOPE_LIMITER_CELL_H
 
 #include <float.h>
 
@@ -183,4 +183,4 @@ __attribute__((always_inline)) INLINE static void hydro_slope_limit_cell(
   }
 }
 
-#endif /* SWIFT_GIZMO_SLOPE_LIMITER_CELL_H */
+#endif /* SWIFT_GIZMO_MFM_SLOPE_LIMITER_CELL_H */
diff --git a/src/hydro/Gizmo/hydro_slope_limiters_face.h b/src/hydro/GizmoMFM/hydro_slope_limiters_face.h
similarity index 97%
rename from src/hydro/Gizmo/hydro_slope_limiters_face.h
rename to src/hydro/GizmoMFM/hydro_slope_limiters_face.h
index 39a453b3d21383fbf075a3c1985dfb182d9a2dcc..8f0636c992ccbd615cc62ca09c1b0ca9b08ea56b 100644
--- a/src/hydro/Gizmo/hydro_slope_limiters_face.h
+++ b/src/hydro/GizmoMFM/hydro_slope_limiters_face.h
@@ -29,8 +29,8 @@
  * @return The slope limited difference between the quantity at the particle
  * position and the quantity at the interface position.
  */
-#ifndef SWIFT_GIZMO_SLOPE_LIMITER_FACE_H
-#define SWIFT_GIZMO_SLOPE_LIMITER_FACE_H
+#ifndef SWIFT_GIZMO_MFM_SLOPE_LIMITER_FACE_H
+#define SWIFT_GIZMO_MFM_SLOPE_LIMITER_FACE_H
 
 /* Some standard headers. */
 #include <float.h>
@@ -125,4 +125,4 @@ __attribute__((always_inline)) INLINE static void hydro_slope_limit_face(
                                            xij_j_norm, r_inv);
 }
 
-#endif /* SWIFT_GIZMO_SLOPE_LIMITER_FACE_H */
+#endif /* SWIFT_GIZMO_MFM_SLOPE_LIMITER_FACE_H */
diff --git a/src/hydro/Gizmo/hydro_unphysical.h b/src/hydro/GizmoMFM/hydro_unphysical.h
similarity index 100%
rename from src/hydro/Gizmo/hydro_unphysical.h
rename to src/hydro/GizmoMFM/hydro_unphysical.h
diff --git a/src/hydro/Gizmo/hydro_velocities.h b/src/hydro/GizmoMFM/hydro_velocities.h
similarity index 100%
rename from src/hydro/Gizmo/hydro_velocities.h
rename to src/hydro/GizmoMFM/hydro_velocities.h
diff --git a/src/hydro/GizmoMFV/hydro.h b/src/hydro/GizmoMFV/hydro.h
new file mode 100644
index 0000000000000000000000000000000000000000..1d5abeaaf63d88b02817a691f160c537d0b1915b
--- /dev/null
+++ b/src/hydro/GizmoMFV/hydro.h
@@ -0,0 +1,975 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Coypright (c) 2015 Matthieu Schaller (matthieu.schaller@durham.ac.uk)
+ *               2016, 2017 Bert Vandenbroucke (bert.vandenbroucke@gmail.com)
+ *
+ * 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/>.
+ *
+ ******************************************************************************/
+#ifndef SWIFT_GIZMO_MFV_HYDRO_H
+#define SWIFT_GIZMO_MFV_HYDRO_H
+
+#include "adiabatic_index.h"
+#include "approx_math.h"
+#include "cosmology.h"
+#include "equation_of_state.h"
+#include "hydro_gradients.h"
+#include "hydro_properties.h"
+#include "hydro_space.h"
+#include "hydro_unphysical.h"
+#include "hydro_velocities.h"
+#include "minmax.h"
+#include "riemann.h"
+
+#include <float.h>
+
+//#define GIZMO_LLOYD_ITERATION
+
+/**
+ * @brief Computes the hydro time-step of a given particle
+ *
+ * @param p Pointer to the particle data.
+ * @param xp Pointer to the extended particle data.
+ * @param hydro_properties Pointer to the hydro parameters.
+ * @param cosmo The cosmological model.
+ */
+__attribute__((always_inline)) INLINE static float hydro_compute_timestep(
+    const struct part* restrict p, const struct xpart* restrict xp,
+    const struct hydro_props* restrict hydro_properties,
+    const struct cosmology* restrict cosmo) {
+
+  const float CFL_condition = hydro_properties->CFL_condition;
+
+#ifdef GIZMO_LLOYD_ITERATION
+  return CFL_condition;
+#endif
+
+  /* v_full is the actual velocity of the particle, primitives.v is its
+     hydrodynamical velocity. The time step depends on the relative difference
+     of the two. */
+  float vrel[3];
+  vrel[0] = p->primitives.v[0] - xp->v_full[0];
+  vrel[1] = p->primitives.v[1] - xp->v_full[1];
+  vrel[2] = p->primitives.v[2] - xp->v_full[2];
+  float vmax =
+      sqrtf(vrel[0] * vrel[0] + vrel[1] * vrel[1] + vrel[2] * vrel[2]) +
+      sqrtf(hydro_gamma * p->primitives.P / p->primitives.rho);
+  vmax = max(vmax, p->timestepvars.vmax);
+
+  // MATTHIEU: Bert is this correct? Do we need more cosmology terms here?
+  const float psize =
+      cosmo->a * powf(p->geometry.volume / hydro_dimension_unit_sphere,
+                      hydro_dimension_inv);
+  float dt = FLT_MAX;
+  if (vmax > 0.) {
+    dt = psize / vmax;
+  }
+  return CFL_condition * dt;
+}
+
+/**
+ * @brief Does some extra hydro operations once the actual physical time step
+ * for the particle is known.
+ *
+ * This method is no longer used, as Gizmo is now unaware of the actual particle
+ * time step.
+ *
+ * @param p The particle to act upon.
+ * @param dt Physical time step of the particle during the next step.
+ */
+__attribute__((always_inline)) INLINE static void hydro_timestep_extra(
+    struct part* p, float dt) {
+
+#ifdef SWIFT_DEBUG_CHECKS
+  if (dt == 0.) {
+    error("Zero time step assigned to particle!");
+  }
+
+  if (dt != dt) {
+    error("NaN time step assigned to particle!");
+  }
+#endif
+}
+
+/**
+ * @brief Initialises the particles for the first time
+ *
+ * This function is called only once just after the ICs have been
+ * read in to do some conversions.
+ *
+ * In this case, we copy the particle velocities into the corresponding
+ * primitive variable field. We do this because the particle velocities in GIZMO
+ * can be independent of the actual fluid velocity. The latter is stored as a
+ * primitive variable and integrated using the linear momentum, a conserved
+ * variable.
+ *
+ * @param p The particle to act upon
+ * @param xp The extended particle data to act upon
+ */
+__attribute__((always_inline)) INLINE static void hydro_first_init_part(
+    struct part* p, struct xpart* xp) {
+
+  const float mass = p->conserved.mass;
+
+  p->primitives.v[0] = p->v[0];
+  p->primitives.v[1] = p->v[1];
+  p->primitives.v[2] = p->v[2];
+
+  /* we can already initialize the momentum */
+  p->conserved.momentum[0] = mass * p->primitives.v[0];
+  p->conserved.momentum[1] = mass * p->primitives.v[1];
+  p->conserved.momentum[2] = mass * p->primitives.v[2];
+
+/* and the thermal energy */
+/* remember that we store the total thermal energy, not the specific thermal
+   energy (as in Gadget) */
+#if defined(EOS_ISOTHERMAL_GAS)
+  /* this overwrites the internal energy from the initial condition file
+   * Note that we call the EoS function just to get the constant u here. */
+  p->conserved.energy = mass * gas_internal_energy_from_entropy(0.f, 0.f);
+#else
+  p->conserved.energy *= mass;
+#endif
+
+#ifdef GIZMO_TOTAL_ENERGY
+  /* add the total kinetic energy */
+  p->conserved.energy += 0.5f * (p->conserved.momentum[0] * p->primitives.v[0] +
+                                 p->conserved.momentum[1] * p->primitives.v[1] +
+                                 p->conserved.momentum[2] * p->primitives.v[2]);
+#endif
+
+#ifdef GIZMO_LLOYD_ITERATION
+  /* overwrite all variables to make sure they 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.;
+
+  p->conserved.mass = 1.;
+  p->conserved.momentum[0] = 0.;
+  p->conserved.momentum[1] = 0.;
+  p->conserved.momentum[2] = 0.;
+  p->conserved.energy = 1.;
+
+  p->v[0] = 0.;
+  p->v[1] = 0.;
+  p->v[2] = 0.;
+#endif
+
+  /* initialize the particle velocity based on the primitive fluid velocity */
+  hydro_velocities_init(p, xp);
+
+  /* ignore accelerations present in the initial condition */
+  p->a_hydro[0] = 0.0f;
+  p->a_hydro[1] = 0.0f;
+  p->a_hydro[2] = 0.0f;
+
+  /* we cannot initialize wcorr in init_part, as init_part gets called every
+     time the density loop is repeated, and the whole point of storing wcorr
+     is to have a way of remembering that we need more neighbours for this
+     particle */
+  p->density.wcorr = 1.0f;
+}
+
+/**
+ * @brief Prepares a particle for the volume calculation.
+ *
+ * Simply makes sure all necessary variables are initialized to zero.
+ *
+ * @param p The particle to act upon
+ * @param hs #hydro_space containing hydro specific space information.
+ */
+__attribute__((always_inline)) INLINE static void hydro_init_part(
+    struct part* p, const struct hydro_space* hs) {
+
+  p->density.wcount = 0.0f;
+  p->density.wcount_dh = 0.0f;
+  p->geometry.volume = 0.0f;
+  p->geometry.matrix_E[0][0] = 0.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] = 0.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] = 0.0f;
+  p->geometry.centroid[0] = 0.0f;
+  p->geometry.centroid[1] = 0.0f;
+  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 = 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 * kernel_norm * 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.
+ *
+ * The name of this method is confusing, as this method is really 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.
+ */
+__attribute__((always_inline)) INLINE static void hydro_prepare_force(
+    struct part* restrict p, struct xpart* restrict xp,
+    const struct cosmology* cosmo) {
+
+  /* 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.
+ *
+ * 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);
+
+  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;
+
+#ifdef GIZMO_LLOYD_ITERATION
+  /* reset the gradients to zero, as we don't want them */
+  hydro_gradients_init(p);
+#endif
+}
+
+/**
+ * @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.
+ */
+__attribute__((always_inline)) INLINE static void hydro_reset_predicted_values(
+    struct part* restrict p, const struct xpart* restrict xp) {}
+
+/**
+ * @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) {}
+
+/**
+ * @brief Extra operations to be done during the drift
+ *
+ * @param p Particle to act upon.
+ * @param xp The extended particle data to act upon.
+ * @param dt_drift The drift time-step for positions.
+ * @param dt_therm The drift time-step for thermal quantities.
+ */
+__attribute__((always_inline)) INLINE static void hydro_predict_extra(
+    struct part* p, struct xpart* xp, float dt_drift, float dt_therm) {
+
+#ifdef GIZMO_LLOYD_ITERATION
+  return;
+#endif
+
+  const float h_inv = 1.0f / p->h;
+
+  /* Predict smoothing length */
+  const float w1 = p->force.h_dt * h_inv * dt_drift;
+  float h_corr;
+  if (fabsf(w1) < 0.2f)
+    h_corr = approx_expf(w1); /* 4th order expansion of exp(w) */
+  else
+    h_corr = expf(w1);
+
+  /* Limit the smoothing length correction (and make sure it is always
+     positive). */
+  if (h_corr < 2.0f && h_corr > 0.) {
+    p->h *= h_corr;
+  }
+
+  /* drift the primitive variables based on the old fluxes */
+  if (p->geometry.volume > 0.) {
+    p->primitives.rho += p->conserved.flux.mass * dt_drift / p->geometry.volume;
+  }
+
+  if (p->conserved.mass > 0.) {
+    p->primitives.v[0] +=
+        p->conserved.flux.momentum[0] * dt_drift / p->conserved.mass;
+    p->primitives.v[1] +=
+        p->conserved.flux.momentum[1] * dt_drift / p->conserved.mass;
+    p->primitives.v[2] +=
+        p->conserved.flux.momentum[2] * dt_drift / p->conserved.mass;
+
+#if !defined(EOS_ISOTHERMAL_GAS)
+    const float u = p->conserved.energy + p->conserved.flux.energy * dt_therm;
+    p->primitives.P =
+        hydro_gamma_minus_one * u * p->primitives.rho / p->conserved.mass;
+#endif
+  }
+
+#ifdef SWIFT_DEBUG_CHECKS
+  if (p->h <= 0.) {
+    error("Zero or negative smoothing length (%g)!", p->h);
+  }
+#endif
+
+  gizmo_check_physical_quantities("density", "pressure", p->primitives.rho,
+                                  p->primitives.v[0], p->primitives.v[1],
+                                  p->primitives.v[2], p->primitives.P);
+}
+
+/**
+ * @brief Set the particle acceleration after the flux loop
+ *
+ * We use the new conserved variables to calculate the new velocity of the
+ * particle, and use that to derive the change of the velocity over the particle
+ * time step.
+ *
+ * If the particle time step is zero, we set the accelerations to zero. This
+ * should only happen at the start of the simulation.
+ *
+ * @param p Particle to act upon.
+ * @param cosmo The cosmological model.
+ */
+__attribute__((always_inline)) INLINE static void hydro_end_force(
+    struct part* p, const struct cosmology* cosmo) {
+
+  /* set the variables that are used to drift the primitive variables */
+
+  // MATTHIEU: Bert is this correct? Do we need cosmology terms here?
+  hydro_velocities_end_force(p);
+}
+
+/**
+ * @brief Extra operations done during the kick
+ *
+ * Not used for GIZMO.
+ *
+ * @param p Particle to act upon.
+ * @param xp Extended particle data to act upon.
+ * @param dt Physical time step.
+ * @param half_dt Half the physical time step.
+ */
+__attribute__((always_inline)) INLINE static void hydro_kick_extra(
+    struct part* p, struct xpart* xp, float dt, const struct cosmology* cosmo,
+    const struct hydro_props* hydro_props) {
+
+  float a_grav[3];
+
+  /* Update conserved variables. */
+  p->conserved.mass += p->conserved.flux.mass * dt;
+  p->conserved.momentum[0] += p->conserved.flux.momentum[0] * dt;
+  p->conserved.momentum[1] += p->conserved.flux.momentum[1] * dt;
+  p->conserved.momentum[2] += p->conserved.flux.momentum[2] * dt;
+#if defined(EOS_ISOTHERMAL_GAS)
+  /* We use the EoS equation in a sneaky way here just to get the constant u */
+  p->conserved.energy =
+      p->conserved.mass * gas_internal_energy_from_entropy(0.f, 0.f);
+#else
+  p->conserved.energy += p->conserved.flux.energy * dt;
+#endif
+
+  /* Apply the minimal energy limit */
+  const float min_energy =
+      hydro_props->minimal_internal_energy * cosmo->a_factor_internal_energy;
+  if (p->conserved.energy < min_energy * p->conserved.mass) {
+    p->conserved.energy = min_energy * p->conserved.mass;
+    p->conserved.flux.energy = 0.f;
+  }
+
+  gizmo_check_physical_quantities(
+      "mass", "energy", p->conserved.mass, p->conserved.momentum[0],
+      p->conserved.momentum[1], p->conserved.momentum[2], p->conserved.energy);
+
+#ifdef SWIFT_DEBUG_CHECKS
+  /* Note that this check will only have effect if no GIZMO_UNPHYSICAL option
+     was selected. */
+  if (p->conserved.mass < 0.) {
+    error(
+        "Negative mass after conserved variables update (mass: %g, dmass: %g)!",
+        p->conserved.mass, p->conserved.flux.mass);
+  }
+
+  if (p->conserved.energy < 0.) {
+    error(
+        "Negative energy after conserved variables update (energy: %g, "
+        "denergy: %g)!",
+        p->conserved.energy, p->conserved.flux.energy);
+  }
+#endif
+
+  /* Add gravity. We only do this if we have gravity activated. */
+  if (p->gpart) {
+    /* Retrieve the current value of the gravitational acceleration from the
+       gpart. We are only allowed to do this because this is the kick. We still
+       need to check whether gpart exists though.*/
+    a_grav[0] = p->gpart->a_grav[0];
+    a_grav[1] = p->gpart->a_grav[1];
+    a_grav[2] = p->gpart->a_grav[2];
+
+    /* Make sure the gpart knows the mass has changed. */
+    p->gpart->mass = p->conserved.mass;
+
+    /* Kick the momentum for half a time step */
+    /* Note that this also affects the particle movement, as the velocity for
+       the particles is set after this. */
+    p->conserved.momentum[0] += dt * p->conserved.mass * a_grav[0];
+    p->conserved.momentum[1] += dt * p->conserved.mass * a_grav[1];
+    p->conserved.momentum[2] += dt * p->conserved.mass * a_grav[2];
+
+    p->conserved.energy += dt * (p->gravity.mflux[0] * a_grav[0] +
+                                 p->gravity.mflux[1] * a_grav[1] +
+                                 p->gravity.mflux[2] * a_grav[2]);
+  }
+
+  hydro_velocities_set(p, xp);
+
+#ifdef GIZMO_LLOYD_ITERATION
+  /* reset conserved variables to safe values */
+  p->conserved.mass = 1.;
+  p->conserved.momentum[0] = 0.;
+  p->conserved.momentum[1] = 0.;
+  p->conserved.momentum[2] = 0.;
+  p->conserved.energy = 1.;
+
+  /* set the particle velocities to the Lloyd velocities */
+  /* note that centroid is the relative position of the centroid w.r.t. the
+     particle position (position - centroid) */
+  xp->v_full[0] = -p->geometry.centroid[0] / p->force.dt;
+  xp->v_full[1] = -p->geometry.centroid[1] / p->force.dt;
+  xp->v_full[2] = -p->geometry.centroid[2] / p->force.dt;
+  p->v[0] = xp->v_full[0];
+  p->v[1] = xp->v_full[1];
+  p->v[2] = xp->v_full[2];
+#endif
+
+  /* reset wcorr */
+  p->density.wcorr = 1.0f;
+}
+
+/**
+ * @brief Returns the comoving internal energy of a particle
+ *
+ * @param p The particle of interest.
+ */
+__attribute__((always_inline)) INLINE static float
+hydro_get_comoving_internal_energy(const struct part* restrict p) {
+
+  if (p->primitives.rho > 0.)
+    return gas_internal_energy_from_pressure(p->primitives.rho,
+                                             p->primitives.P);
+  else
+    return 0.;
+}
+
+/**
+ * @brief Returns the physical internal energy of a particle
+ *
+ * @param p The particle of interest.
+ * @param cosmo The cosmological model.
+ */
+__attribute__((always_inline)) INLINE static float
+hydro_get_physical_internal_energy(const struct part* restrict p,
+                                   const struct cosmology* cosmo) {
+
+  return cosmo->a_factor_internal_energy *
+         hydro_get_comoving_internal_energy(p);
+}
+
+/**
+ * @brief Returns the comoving entropy of a particle
+ *
+ * @param p The particle of interest.
+ */
+__attribute__((always_inline)) INLINE static float hydro_get_comoving_entropy(
+    const struct part* restrict p) {
+
+  if (p->primitives.rho > 0.) {
+    return gas_entropy_from_pressure(p->primitives.rho, p->primitives.P);
+  } else {
+    return 0.;
+  }
+}
+
+/**
+ * @brief Returns the physical internal energy of a particle
+ *
+ * @param p The particle of interest.
+ * @param cosmo The cosmological model.
+ */
+__attribute__((always_inline)) INLINE static float hydro_get_physical_entropy(
+    const struct part* restrict p, const struct cosmology* cosmo) {
+
+  /* Note: no cosmological conversion required here with our choice of
+   * coordinates. */
+  return hydro_get_comoving_entropy(p);
+}
+
+/**
+ * @brief Returns the sound speed of a particle
+ *
+ * @param p The particle of interest.
+ */
+__attribute__((always_inline)) INLINE static float
+hydro_get_comoving_soundspeed(const struct part* restrict p) {
+
+  if (p->primitives.rho > 0.)
+    return gas_soundspeed_from_pressure(p->primitives.rho, p->primitives.P);
+  else
+    return 0.;
+}
+
+/**
+ * @brief Returns the physical sound speed of a particle
+ *
+ * @param p The particle of interest.
+ * @param cosmo The cosmological model.
+ */
+__attribute__((always_inline)) INLINE static float
+hydro_get_physical_soundspeed(const struct part* restrict p,
+                              const struct cosmology* cosmo) {
+
+  return cosmo->a_factor_sound_speed * hydro_get_comoving_soundspeed(p);
+}
+
+/**
+ * @brief Returns the comoving pressure of a particle
+ *
+ * @param p The particle of interest
+ */
+__attribute__((always_inline)) INLINE static float hydro_get_comoving_pressure(
+    const struct part* restrict p) {
+
+  return p->primitives.P;
+}
+
+/**
+ * @brief Returns the comoving pressure of a particle
+ *
+ * @param p The particle of interest.
+ * @param cosmo The cosmological model.
+ */
+__attribute__((always_inline)) INLINE static float hydro_get_physical_pressure(
+    const struct part* restrict p, const struct cosmology* cosmo) {
+
+  return cosmo->a_factor_pressure * p->primitives.P;
+}
+
+/**
+ * @brief Returns the mass of a particle
+ *
+ * @param p The particle of interest
+ */
+__attribute__((always_inline)) INLINE static float hydro_get_mass(
+    const struct part* restrict p) {
+
+  return p->conserved.mass;
+}
+
+/**
+ * @brief Sets the mass of a particle
+ *
+ * @param p The particle of interest
+ * @param m The mass to set.
+ */
+__attribute__((always_inline)) INLINE static void hydro_set_mass(
+    struct part* restrict p, float m) {
+
+  p->conserved.mass = m;
+}
+
+/**
+ * @brief Returns the velocities drifted to the current time of a particle.
+ *
+ * @param p The particle of interest
+ * @param xp The extended data of the particle.
+ * @param dt_kick_hydro The time (for hydro accelerations) since the last kick.
+ * @param dt_kick_grav The time (for gravity accelerations) since the last kick.
+ * @param v (return) The velocities at the current time.
+ */
+__attribute__((always_inline)) INLINE static void hydro_get_drifted_velocities(
+    const struct part* restrict p, const struct xpart* xp, float dt_kick_hydro,
+    float dt_kick_grav, float v[3]) {
+
+  if (p->conserved.mass > 0.) {
+    v[0] = p->primitives.v[0] +
+           p->conserved.flux.momentum[0] * dt_kick_hydro / p->conserved.mass;
+    v[1] = p->primitives.v[1] +
+           p->conserved.flux.momentum[1] * dt_kick_hydro / p->conserved.mass;
+    v[2] = p->primitives.v[2] +
+           p->conserved.flux.momentum[2] * dt_kick_hydro / p->conserved.mass;
+  } else {
+    v[0] = p->primitives.v[0];
+    v[1] = p->primitives.v[1];
+    v[2] = p->primitives.v[2];
+  }
+
+  // MATTHIEU: Bert is this correct?
+  v[0] += xp->a_grav[0] * dt_kick_grav;
+  v[1] += xp->a_grav[1] * dt_kick_grav;
+  v[2] += xp->a_grav[2] * dt_kick_grav;
+}
+
+/**
+ * @brief Returns the comoving density of a particle
+ *
+ * @param p The particle of interest
+ */
+__attribute__((always_inline)) INLINE static float hydro_get_comoving_density(
+    const struct part* restrict p) {
+
+  return p->primitives.rho;
+}
+
+/**
+ * @brief Returns the physical density of a particle
+ *
+ * @param p The particle of interest
+ * @param cosmo The cosmological model.
+ */
+__attribute__((always_inline)) INLINE static float hydro_get_physical_density(
+    const struct part* restrict p, const struct cosmology* cosmo) {
+
+  return cosmo->a3_inv * p->primitives.rho;
+}
+
+/**
+ * @brief Modifies the thermal state of a particle to the imposed internal
+ * energy
+ *
+ * This overrides the current state of the particle but does *not* change its
+ * time-derivatives
+ *
+ * @param p The particle
+ * @param u The new internal energy
+ */
+__attribute__((always_inline)) INLINE static void hydro_set_internal_energy(
+    struct part* restrict p, float u) {
+
+  /* conserved.energy is NOT the specific energy (u), but the total thermal
+     energy (u*m) */
+  p->conserved.energy = u * p->conserved.mass;
+#ifdef GIZMO_TOTAL_ENERGY
+  /* add the kinetic energy */
+  p->conserved.energy += 0.5f * p->conserved.mass *
+                         (p->conserved.momentum[0] * p->primitives.v[0] +
+                          p->conserved.momentum[1] * p->primitives.v[1] +
+                          p->conserved.momentum[2] * p->primitives.v[2]);
+#endif
+  p->primitives.P = hydro_gamma_minus_one * p->primitives.rho * u;
+}
+
+/**
+ * @brief Modifies the thermal state of a particle to the imposed entropy
+ *
+ * This overrides the current state of the particle but does *not* change its
+ * time-derivatives
+ *
+ * @param p The particle
+ * @param S The new entropy
+ */
+__attribute__((always_inline)) INLINE static void hydro_set_entropy(
+    struct part* restrict p, float S) {
+
+  p->conserved.energy = S * pow_gamma_minus_one(p->primitives.rho) *
+                        hydro_one_over_gamma_minus_one * p->conserved.mass;
+#ifdef GIZMO_TOTAL_ENERGY
+  /* add the kinetic energy */
+  p->conserved.energy += 0.5f * p->conserved.mass *
+                         (p->conserved.momentum[0] * p->primitives.v[0] +
+                          p->conserved.momentum[1] * p->primitives.v[1] +
+                          p->conserved.momentum[2] * p->primitives.v[2]);
+#endif
+  p->primitives.P = S * pow_gamma(p->primitives.rho);
+}
+
+/**
+ * @brief Overwrite the initial internal energy of a particle.
+ *
+ * Note that in the cases where the thermodynamic variable is not
+ * internal energy but gets converted later, we must overwrite that
+ * field. The conversion to the actual variable happens later after
+ * the initial fake time-step.
+ *
+ * @param p The #part to write to.
+ * @param u_init The new initial internal energy.
+ */
+__attribute__((always_inline)) INLINE static void
+hydro_set_init_internal_energy(struct part* p, float u_init) {
+
+  p->conserved.energy = u_init * p->conserved.mass;
+#ifdef GIZMO_TOTAL_ENERGY
+  /* add the kinetic energy */
+  p->conserved.energy += 0.5f * p->conserved.mass *
+                         (p->conserved.momentum[0] * p->primitives.v[0] +
+                          p->conserved.momentum[1] * p->primitives.v[1] +
+                          p->conserved.momentum[2] * p->primitives.v[2]);
+#endif
+  p->primitives.P = hydro_gamma_minus_one * p->primitives.rho * u_init;
+}
+
+#endif /* SWIFT_GIZMO_MFV_HYDRO_H */
diff --git a/src/hydro/GizmoMFV/hydro_debug.h b/src/hydro/GizmoMFV/hydro_debug.h
new file mode 100644
index 0000000000000000000000000000000000000000..8af3f824666529efad833c3bd520ace779718449
--- /dev/null
+++ b/src/hydro/GizmoMFV/hydro_debug.h
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Coypright (c) 2016 Matthieu Schaller (matthieu.schaller@durham.ac.uk)
+ *
+ * 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/>.
+ *
+ ******************************************************************************/
+#ifndef SWIFT_GIZMO_MFV_HYDRO_DEBUG_H
+#define SWIFT_GIZMO_MFV_HYDRO_DEBUG_H
+
+__attribute__((always_inline)) INLINE static void hydro_debug_particle(
+    const struct part* p, const struct xpart* xp) {
+  printf(
+      "x=[%.16e,%.16e,%.16e], "
+      "v=[%.3e,%.3e,%.3e], "
+      "a=[%.3e,%.3e,%.3e], "
+      "h=%.3e, "
+      "time_bin=%d, "
+      "primitives={"
+      "v=[%.3e,%.3e,%.3e], "
+      "rho=%.3e, "
+      "P=%.3e, "
+      "gradients={"
+      "rho=[%.3e,%.3e,%.3e], "
+      "v=[[%.3e,%.3e,%.3e],[%.3e,%.3e,%.3e],[%.3e,%.3e,%.3e]], "
+      "P=[%.3e,%.3e,%.3e]}, "
+      "limiter={"
+      "rho=[%.3e,%.3e], "
+      "v=[[%.3e,%.3e],[%.3e,%.3e],[%.3e,%.3e]], "
+      "P=[%.3e,%.3e], "
+      "maxr=%.3e}}, "
+      "conserved={"
+      "momentum=[%.3e,%.3e,%.3e], "
+      "mass=%.3e, "
+      "energy=%.3e}, "
+      "geometry={"
+      "volume=%.3e, "
+      "matrix_E=[[%.3e,%.3e,%.3e],[%.3e,%.3e,%.3e],[%.3e,%.3e,%.3e]]}, "
+      "timestepvars={"
+      "vmax=%.3e},"
+      "density={"
+      "wcount_dh=%.3e, "
+      "wcount=%.3e}\n",
+      p->x[0], p->x[1], p->x[2], p->v[0], p->v[1], p->v[2], p->a_hydro[0],
+      p->a_hydro[1], p->a_hydro[2], p->h, p->time_bin, p->primitives.v[0],
+      p->primitives.v[1], p->primitives.v[2], p->primitives.rho,
+      p->primitives.P, p->primitives.gradients.rho[0],
+      p->primitives.gradients.rho[1], p->primitives.gradients.rho[2],
+      p->primitives.gradients.v[0][0], p->primitives.gradients.v[0][1],
+      p->primitives.gradients.v[0][2], p->primitives.gradients.v[1][0],
+      p->primitives.gradients.v[1][1], p->primitives.gradients.v[1][2],
+      p->primitives.gradients.v[2][0], p->primitives.gradients.v[2][1],
+      p->primitives.gradients.v[2][2], p->primitives.gradients.P[0],
+      p->primitives.gradients.P[1], p->primitives.gradients.P[2],
+      p->primitives.limiter.rho[0], p->primitives.limiter.rho[1],
+      p->primitives.limiter.v[0][0], p->primitives.limiter.v[0][1],
+      p->primitives.limiter.v[1][0], p->primitives.limiter.v[1][1],
+      p->primitives.limiter.v[2][0], p->primitives.limiter.v[2][1],
+      p->primitives.limiter.P[0], p->primitives.limiter.P[1],
+      p->primitives.limiter.maxr, p->conserved.momentum[0],
+      p->conserved.momentum[1], p->conserved.momentum[2], p->conserved.mass,
+      p->conserved.energy, p->geometry.volume, p->geometry.matrix_E[0][0],
+      p->geometry.matrix_E[0][1], p->geometry.matrix_E[0][2],
+      p->geometry.matrix_E[1][0], p->geometry.matrix_E[1][1],
+      p->geometry.matrix_E[1][2], p->geometry.matrix_E[2][0],
+      p->geometry.matrix_E[2][1], p->geometry.matrix_E[2][2],
+      p->timestepvars.vmax, p->density.wcount_dh, p->density.wcount);
+}
+
+#endif /* SWIFT_GIZMO_MFV_HYDRO_DEBUG_H */
diff --git a/src/hydro/GizmoMFV/hydro_gradients.h b/src/hydro/GizmoMFV/hydro_gradients.h
new file mode 100644
index 0000000000000000000000000000000000000000..387c263775ddfb37e4c7cb31a624ba5dc673beb2
--- /dev/null
+++ b/src/hydro/GizmoMFV/hydro_gradients.h
@@ -0,0 +1,159 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Copyright (c) 2016 Bert Vandenbroucke (bert.vandenbroucke@gmail.com)
+ *
+ * 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/>.
+ *
+ ******************************************************************************/
+
+#ifndef SWIFT_HYDRO_GIZMO_MFV_GRADIENTS_H
+#define SWIFT_HYDRO_GIZMO_MFV_GRADIENTS_H
+
+#include "hydro_slope_limiters.h"
+#include "hydro_unphysical.h"
+#include "riemann.h"
+
+#if defined(GRADIENTS_SPH)
+
+#define HYDRO_GRADIENT_IMPLEMENTATION "SPH gradients (Price 2012)"
+#include "hydro_gradients_sph.h"
+
+#elif defined(GRADIENTS_GIZMO)
+
+#define HYDRO_GRADIENT_IMPLEMENTATION "GIZMO gradients (Hopkins 2015)"
+#include "hydro_gradients_gizmo.h"
+
+#else
+
+/* No gradients. Perfectly acceptable, but we have to provide empty functions */
+#define HYDRO_GRADIENT_IMPLEMENTATION "No gradients (first order scheme)"
+
+/**
+ * @brief Initialize gradient variables
+ *
+ * @param p Particle.
+ */
+__attribute__((always_inline)) INLINE static void hydro_gradients_init(
+    struct part *p) {}
+
+/**
+ * @brief Gradient calculations done during the neighbour loop
+ *
+ * @param r2 Squared distance between the two particles.
+ * @param dx Distance vector (pi->x - pj->x).
+ * @param hi Smoothing length of particle i.
+ * @param hj Smoothing length of particle j.
+ * @param pi Particle i.
+ * @param pj Particle j.
+ */
+__attribute__((always_inline)) INLINE static void hydro_gradients_collect(
+    float r2, const float *dx, float hi, float hj, struct part *restrict pi,
+    struct part *restrict pj) {}
+
+/**
+ * @brief Gradient calculations done during the neighbour loop: non-symmetric
+ * version
+ *
+ * @param r2 Squared distance between the two particles.
+ * @param dx Distance vector (pi->x - pj->x).
+ * @param hi Smoothing length of particle i.
+ * @param hj Smoothing length of particle j.
+ * @param pi Particle i.
+ * @param pj Particle j.
+ */
+__attribute__((always_inline)) INLINE static void
+hydro_gradients_nonsym_collect(float r2, const float *dx, float hi, float hj,
+                               struct part *restrict pi,
+                               struct part *restrict pj) {}
+
+/**
+ * @brief Finalize the gradient variables after all data have been collected
+ *
+ * @param p Particle.
+ */
+__attribute__((always_inline)) INLINE static void hydro_gradients_finalize(
+    struct part *p) {}
+
+#endif
+
+/**
+ * @brief Gradients reconstruction. Is the same for all gradient types (although
+ * gradients_none does nothing, since all gradients are zero -- are they?).
+ */
+__attribute__((always_inline)) INLINE static void hydro_gradients_predict(
+    struct part* restrict pi, struct part* restrict pj, float hi, float hj,
+    const float* dx, float r, const float* xij_i, float* Wi, float* Wj) {
+
+  /* perform gradient reconstruction in space and time */
+  /* Compute interface position (relative to pj, since we don't need the actual
+   * position) eqn. (8) */
+  const float xfac = hj / (hi + hj);
+  const float xij_j[3] = {xfac * dx[0], xfac * dx[1], xfac * dx[2]};
+
+  float dWi[5];
+  dWi[0] = pi->primitives.gradients.rho[0] * xij_i[0] +
+           pi->primitives.gradients.rho[1] * xij_i[1] +
+           pi->primitives.gradients.rho[2] * xij_i[2];
+  dWi[1] = pi->primitives.gradients.v[0][0] * xij_i[0] +
+           pi->primitives.gradients.v[0][1] * xij_i[1] +
+           pi->primitives.gradients.v[0][2] * xij_i[2];
+  dWi[2] = pi->primitives.gradients.v[1][0] * xij_i[0] +
+           pi->primitives.gradients.v[1][1] * xij_i[1] +
+           pi->primitives.gradients.v[1][2] * xij_i[2];
+  dWi[3] = pi->primitives.gradients.v[2][0] * xij_i[0] +
+           pi->primitives.gradients.v[2][1] * xij_i[1] +
+           pi->primitives.gradients.v[2][2] * xij_i[2];
+  dWi[4] = pi->primitives.gradients.P[0] * xij_i[0] +
+           pi->primitives.gradients.P[1] * xij_i[1] +
+           pi->primitives.gradients.P[2] * xij_i[2];
+
+  float dWj[5];
+  dWj[0] = pj->primitives.gradients.rho[0] * xij_j[0] +
+           pj->primitives.gradients.rho[1] * xij_j[1] +
+           pj->primitives.gradients.rho[2] * xij_j[2];
+  dWj[1] = pj->primitives.gradients.v[0][0] * xij_j[0] +
+           pj->primitives.gradients.v[0][1] * xij_j[1] +
+           pj->primitives.gradients.v[0][2] * xij_j[2];
+  dWj[2] = pj->primitives.gradients.v[1][0] * xij_j[0] +
+           pj->primitives.gradients.v[1][1] * xij_j[1] +
+           pj->primitives.gradients.v[1][2] * xij_j[2];
+  dWj[3] = pj->primitives.gradients.v[2][0] * xij_j[0] +
+           pj->primitives.gradients.v[2][1] * xij_j[1] +
+           pj->primitives.gradients.v[2][2] * xij_j[2];
+  dWj[4] = pj->primitives.gradients.P[0] * xij_j[0] +
+           pj->primitives.gradients.P[1] * xij_j[1] +
+           pj->primitives.gradients.P[2] * xij_j[2];
+
+  /* Apply the slope limiter at this interface */
+  hydro_slope_limit_face(Wi, Wj, dWi, dWj, xij_i, xij_j, r);
+
+  Wi[0] += dWi[0];
+  Wi[1] += dWi[1];
+  Wi[2] += dWi[2];
+  Wi[3] += dWi[3];
+  Wi[4] += dWi[4];
+
+  Wj[0] += dWj[0];
+  Wj[1] += dWj[1];
+  Wj[2] += dWj[2];
+  Wj[3] += dWj[3];
+  Wj[4] += dWj[4];
+
+  gizmo_check_physical_quantities("density", "pressure", Wi[0], Wi[1], Wi[2],
+                                  Wi[3], Wi[4]);
+  gizmo_check_physical_quantities("density", "pressure", Wj[0], Wj[1], Wj[2],
+                                  Wj[3], Wj[4]);
+}
+
+#endif /* SWIFT_HYDRO_GIZMO_MFV_GRADIENTS_H */
diff --git a/src/hydro/GizmoMFV/hydro_gradients_gizmo.h b/src/hydro/GizmoMFV/hydro_gradients_gizmo.h
new file mode 100644
index 0000000000000000000000000000000000000000..2592f46da9a8c118d18beba933f98f477ec5a3b2
--- /dev/null
+++ b/src/hydro/GizmoMFV/hydro_gradients_gizmo.h
@@ -0,0 +1,488 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Copyright (c) 2016 Bert Vandenbroucke (bert.vandenbroucke@gmail.com)
+ *
+ * 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/>.
+ *
+ ******************************************************************************/
+
+/**
+ * @brief Initialize gradient variables
+ *
+ * @param p Particle.
+ */
+#ifndef SWIFT_GIZMO_MFV_HYDRO_GRADIENTS_H
+#define SWIFT_GIZMO_MFV_HYDRO_GRADIENTS_H
+
+__attribute__((always_inline)) INLINE static void hydro_gradients_init(
+    struct part *p) {
+
+  p->primitives.gradients.rho[0] = 0.0f;
+  p->primitives.gradients.rho[1] = 0.0f;
+  p->primitives.gradients.rho[2] = 0.0f;
+
+  p->primitives.gradients.v[0][0] = 0.0f;
+  p->primitives.gradients.v[0][1] = 0.0f;
+  p->primitives.gradients.v[0][2] = 0.0f;
+
+  p->primitives.gradients.v[1][0] = 0.0f;
+  p->primitives.gradients.v[1][1] = 0.0f;
+  p->primitives.gradients.v[1][2] = 0.0f;
+
+  p->primitives.gradients.v[2][0] = 0.0f;
+  p->primitives.gradients.v[2][1] = 0.0f;
+  p->primitives.gradients.v[2][2] = 0.0f;
+
+  p->primitives.gradients.P[0] = 0.0f;
+  p->primitives.gradients.P[1] = 0.0f;
+  p->primitives.gradients.P[2] = 0.0f;
+
+  hydro_slope_limit_cell_init(p);
+}
+
+/**
+ * @brief Gradient calculations done during the neighbour loop
+ *
+ * @param r2 Squared distance between the two particles.
+ * @param dx Distance vector (pi->x - pj->x).
+ * @param hi Smoothing length of particle i.
+ * @param hj Smoothing length of particle j.
+ * @param pi Particle i.
+ * @param pj Particle j.
+ */
+__attribute__((always_inline)) INLINE static void hydro_gradients_collect(
+    float r2, const float *dx, float hi, float hj, struct part *restrict pi,
+    struct part *restrict pj) {
+
+  const float r_inv = 1.f / sqrtf(r2);
+  const float r = r2 * r_inv;
+
+  float wi, wj, wi_dx, wj_dx;
+  float Bi[3][3];
+  float Bj[3][3];
+  float Wi[5], Wj[5];
+
+  /* Initialize local variables */
+  for (int k = 0; k < 3; k++) {
+    for (int l = 0; l < 3; l++) {
+      Bi[k][l] = pi->geometry.matrix_E[k][l];
+      Bj[k][l] = pj->geometry.matrix_E[k][l];
+    }
+  }
+  Wi[0] = pi->primitives.rho;
+  Wi[1] = pi->primitives.v[0];
+  Wi[2] = pi->primitives.v[1];
+  Wi[3] = pi->primitives.v[2];
+  Wi[4] = pi->primitives.P;
+  Wj[0] = pj->primitives.rho;
+  Wj[1] = pj->primitives.v[0];
+  Wj[2] = pj->primitives.v[1];
+  Wj[3] = pj->primitives.v[2];
+  Wj[4] = pj->primitives.P;
+
+  /* Compute kernel of pi. */
+  const float hi_inv = 1.f / hi;
+  const float xi = r * hi_inv;
+  kernel_deval(xi, &wi, &wi_dx);
+
+  if (pi->density.wcorr > const_gizmo_min_wcorr) {
+    /* Compute gradients for pi */
+    /* there is a sign difference w.r.t. eqn. (6) because of the inverse
+     * definition of dx */
+    pi->primitives.gradients.rho[0] +=
+        (Wi[0] - Wj[0]) * wi *
+        (Bi[0][0] * dx[0] + Bi[0][1] * dx[1] + Bi[0][2] * dx[2]);
+    pi->primitives.gradients.rho[1] +=
+        (Wi[0] - Wj[0]) * wi *
+        (Bi[1][0] * dx[0] + Bi[1][1] * dx[1] + Bi[1][2] * dx[2]);
+    pi->primitives.gradients.rho[2] +=
+        (Wi[0] - Wj[0]) * wi *
+        (Bi[2][0] * dx[0] + Bi[2][1] * dx[1] + Bi[2][2] * dx[2]);
+
+    pi->primitives.gradients.v[0][0] +=
+        (Wi[1] - Wj[1]) * wi *
+        (Bi[0][0] * dx[0] + Bi[0][1] * dx[1] + Bi[0][2] * dx[2]);
+    pi->primitives.gradients.v[0][1] +=
+        (Wi[1] - Wj[1]) * wi *
+        (Bi[1][0] * dx[0] + Bi[1][1] * dx[1] + Bi[1][2] * dx[2]);
+    pi->primitives.gradients.v[0][2] +=
+        (Wi[1] - Wj[1]) * wi *
+        (Bi[2][0] * dx[0] + Bi[2][1] * dx[1] + Bi[2][2] * dx[2]);
+    pi->primitives.gradients.v[1][0] +=
+        (Wi[2] - Wj[2]) * wi *
+        (Bi[0][0] * dx[0] + Bi[0][1] * dx[1] + Bi[0][2] * dx[2]);
+    pi->primitives.gradients.v[1][1] +=
+        (Wi[2] - Wj[2]) * wi *
+        (Bi[1][0] * dx[0] + Bi[1][1] * dx[1] + Bi[1][2] * dx[2]);
+    pi->primitives.gradients.v[1][2] +=
+        (Wi[2] - Wj[2]) * wi *
+        (Bi[2][0] * dx[0] + Bi[2][1] * dx[1] + Bi[2][2] * dx[2]);
+    pi->primitives.gradients.v[2][0] +=
+        (Wi[3] - Wj[3]) * wi *
+        (Bi[0][0] * dx[0] + Bi[0][1] * dx[1] + Bi[0][2] * dx[2]);
+    pi->primitives.gradients.v[2][1] +=
+        (Wi[3] - Wj[3]) * wi *
+        (Bi[1][0] * dx[0] + Bi[1][1] * dx[1] + Bi[1][2] * dx[2]);
+    pi->primitives.gradients.v[2][2] +=
+        (Wi[3] - Wj[3]) * wi *
+        (Bi[2][0] * dx[0] + Bi[2][1] * dx[1] + Bi[2][2] * dx[2]);
+
+    pi->primitives.gradients.P[0] +=
+        (Wi[4] - Wj[4]) * wi *
+        (Bi[0][0] * dx[0] + Bi[0][1] * dx[1] + Bi[0][2] * dx[2]);
+    pi->primitives.gradients.P[1] +=
+        (Wi[4] - Wj[4]) * wi *
+        (Bi[1][0] * dx[0] + Bi[1][1] * dx[1] + Bi[1][2] * dx[2]);
+    pi->primitives.gradients.P[2] +=
+        (Wi[4] - Wj[4]) * wi *
+        (Bi[2][0] * dx[0] + Bi[2][1] * dx[1] + Bi[2][2] * dx[2]);
+
+  } else {
+    /* The gradient matrix was not well-behaved, switch to SPH gradients */
+
+    pi->primitives.gradients.rho[0] -=
+        wi_dx * dx[0] * (pi->primitives.rho - pj->primitives.rho) * r_inv;
+    pi->primitives.gradients.rho[1] -=
+        wi_dx * dx[1] * (pi->primitives.rho - pj->primitives.rho) * r_inv;
+    pi->primitives.gradients.rho[2] -=
+        wi_dx * dx[2] * (pi->primitives.rho - pj->primitives.rho) * r_inv;
+
+    pi->primitives.gradients.v[0][0] -=
+        wi_dx * dx[0] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv;
+    pi->primitives.gradients.v[0][1] -=
+        wi_dx * dx[1] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv;
+    pi->primitives.gradients.v[0][2] -=
+        wi_dx * dx[2] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv;
+
+    pi->primitives.gradients.v[1][0] -=
+        wi_dx * dx[0] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv;
+    pi->primitives.gradients.v[1][1] -=
+        wi_dx * dx[1] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv;
+    pi->primitives.gradients.v[1][2] -=
+        wi_dx * dx[2] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv;
+
+    pi->primitives.gradients.v[2][0] -=
+        wi_dx * dx[0] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv;
+    pi->primitives.gradients.v[2][1] -=
+        wi_dx * dx[1] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv;
+    pi->primitives.gradients.v[2][2] -=
+        wi_dx * dx[2] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv;
+
+    pi->primitives.gradients.P[0] -=
+        wi_dx * dx[0] * (pi->primitives.P - pj->primitives.P) * r_inv;
+    pi->primitives.gradients.P[1] -=
+        wi_dx * dx[1] * (pi->primitives.P - pj->primitives.P) * r_inv;
+    pi->primitives.gradients.P[2] -=
+        wi_dx * dx[2] * (pi->primitives.P - pj->primitives.P) * r_inv;
+  }
+
+  hydro_slope_limit_cell_collect(pi, pj, r);
+
+  /* Compute kernel of pj. */
+  const float hj_inv = 1.f / hj;
+  const float xj = r * hj_inv;
+  kernel_deval(xj, &wj, &wj_dx);
+
+  if (pj->density.wcorr > const_gizmo_min_wcorr) {
+    /* Compute gradients for pj */
+    /* there is no sign difference w.r.t. eqn. (6) because dx is now what we
+     * want
+     * it to be */
+    pj->primitives.gradients.rho[0] +=
+        (Wi[0] - Wj[0]) * wj *
+        (Bj[0][0] * dx[0] + Bj[0][1] * dx[1] + Bj[0][2] * dx[2]);
+    pj->primitives.gradients.rho[1] +=
+        (Wi[0] - Wj[0]) * wj *
+        (Bj[1][0] * dx[0] + Bj[1][1] * dx[1] + Bj[1][2] * dx[2]);
+    pj->primitives.gradients.rho[2] +=
+        (Wi[0] - Wj[0]) * wj *
+        (Bj[2][0] * dx[0] + Bj[2][1] * dx[1] + Bj[2][2] * dx[2]);
+
+    pj->primitives.gradients.v[0][0] +=
+        (Wi[1] - Wj[1]) * wj *
+        (Bj[0][0] * dx[0] + Bj[0][1] * dx[1] + Bj[0][2] * dx[2]);
+    pj->primitives.gradients.v[0][1] +=
+        (Wi[1] - Wj[1]) * wj *
+        (Bj[1][0] * dx[0] + Bj[1][1] * dx[1] + Bj[1][2] * dx[2]);
+    pj->primitives.gradients.v[0][2] +=
+        (Wi[1] - Wj[1]) * wj *
+        (Bj[2][0] * dx[0] + Bj[2][1] * dx[1] + Bj[2][2] * dx[2]);
+    pj->primitives.gradients.v[1][0] +=
+        (Wi[2] - Wj[2]) * wj *
+        (Bj[0][0] * dx[0] + Bj[0][1] * dx[1] + Bj[0][2] * dx[2]);
+    pj->primitives.gradients.v[1][1] +=
+        (Wi[2] - Wj[2]) * wj *
+        (Bj[1][0] * dx[0] + Bj[1][1] * dx[1] + Bj[1][2] * dx[2]);
+    pj->primitives.gradients.v[1][2] +=
+        (Wi[2] - Wj[2]) * wj *
+        (Bj[2][0] * dx[0] + Bj[2][1] * dx[1] + Bj[2][2] * dx[2]);
+    pj->primitives.gradients.v[2][0] +=
+        (Wi[3] - Wj[3]) * wj *
+        (Bj[0][0] * dx[0] + Bj[0][1] * dx[1] + Bj[0][2] * dx[2]);
+    pj->primitives.gradients.v[2][1] +=
+        (Wi[3] - Wj[3]) * wj *
+        (Bj[1][0] * dx[0] + Bj[1][1] * dx[1] + Bj[1][2] * dx[2]);
+    pj->primitives.gradients.v[2][2] +=
+        (Wi[3] - Wj[3]) * wj *
+        (Bj[2][0] * dx[0] + Bj[2][1] * dx[1] + Bj[2][2] * dx[2]);
+
+    pj->primitives.gradients.P[0] +=
+        (Wi[4] - Wj[4]) * wj *
+        (Bj[0][0] * dx[0] + Bj[0][1] * dx[1] + Bj[0][2] * dx[2]);
+    pj->primitives.gradients.P[1] +=
+        (Wi[4] - Wj[4]) * wj *
+        (Bj[1][0] * dx[0] + Bj[1][1] * dx[1] + Bj[1][2] * dx[2]);
+    pj->primitives.gradients.P[2] +=
+        (Wi[4] - Wj[4]) * wj *
+        (Bj[2][0] * dx[0] + Bj[2][1] * dx[1] + Bj[2][2] * dx[2]);
+
+  } else {
+    /* SPH gradients */
+
+    pj->primitives.gradients.rho[0] -=
+        wj_dx * dx[0] * (pi->primitives.rho - pj->primitives.rho) * r_inv;
+    pj->primitives.gradients.rho[1] -=
+        wj_dx * dx[1] * (pi->primitives.rho - pj->primitives.rho) * r_inv;
+    pj->primitives.gradients.rho[2] -=
+        wj_dx * dx[2] * (pi->primitives.rho - pj->primitives.rho) * r_inv;
+
+    pj->primitives.gradients.v[0][0] -=
+        wj_dx * dx[0] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv;
+    pj->primitives.gradients.v[0][1] -=
+        wj_dx * dx[1] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv;
+    pj->primitives.gradients.v[0][2] -=
+        wj_dx * dx[2] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv;
+
+    pj->primitives.gradients.v[1][0] -=
+        wj_dx * dx[0] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv;
+    pj->primitives.gradients.v[1][1] -=
+        wj_dx * dx[1] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv;
+    pj->primitives.gradients.v[1][2] -=
+        wj_dx * dx[2] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv;
+    pj->primitives.gradients.v[2][0] -=
+        wj_dx * dx[0] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv;
+    pj->primitives.gradients.v[2][1] -=
+        wj_dx * dx[1] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv;
+    pj->primitives.gradients.v[2][2] -=
+        wj_dx * dx[2] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv;
+
+    pj->primitives.gradients.P[0] -=
+        wj_dx * dx[0] * (pi->primitives.P - pj->primitives.P) * r_inv;
+    pj->primitives.gradients.P[1] -=
+        wj_dx * dx[1] * (pi->primitives.P - pj->primitives.P) * r_inv;
+    pj->primitives.gradients.P[2] -=
+        wj_dx * dx[2] * (pi->primitives.P - pj->primitives.P) * r_inv;
+  }
+
+  hydro_slope_limit_cell_collect(pj, pi, r);
+}
+
+/**
+ * @brief Gradient calculations done during the neighbour loop
+ *
+ * @param r2 Squared distance between the two particles.
+ * @param dx Distance vector (pi->x - pj->x).
+ * @param hi Smoothing length of particle i.
+ * @param hj Smoothing length of particle j.
+ * @param pi Particle i.
+ * @param pj Particle j.
+ */
+__attribute__((always_inline)) INLINE static void
+hydro_gradients_nonsym_collect(float r2, const float *dx, float hi, float hj,
+                               struct part *restrict pi,
+                               struct part *restrict pj) {
+
+  const float r_inv = 1.f / sqrtf(r2);
+  const float r = r2 * r_inv;
+
+  float Bi[3][3];
+  float Wi[5], Wj[5];
+
+  /* Initialize local variables */
+  for (int k = 0; k < 3; k++) {
+    for (int l = 0; l < 3; l++) {
+      Bi[k][l] = pi->geometry.matrix_E[k][l];
+    }
+  }
+  Wi[0] = pi->primitives.rho;
+  Wi[1] = pi->primitives.v[0];
+  Wi[2] = pi->primitives.v[1];
+  Wi[3] = pi->primitives.v[2];
+  Wi[4] = pi->primitives.P;
+  Wj[0] = pj->primitives.rho;
+  Wj[1] = pj->primitives.v[0];
+  Wj[2] = pj->primitives.v[1];
+  Wj[3] = pj->primitives.v[2];
+  Wj[4] = pj->primitives.P;
+
+  /* Compute kernel of pi. */
+  float wi, wi_dx;
+  const float hi_inv = 1.f / hi;
+  const float xi = r * hi_inv;
+  kernel_deval(xi, &wi, &wi_dx);
+
+  if (pi->density.wcorr > const_gizmo_min_wcorr) {
+    /* Compute gradients for pi */
+    /* there is a sign difference w.r.t. eqn. (6) because of the inverse
+     * definition of dx */
+    pi->primitives.gradients.rho[0] +=
+        (Wi[0] - Wj[0]) * wi *
+        (Bi[0][0] * dx[0] + Bi[0][1] * dx[1] + Bi[0][2] * dx[2]);
+    pi->primitives.gradients.rho[1] +=
+        (Wi[0] - Wj[0]) * wi *
+        (Bi[1][0] * dx[0] + Bi[1][1] * dx[1] + Bi[1][2] * dx[2]);
+    pi->primitives.gradients.rho[2] +=
+        (Wi[0] - Wj[0]) * wi *
+        (Bi[2][0] * dx[0] + Bi[2][1] * dx[1] + Bi[2][2] * dx[2]);
+
+    pi->primitives.gradients.v[0][0] +=
+        (Wi[1] - Wj[1]) * wi *
+        (Bi[0][0] * dx[0] + Bi[0][1] * dx[1] + Bi[0][2] * dx[2]);
+    pi->primitives.gradients.v[0][1] +=
+        (Wi[1] - Wj[1]) * wi *
+        (Bi[1][0] * dx[0] + Bi[1][1] * dx[1] + Bi[1][2] * dx[2]);
+    pi->primitives.gradients.v[0][2] +=
+        (Wi[1] - Wj[1]) * wi *
+        (Bi[2][0] * dx[0] + Bi[2][1] * dx[1] + Bi[2][2] * dx[2]);
+    pi->primitives.gradients.v[1][0] +=
+        (Wi[2] - Wj[2]) * wi *
+        (Bi[0][0] * dx[0] + Bi[0][1] * dx[1] + Bi[0][2] * dx[2]);
+    pi->primitives.gradients.v[1][1] +=
+        (Wi[2] - Wj[2]) * wi *
+        (Bi[1][0] * dx[0] + Bi[1][1] * dx[1] + Bi[1][2] * dx[2]);
+    pi->primitives.gradients.v[1][2] +=
+        (Wi[2] - Wj[2]) * wi *
+        (Bi[2][0] * dx[0] + Bi[2][1] * dx[1] + Bi[2][2] * dx[2]);
+    pi->primitives.gradients.v[2][0] +=
+        (Wi[3] - Wj[3]) * wi *
+        (Bi[0][0] * dx[0] + Bi[0][1] * dx[1] + Bi[0][2] * dx[2]);
+    pi->primitives.gradients.v[2][1] +=
+        (Wi[3] - Wj[3]) * wi *
+        (Bi[1][0] * dx[0] + Bi[1][1] * dx[1] + Bi[1][2] * dx[2]);
+    pi->primitives.gradients.v[2][2] +=
+        (Wi[3] - Wj[3]) * wi *
+        (Bi[2][0] * dx[0] + Bi[2][1] * dx[1] + Bi[2][2] * dx[2]);
+
+    pi->primitives.gradients.P[0] +=
+        (Wi[4] - Wj[4]) * wi *
+        (Bi[0][0] * dx[0] + Bi[0][1] * dx[1] + Bi[0][2] * dx[2]);
+    pi->primitives.gradients.P[1] +=
+        (Wi[4] - Wj[4]) * wi *
+        (Bi[1][0] * dx[0] + Bi[1][1] * dx[1] + Bi[1][2] * dx[2]);
+    pi->primitives.gradients.P[2] +=
+        (Wi[4] - Wj[4]) * wi *
+        (Bi[2][0] * dx[0] + Bi[2][1] * dx[1] + Bi[2][2] * dx[2]);
+
+  } else {
+    /* Gradient matrix is not well-behaved, switch to SPH gradients */
+
+    pi->primitives.gradients.rho[0] -=
+        wi_dx * dx[0] * (pi->primitives.rho - pj->primitives.rho) * r_inv;
+    pi->primitives.gradients.rho[1] -=
+        wi_dx * dx[1] * (pi->primitives.rho - pj->primitives.rho) * r_inv;
+    pi->primitives.gradients.rho[2] -=
+        wi_dx * dx[2] * (pi->primitives.rho - pj->primitives.rho) * r_inv;
+
+    pi->primitives.gradients.v[0][0] -=
+        wi_dx * dx[0] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv;
+    pi->primitives.gradients.v[0][1] -=
+        wi_dx * dx[1] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv;
+    pi->primitives.gradients.v[0][2] -=
+        wi_dx * dx[2] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv;
+    pi->primitives.gradients.v[1][0] -=
+        wi_dx * dx[0] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv;
+    pi->primitives.gradients.v[1][1] -=
+        wi_dx * dx[1] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv;
+    pi->primitives.gradients.v[1][2] -=
+        wi_dx * dx[2] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv;
+
+    pi->primitives.gradients.v[2][0] -=
+        wi_dx * dx[0] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv;
+    pi->primitives.gradients.v[2][1] -=
+        wi_dx * dx[1] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv;
+    pi->primitives.gradients.v[2][2] -=
+        wi_dx * dx[2] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv;
+
+    pi->primitives.gradients.P[0] -=
+        wi_dx * dx[0] * (pi->primitives.P - pj->primitives.P) * r_inv;
+    pi->primitives.gradients.P[1] -=
+        wi_dx * dx[1] * (pi->primitives.P - pj->primitives.P) * r_inv;
+    pi->primitives.gradients.P[2] -=
+        wi_dx * dx[2] * (pi->primitives.P - pj->primitives.P) * r_inv;
+  }
+
+  hydro_slope_limit_cell_collect(pi, pj, r);
+}
+
+/**
+ * @brief Finalize the gradient variables after all data have been collected
+ *
+ * @param p Particle.
+ */
+__attribute__((always_inline)) INLINE static void hydro_gradients_finalize(
+    struct part *p) {
+
+  /* add kernel normalization to gradients */
+  const float volume = p->geometry.volume;
+  const float h = p->h;
+  const float h_inv = 1.0f / h;
+  const float ihdim = pow_dimension(h_inv);
+  const float ihdimp1 = pow_dimension_plus_one(h_inv);
+
+  if (p->density.wcorr > const_gizmo_min_wcorr) {
+    p->primitives.gradients.rho[0] *= ihdim;
+    p->primitives.gradients.rho[1] *= ihdim;
+    p->primitives.gradients.rho[2] *= ihdim;
+
+    p->primitives.gradients.v[0][0] *= ihdim;
+    p->primitives.gradients.v[0][1] *= ihdim;
+    p->primitives.gradients.v[0][2] *= ihdim;
+    p->primitives.gradients.v[1][0] *= ihdim;
+    p->primitives.gradients.v[1][1] *= ihdim;
+    p->primitives.gradients.v[1][2] *= ihdim;
+    p->primitives.gradients.v[2][0] *= ihdim;
+    p->primitives.gradients.v[2][1] *= ihdim;
+    p->primitives.gradients.v[2][2] *= ihdim;
+
+    p->primitives.gradients.P[0] *= ihdim;
+    p->primitives.gradients.P[1] *= ihdim;
+    p->primitives.gradients.P[2] *= ihdim;
+
+  } else {
+
+    /* finalize gradients by multiplying with volume */
+    p->primitives.gradients.rho[0] *= ihdimp1 * volume;
+    p->primitives.gradients.rho[1] *= ihdimp1 * volume;
+    p->primitives.gradients.rho[2] *= ihdimp1 * volume;
+
+    p->primitives.gradients.v[0][0] *= ihdimp1 * volume;
+    p->primitives.gradients.v[0][1] *= ihdimp1 * volume;
+    p->primitives.gradients.v[0][2] *= ihdimp1 * volume;
+
+    p->primitives.gradients.v[1][0] *= ihdimp1 * volume;
+    p->primitives.gradients.v[1][1] *= ihdimp1 * volume;
+    p->primitives.gradients.v[1][2] *= ihdimp1 * volume;
+    p->primitives.gradients.v[2][0] *= ihdimp1 * volume;
+    p->primitives.gradients.v[2][1] *= ihdimp1 * volume;
+    p->primitives.gradients.v[2][2] *= ihdimp1 * volume;
+
+    p->primitives.gradients.P[0] *= ihdimp1 * volume;
+    p->primitives.gradients.P[1] *= ihdimp1 * volume;
+    p->primitives.gradients.P[2] *= ihdimp1 * volume;
+  }
+
+  hydro_slope_limit_cell(p);
+}
+
+#endif /* SWIFT_GIZMO_MFV_HYDRO_GRADIENTS_H */
diff --git a/src/hydro/GizmoMFV/hydro_gradients_sph.h b/src/hydro/GizmoMFV/hydro_gradients_sph.h
new file mode 100644
index 0000000000000000000000000000000000000000..7b2b89ae688622ff017e4188f9e8fd2c7cee9d7a
--- /dev/null
+++ b/src/hydro/GizmoMFV/hydro_gradients_sph.h
@@ -0,0 +1,256 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Copyright (c) 2016 Bert Vandenbroucke (bert.vandenbroucke@gmail.com)
+ *
+ * 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/>.
+ *
+ ******************************************************************************/
+
+/**
+ * @brief Initialize gradient variables
+ *
+ * @param p Particle.
+ */
+#ifndef SWIFT_GIZMO_MFV_HYDRO_SPH_GRADIENTS_H
+#define SWIFT_GIZMO_MFV_HYDRO_SPH_GRADIENTS_H
+
+__attribute__((always_inline)) INLINE static void hydro_gradients_init(
+    struct part *p) {
+
+  p->primitives.gradients.rho[0] = 0.0f;
+  p->primitives.gradients.rho[1] = 0.0f;
+  p->primitives.gradients.rho[2] = 0.0f;
+
+  p->primitives.gradients.v[0][0] = 0.0f;
+  p->primitives.gradients.v[0][1] = 0.0f;
+  p->primitives.gradients.v[0][2] = 0.0f;
+
+  p->primitives.gradients.v[1][0] = 0.0f;
+  p->primitives.gradients.v[1][1] = 0.0f;
+  p->primitives.gradients.v[1][2] = 0.0f;
+  p->primitives.gradients.v[2][0] = 0.0f;
+  p->primitives.gradients.v[2][1] = 0.0f;
+  p->primitives.gradients.v[2][2] = 0.0f;
+
+  p->primitives.gradients.P[0] = 0.0f;
+  p->primitives.gradients.P[1] = 0.0f;
+  p->primitives.gradients.P[2] = 0.0f;
+
+  hydro_slope_limit_cell_init(p);
+}
+
+/**
+ * @brief Gradient calculations done during the neighbour loop
+ *
+ * @param r2 Squared distance between the two particles.
+ * @param dx Distance vector (pi->x - pj->x).
+ * @param hi Smoothing length of particle i.
+ * @param hj Smoothing length of particle j.
+ * @param pi Particle i.
+ * @param pj Particle j.
+ */
+__attribute__((always_inline)) INLINE static void hydro_gradients_collect(
+    float r2, const float *dx, float hi, float hj, struct part *restrict pi,
+    struct part *restrict pj) {
+
+  const float r_inv = 1.f / sqrtf(r2);
+  const float r = r2 * r_inv;
+
+  float wi, wi_dx;
+  const float hi_inv = 1.0f / hi;
+  const float xi = r * hi_inv;
+  kernel_deval(xi, &wi, &wi_dx);
+
+  /* very basic gradient estimate */
+  pi->primitives.gradients.rho[0] -=
+      wi_dx * dx[0] * (pi->primitives.rho - pj->primitives.rho) * r_inv;
+  pi->primitives.gradients.rho[1] -=
+      wi_dx * dx[1] * (pi->primitives.rho - pj->primitives.rho) * r_inv;
+  pi->primitives.gradients.rho[2] -=
+      wi_dx * dx[2] * (pi->primitives.rho - pj->primitives.rho) * r_inv;
+
+  pi->primitives.gradients.v[0][0] -=
+      wi_dx * dx[0] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv;
+  pi->primitives.gradients.v[0][1] -=
+      wi_dx * dx[1] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv;
+  pi->primitives.gradients.v[0][2] -=
+      wi_dx * dx[2] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv;
+
+  pi->primitives.gradients.v[1][0] -=
+      wi_dx * dx[0] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv;
+  pi->primitives.gradients.v[1][1] -=
+      wi_dx * dx[1] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv;
+  pi->primitives.gradients.v[1][2] -=
+      wi_dx * dx[2] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv;
+
+  pi->primitives.gradients.v[2][0] -=
+      wi_dx * dx[0] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv;
+  pi->primitives.gradients.v[2][1] -=
+      wi_dx * dx[1] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv;
+  pi->primitives.gradients.v[2][2] -=
+      wi_dx * dx[2] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv;
+
+  pi->primitives.gradients.P[0] -=
+      wi_dx * dx[0] * (pi->primitives.P - pj->primitives.P) * r_inv;
+  pi->primitives.gradients.P[1] -=
+      wi_dx * dx[1] * (pi->primitives.P - pj->primitives.P) * r_inv;
+  pi->primitives.gradients.P[2] -=
+      wi_dx * dx[2] * (pi->primitives.P - pj->primitives.P) * r_inv;
+
+  hydro_slope_limit_cell_collect(pi, pj, r);
+
+  float wj, wj_dx;
+  const float hj_inv = 1.0f / hj;
+  const float xj = r * hj_inv;
+  kernel_deval(xj, &wj, &wj_dx);
+
+  /* signs are the same as before, since we swap i and j twice */
+  pj->primitives.gradients.rho[0] -=
+      wj_dx * dx[0] * (pi->primitives.rho - pj->primitives.rho) * r_inv;
+  pj->primitives.gradients.rho[1] -=
+      wj_dx * dx[1] * (pi->primitives.rho - pj->primitives.rho) * r_inv;
+  pj->primitives.gradients.rho[2] -=
+      wj_dx * dx[2] * (pi->primitives.rho - pj->primitives.rho) * r_inv;
+
+  pj->primitives.gradients.v[0][0] -=
+      wj_dx * dx[0] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv;
+  pj->primitives.gradients.v[0][1] -=
+      wj_dx * dx[1] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv;
+  pj->primitives.gradients.v[0][2] -=
+      wj_dx * dx[2] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv;
+
+  pj->primitives.gradients.v[1][0] -=
+      wj_dx * dx[0] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv;
+  pj->primitives.gradients.v[1][1] -=
+      wj_dx * dx[1] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv;
+  pj->primitives.gradients.v[1][2] -=
+      wj_dx * dx[2] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv;
+  pj->primitives.gradients.v[2][0] -=
+      wj_dx * dx[0] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv;
+  pj->primitives.gradients.v[2][1] -=
+      wj_dx * dx[1] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv;
+  pj->primitives.gradients.v[2][2] -=
+      wj_dx * dx[2] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv;
+
+  pj->primitives.gradients.P[0] -=
+      wj_dx * dx[0] * (pi->primitives.P - pj->primitives.P) * r_inv;
+  pj->primitives.gradients.P[1] -=
+      wj_dx * dx[1] * (pi->primitives.P - pj->primitives.P) * r_inv;
+  pj->primitives.gradients.P[2] -=
+      wj_dx * dx[2] * (pi->primitives.P - pj->primitives.P) * r_inv;
+
+  hydro_slope_limit_cell_collect(pj, pi, r);
+}
+
+/**
+ * @brief Gradient calculations done during the neighbour loop: non-symmetric
+ * version
+ *
+ * @param r2 Squared distance between the two particles.
+ * @param dx Distance vector (pi->x - pj->x).
+ * @param hi Smoothing length of particle i.
+ * @param hj Smoothing length of particle j.
+ * @param pi Particle i.
+ * @param pj Particle j.
+ */
+__attribute__((always_inline)) INLINE static void
+hydro_gradients_nonsym_collect(float r2, const float *dx, float hi, float hj,
+                               struct part *restrict pi,
+                               struct part *restrict pj) {
+
+  const float r_inv = 1.f / sqrtf(r2);
+  const float r = r2 * r_inv;
+
+  float wi, wi_dx;
+  const float hi_inv = 1.0f / hi;
+  const float xi = r * hi_inv;
+  kernel_deval(xi, &wi, &wi_dx);
+
+  /* very basic gradient estimate */
+  pi->primitives.gradients.rho[0] -=
+      wi_dx * dx[0] * (pi->primitives.rho - pj->primitives.rho) * r_inv;
+  pi->primitives.gradients.rho[1] -=
+      wi_dx * dx[1] * (pi->primitives.rho - pj->primitives.rho) * r_inv;
+  pi->primitives.gradients.rho[2] -=
+      wi_dx * dx[2] * (pi->primitives.rho - pj->primitives.rho) * r_inv;
+
+  pi->primitives.gradients.v[0][0] -=
+      wi_dx * dx[0] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv;
+  pi->primitives.gradients.v[0][1] -=
+      wi_dx * dx[1] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv;
+  pi->primitives.gradients.v[0][2] -=
+      wi_dx * dx[2] * (pi->primitives.v[0] - pj->primitives.v[0]) * r_inv;
+
+  pi->primitives.gradients.v[1][0] -=
+      wi_dx * dx[0] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv;
+  pi->primitives.gradients.v[1][1] -=
+      wi_dx * dx[1] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv;
+  pi->primitives.gradients.v[1][2] -=
+      wi_dx * dx[2] * (pi->primitives.v[1] - pj->primitives.v[1]) * r_inv;
+
+  pi->primitives.gradients.v[2][0] -=
+      wi_dx * dx[0] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv;
+  pi->primitives.gradients.v[2][1] -=
+      wi_dx * dx[1] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv;
+  pi->primitives.gradients.v[2][2] -=
+      wi_dx * dx[2] * (pi->primitives.v[2] - pj->primitives.v[2]) * r_inv;
+
+  pi->primitives.gradients.P[0] -=
+      wi_dx * dx[0] * (pi->primitives.P - pj->primitives.P) * r_inv;
+  pi->primitives.gradients.P[1] -=
+      wi_dx * dx[1] * (pi->primitives.P - pj->primitives.P) * r_inv;
+  pi->primitives.gradients.P[2] -=
+      wi_dx * dx[2] * (pi->primitives.P - pj->primitives.P) * r_inv;
+
+  hydro_slope_limit_cell_collect(pi, pj, r);
+}
+
+/**
+ * @brief Finalize the gradient variables after all data have been collected
+ *
+ * @param p Particle.
+ */
+__attribute__((always_inline)) INLINE static void hydro_gradients_finalize(
+    struct part *p) {
+
+  const float h = p->h;
+  const float ih = 1.0f / h;
+  const float ihdimp1 = pow_dimension_plus_one(ih);
+  const float volume = p->geometry.volume;
+
+  /* finalize gradients by multiplying with volume */
+  p->primitives.gradients.rho[0] *= ihdimp1 * volume;
+  p->primitives.gradients.rho[1] *= ihdimp1 * volume;
+  p->primitives.gradients.rho[2] *= ihdimp1 * volume;
+
+  p->primitives.gradients.v[0][0] *= ihdimp1 * volume;
+  p->primitives.gradients.v[0][1] *= ihdimp1 * volume;
+  p->primitives.gradients.v[0][2] *= ihdimp1 * volume;
+
+  p->primitives.gradients.v[1][0] *= ihdimp1 * volume;
+  p->primitives.gradients.v[1][1] *= ihdimp1 * volume;
+  p->primitives.gradients.v[1][2] *= ihdimp1 * volume;
+
+  p->primitives.gradients.v[2][0] *= ihdimp1 * volume;
+  p->primitives.gradients.v[2][1] *= ihdimp1 * volume;
+  p->primitives.gradients.v[2][2] *= ihdimp1 * volume;
+
+  p->primitives.gradients.P[0] *= ihdimp1 * volume;
+  p->primitives.gradients.P[1] *= ihdimp1 * volume;
+  p->primitives.gradients.P[2] *= ihdimp1 * volume;
+
+  hydro_slope_limit_cell(p);
+}
+
+#endif /* SWIFT_GIZMO_MFV_HYDRO_SPH_GRADIENTS_H */
diff --git a/src/hydro/Gizmo/hydro_iact.h b/src/hydro/GizmoMFV/hydro_iact.h
similarity index 99%
rename from src/hydro/Gizmo/hydro_iact.h
rename to src/hydro/GizmoMFV/hydro_iact.h
index 0c888e4159c6da6eb07eb0afbf758efce1c697ee..bb835094acd285b109383c1f5d04a6f5e2d936df 100644
--- a/src/hydro/Gizmo/hydro_iact.h
+++ b/src/hydro/GizmoMFV/hydro_iact.h
@@ -18,8 +18,8 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  *
  ******************************************************************************/
-#ifndef SWIFT_GIZMO_HYDRO_IACT_H
-#define SWIFT_GIZMO_HYDRO_IACT_H
+#ifndef SWIFT_GIZMO_MFV_HYDRO_IACT_H
+#define SWIFT_GIZMO_MFV_HYDRO_IACT_H
 
 #include "adiabatic_index.h"
 #include "hydro_gradients.h"
@@ -514,4 +514,4 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force(
   runner_iact_fluxes_common(r2, dx, hi, hj, pi, pj, 0, a, H);
 }
 
-#endif /* SWIFT_GIZMO_HYDRO_IACT_H */
+#endif /* SWIFT_GIZMO_MFV_HYDRO_IACT_H */
diff --git a/src/hydro/GizmoMFV/hydro_io.h b/src/hydro/GizmoMFV/hydro_io.h
new file mode 100644
index 0000000000000000000000000000000000000000..c1b151230f3198a30d6696e36a2704156804fdce
--- /dev/null
+++ b/src/hydro/GizmoMFV/hydro_io.h
@@ -0,0 +1,244 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Coypright (c) 2016 Bert Vandenbroucke (bert.vandenbroucke@gmail.com)
+ *
+ * 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/>.
+ *
+ ******************************************************************************/
+#ifndef SWIFT_GIZMO_MFV_HYDRO_IO_H
+#define SWIFT_GIZMO_MFV_HYDRO_IO_H
+
+#include "adiabatic_index.h"
+#include "hydro.h"
+#include "hydro_gradients.h"
+#include "hydro_slope_limiters.h"
+#include "io_properties.h"
+#include "riemann.h"
+
+/* Set the description of the particle movement. */
+#if defined(GIZMO_FIX_PARTICLES)
+#define GIZMO_PARTICLE_MOVEMENT "Fixed particles."
+#else
+#define GIZMO_PARTICLE_MOVEMENT "Particles move with flow velocity."
+#endif
+
+/**
+ * @brief Specifies which particle fields to read from a dataset
+ *
+ * @param parts The particle array.
+ * @param list The list of i/o properties to read.
+ * @param num_fields The number of i/o fields to read.
+ */
+void hydro_read_particles(struct part* parts, struct io_props* list,
+                          int* num_fields) {
+
+  *num_fields = 8;
+
+  /* List what we want to read */
+  list[0] = io_make_input_field("Coordinates", DOUBLE, 3, COMPULSORY,
+                                UNIT_CONV_LENGTH, parts, x);
+  list[1] = io_make_input_field("Velocities", FLOAT, 3, COMPULSORY,
+                                UNIT_CONV_SPEED, parts, v);
+  list[2] = io_make_input_field("Masses", FLOAT, 1, COMPULSORY, UNIT_CONV_MASS,
+                                parts, conserved.mass);
+  list[3] = io_make_input_field("SmoothingLength", FLOAT, 1, COMPULSORY,
+                                UNIT_CONV_LENGTH, parts, h);
+  list[4] = io_make_input_field("InternalEnergy", FLOAT, 1, COMPULSORY,
+                                UNIT_CONV_ENERGY_PER_UNIT_MASS, parts,
+                                conserved.energy);
+  list[5] = io_make_input_field("ParticleIDs", ULONGLONG, 1, COMPULSORY,
+                                UNIT_CONV_NO_UNITS, parts, id);
+  list[6] = io_make_input_field("Accelerations", FLOAT, 3, OPTIONAL,
+                                UNIT_CONV_ACCELERATION, parts, a_hydro);
+  list[7] = io_make_input_field("Density", FLOAT, 1, OPTIONAL,
+                                UNIT_CONV_DENSITY, parts, primitives.rho);
+}
+
+/**
+ * @brief Get the internal energy of a particle
+ *
+ * @param e #engine.
+ * @param p Particle.
+ * @param ret (return) Internal energy of the particle
+ */
+void convert_u(const struct engine* e, const struct part* p,
+               const struct xpart* xp, float* ret) {
+
+  ret[0] = hydro_get_comoving_internal_energy(p);
+}
+
+/**
+ * @brief Get the entropic function of a particle
+ *
+ * @param e #engine.
+ * @param p Particle.
+ * @param ret (return) Entropic function of the particle
+ */
+void convert_A(const struct engine* e, const struct part* p,
+               const struct xpart* xp, float* ret) {
+  ret[0] = hydro_get_comoving_entropy(p);
+}
+
+/**
+ * @brief Get the total energy of a particle
+ *
+ * @param e #engine.
+ * @param p Particle.
+ * @return Total energy of the particle
+ */
+void convert_Etot(const struct engine* e, const struct part* p,
+                  const struct xpart* xp, float* ret) {
+#ifdef GIZMO_TOTAL_ENERGY
+  ret[0] = p->conserved.energy;
+#else
+  float momentum2;
+
+  momentum2 = p->conserved.momentum[0] * p->conserved.momentum[0] +
+              p->conserved.momentum[1] * p->conserved.momentum[1] +
+              p->conserved.momentum[2] * p->conserved.momentum[2];
+
+  ret[0] = p->conserved.energy + 0.5f * momentum2 / p->conserved.mass;
+#endif
+}
+
+void convert_part_pos(const struct engine* e, const struct part* p,
+                      const struct xpart* xp, double* ret) {
+
+  if (e->s->periodic) {
+    ret[0] = box_wrap(p->x[0], 0.0, e->s->dim[0]);
+    ret[1] = box_wrap(p->x[1], 0.0, e->s->dim[1]);
+    ret[2] = box_wrap(p->x[2], 0.0, e->s->dim[2]);
+  } else {
+    ret[0] = p->x[0];
+    ret[1] = p->x[1];
+    ret[2] = p->x[2];
+  }
+}
+
+void convert_part_vel(const struct engine* e, const struct part* p,
+                      const struct xpart* xp, float* ret) {
+
+  const int with_cosmology = (e->policy & engine_policy_cosmology);
+  const struct cosmology* cosmo = e->cosmology;
+  const integertime_t ti_current = e->ti_current;
+  const double time_base = e->time_base;
+
+  const integertime_t ti_beg = get_integer_time_begin(ti_current, p->time_bin);
+  const integertime_t ti_end = get_integer_time_end(ti_current, p->time_bin);
+
+  /* Get time-step since the last kick */
+  float dt_kick_grav, dt_kick_hydro;
+  if (with_cosmology) {
+    dt_kick_grav = cosmology_get_grav_kick_factor(cosmo, ti_beg, ti_current);
+    dt_kick_grav -=
+        cosmology_get_grav_kick_factor(cosmo, ti_beg, (ti_beg + ti_end) / 2);
+    dt_kick_hydro = cosmology_get_hydro_kick_factor(cosmo, ti_beg, ti_current);
+    dt_kick_hydro -=
+        cosmology_get_hydro_kick_factor(cosmo, ti_beg, (ti_beg + ti_end) / 2);
+  } else {
+    dt_kick_grav = (ti_current - ((ti_beg + ti_end) / 2)) * time_base;
+    dt_kick_hydro = (ti_current - ((ti_beg + ti_end) / 2)) * time_base;
+  }
+
+  /* Extrapolate the velocites to the current time */
+  hydro_get_drifted_velocities(p, xp, dt_kick_hydro, dt_kick_grav, ret);
+
+  /* Conversion from internal units to peculiar velocities */
+  ret[0] *= cosmo->a2_inv;
+  ret[1] *= cosmo->a2_inv;
+  ret[2] *= cosmo->a2_inv;
+}
+
+void convert_part_potential(const struct engine* e, const struct part* p,
+                            const struct xpart* xp, float* ret) {
+
+  if (p->gpart != NULL)
+    ret[0] = gravity_get_comoving_potential(p->gpart);
+  else
+    ret[0] = 0.f;
+}
+
+/**
+ * @brief Specifies which particle fields to write to a dataset
+ *
+ * @param parts The particle array.
+ * @param list The list of i/o properties to write.
+ * @param num_fields The number of i/o fields to write.
+ */
+void hydro_write_particles(const struct part* parts, const struct xpart* xparts,
+                           struct io_props* list, int* num_fields) {
+
+  *num_fields = 11;
+
+  /* List what we want to write */
+  list[0] = io_make_output_field_convert_part("Coordinates", DOUBLE, 3,
+                                              UNIT_CONV_LENGTH, parts, xparts,
+                                              convert_part_pos);
+  list[1] = io_make_output_field_convert_part(
+      "Velocities", FLOAT, 3, UNIT_CONV_SPEED, parts, xparts, convert_part_vel);
+
+  list[2] = io_make_output_field("Masses", FLOAT, 1, UNIT_CONV_MASS, parts,
+                                 conserved.mass);
+  list[3] = io_make_output_field("SmoothingLength", FLOAT, 1, UNIT_CONV_LENGTH,
+                                 parts, h);
+  list[4] = io_make_output_field_convert_part("InternalEnergy", FLOAT, 1,
+                                              UNIT_CONV_ENERGY_PER_UNIT_MASS,
+                                              parts, xparts, convert_u);
+  list[5] = io_make_output_field("ParticleIDs", ULONGLONG, 1,
+                                 UNIT_CONV_NO_UNITS, parts, id);
+  list[6] = io_make_output_field("Density", FLOAT, 1, UNIT_CONV_DENSITY, parts,
+                                 primitives.rho);
+  list[7] = io_make_output_field_convert_part(
+      "Entropy", FLOAT, 1, UNIT_CONV_ENTROPY, parts, xparts, convert_A);
+  list[8] = io_make_output_field("Pressure", FLOAT, 1, UNIT_CONV_PRESSURE,
+                                 parts, primitives.P);
+  list[9] = io_make_output_field_convert_part(
+      "TotEnergy", FLOAT, 1, UNIT_CONV_ENERGY, parts, xparts, convert_Etot);
+
+  list[10] = io_make_output_field_convert_part("Potential", FLOAT, 1,
+                                               UNIT_CONV_POTENTIAL, parts,
+                                               xparts, convert_part_potential);
+}
+
+/**
+ * @brief Writes the current model of SPH to the file
+ * @param h_grpsph The HDF5 group in which to write
+ */
+void hydro_write_flavour(hid_t h_grpsph) {
+  /* Gradient information */
+  io_write_attribute_s(h_grpsph, "Gradient reconstruction model",
+                       HYDRO_GRADIENT_IMPLEMENTATION);
+
+  /* Slope limiter information */
+  io_write_attribute_s(h_grpsph, "Cell wide slope limiter model",
+                       HYDRO_SLOPE_LIMITER_CELL_IMPLEMENTATION);
+  io_write_attribute_s(h_grpsph, "Piecewise slope limiter model",
+                       HYDRO_SLOPE_LIMITER_FACE_IMPLEMENTATION);
+
+  /* Riemann solver information */
+  io_write_attribute_s(h_grpsph, "Riemann solver type",
+                       RIEMANN_SOLVER_IMPLEMENTATION);
+
+  /* Particle movement information */
+  io_write_attribute_s(h_grpsph, "Particle movement", GIZMO_PARTICLE_MOVEMENT);
+}
+
+/**
+ * @brief Are we writing entropy in the internal energy field ?
+ *
+ * @return 1 if entropy is in 'internal energy', 0 otherwise.
+ */
+int writeEntropyFlag() { return 0; }
+
+#endif /* SWIFT_GIZMO_MFV_HYDRO_IO_H */
diff --git a/src/hydro/GizmoMFV/hydro_part.h b/src/hydro/GizmoMFV/hydro_part.h
new file mode 100644
index 0000000000000000000000000000000000000000..6248ddb11daf39a65be9a57fe51e40386ecda50b
--- /dev/null
+++ b/src/hydro/GizmoMFV/hydro_part.h
@@ -0,0 +1,213 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Coypright (c) 2014 Bert Vandenbroucke (bert.vandenbroucke@ugent.be)
+ *
+ * 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/>.
+ *
+ ******************************************************************************/
+#ifndef SWIFT_GIZMO_MFV_HYDRO_PART_H
+#define SWIFT_GIZMO_MFV_HYDRO_PART_H
+
+#include "chemistry_struct.h"
+#include "cooling_struct.h"
+
+/* Extra particle data not needed during the computation. */
+struct xpart {
+
+  /* Offset between current position and position at last tree rebuild. */
+  float x_diff[3];
+
+  /* Offset between the current position and position at the last sort. */
+  float x_diff_sort[3];
+
+  /* Velocity at the last full step. */
+  float v_full[3];
+
+  /* Gravitational acceleration at the last full step. */
+  float a_grav[3];
+
+  /* Additional data used to record cooling information */
+  struct cooling_xpart_data cooling_data;
+
+} SWIFT_STRUCT_ALIGN;
+
+/* Data of a single particle. */
+struct part {
+
+  /* Particle ID. */
+  long long id;
+
+  /* Associated gravitas. */
+  struct gpart *gpart;
+
+  /* Particle position. */
+  double x[3];
+
+  /* Particle predicted velocity. */
+  float v[3];
+
+  /* Particle acceleration. */
+  float a_hydro[3];
+
+  /* Particle smoothing length. */
+  float h;
+
+  /* The primitive hydrodynamical variables. */
+  struct {
+
+    /* Density. */
+    float rho;
+
+    /* Fluid velocity. */
+    float v[3];
+
+    /* Pressure. */
+    float P;
+
+    /* Gradients of the primitive variables. */
+    struct {
+
+      /* Density gradients. */
+      float rho[3];
+
+      /* Fluid velocity gradients. */
+      float v[3][3];
+
+      /* Pressure gradients. */
+      float P[3];
+
+    } gradients;
+
+    /* Quantities needed by the slope limiter. */
+    struct {
+
+      /* Extreme values of the density among the neighbours. */
+      float rho[2];
+
+      /* Extreme values of the fluid velocity among the neighbours. */
+      float v[3][2];
+
+      /* Extreme values of the pressure among the neighbours. */
+      float P[2];
+
+      /* Maximal distance to all neighbouring faces. */
+      float maxr;
+
+    } limiter;
+
+  } primitives;
+
+  /* The conserved hydrodynamical variables. */
+  struct {
+
+    /* Fluid mass */
+    float mass;
+
+    /* Fluid momentum. */
+    float momentum[3];
+
+    /* Fluid thermal energy (not per unit mass!). */
+    float energy;
+
+    /* Fluxes. */
+    struct {
+
+      /* Mass flux. */
+      float mass;
+
+      /* Momentum flux. */
+      float momentum[3];
+
+      /* Energy flux. */
+      float energy;
+
+    } flux;
+
+  } conserved;
+
+  /* Geometrical quantities used for hydro. */
+  struct {
+
+    /* Volume of the particle. */
+    float volume;
+
+    /* Geometrical shear matrix used to calculate second order accurate
+       gradients */
+    float matrix_E[3][3];
+
+    /* Centroid of the "cell". */
+    float centroid[3];
+
+  } geometry;
+
+  /* Variables used for timestep calculation. */
+  struct {
+
+    /* Maximum signal velocity among all the neighbours of the particle. The
+     * signal velocity encodes information about the relative fluid velocities
+     * AND particle velocities of the neighbour and this particle, as well as
+     * the sound speed of both particles. */
+    float vmax;
+
+  } timestepvars;
+
+  /* Quantities used during the volume (=density) loop. */
+  struct {
+
+    /* Derivative of particle number density. */
+    float wcount_dh;
+
+    /* Particle number density. */
+    float wcount;
+
+    /* Correction factor for wcount. */
+    float wcorr;
+
+  } density;
+
+  /* Quantities used during the force loop. */
+  struct {
+
+    /* Needed to drift the primitive variables. */
+    float h_dt;
+
+  } force;
+
+  /* Specific stuff for the gravity-hydro coupling. */
+  struct {
+
+    /* Current value of the mass flux vector. */
+    float mflux[3];
+
+  } gravity;
+
+  /* Chemistry information */
+  struct chemistry_part_data chemistry_data;
+
+  /* Time-step length */
+  timebin_t time_bin;
+
+#ifdef SWIFT_DEBUG_CHECKS
+
+  /* Time of the last drift */
+  integertime_t ti_drift;
+
+  /* Time of the last kick */
+  integertime_t ti_kick;
+
+#endif
+
+} SWIFT_STRUCT_ALIGN;
+
+#endif /* SWIFT_GIZMO_MFV_HYDRO_PART_H */
diff --git a/src/hydro/GizmoMFV/hydro_slope_limiters.h b/src/hydro/GizmoMFV/hydro_slope_limiters.h
new file mode 100644
index 0000000000000000000000000000000000000000..78f2785cdae5dc2334d37e3924dd5b259cca8c05
--- /dev/null
+++ b/src/hydro/GizmoMFV/hydro_slope_limiters.h
@@ -0,0 +1,94 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Copyright (c) 2016 Bert Vandenbroucke (bert.vandenbroucke@gmail.com)
+ *
+ * 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/>.
+ *
+ ******************************************************************************/
+
+#ifndef SWIFT_HYDRO_SLOPE_LIMITERS_H
+#define SWIFT_HYDRO_SLOPE_LIMITERS_H
+
+#include "dimension.h"
+#include "kernel_hydro.h"
+
+#ifdef SLOPE_LIMITER_PER_FACE
+
+#define HYDRO_SLOPE_LIMITER_FACE_IMPLEMENTATION \
+  "GIZMO piecewise slope limiter (Hopkins 2015)"
+#include "hydro_slope_limiters_face.h"
+
+#else
+
+#define HYDRO_SLOPE_LIMITER_FACE_IMPLEMENTATION "No piecewise slope limiter"
+
+/**
+ * @brief Slope limit the slopes at the interface between two particles
+ *
+ * @param Wi Hydrodynamic variables of particle i.
+ * @param Wj Hydrodynamic variables of particle j.
+ * @param dWi Difference between the hydrodynamic variables of particle i at the
+ * position of particle i and at the interface position.
+ * @param dWj Difference between the hydrodynamic variables of particle j at the
+ * position of particle j and at the interface position.
+ * @param xij_i Relative position vector of the interface w.r.t. particle i.
+ * @param xij_j Relative position vector of the interface w.r.t. partilce j.
+ * @param r Distance between particle i and particle j.
+ */
+__attribute__((always_inline)) INLINE static void hydro_slope_limit_face(
+    float *Wi, float *Wj, float *dWi, float *dWj, float *xij_i, float *xij_j,
+    float r) {}
+
+#endif
+
+#ifdef SLOPE_LIMITER_CELL_WIDE
+
+#define HYDRO_SLOPE_LIMITER_CELL_IMPLEMENTATION \
+  "Cell wide slope limiter (Springel 2010)"
+#include "hydro_slope_limiters_cell.h"
+
+#else
+
+#define HYDRO_SLOPE_LIMITER_CELL_IMPLEMENTATION "No cell wide slope limiter"
+
+/**
+ * @brief Initialize variables for the cell wide slope limiter
+ *
+ * @param p Particle.
+ */
+__attribute__((always_inline)) INLINE static void hydro_slope_limit_cell_init(
+    struct part *p) {}
+
+/**
+ * @brief Collect information for the cell wide slope limiter during the
+ * neighbour loop
+ *
+ * @param pi Particle i.
+ * @param pj Particle j.
+ * @param r Distance between particle i and particle j.
+ */
+__attribute__((always_inline)) INLINE static void
+hydro_slope_limit_cell_collect(struct part *pi, struct part *pj, float r) {}
+
+/**
+ * @brief Slope limit cell gradients
+ *
+ * @param p Particle.
+ */
+__attribute__((always_inline)) INLINE static void hydro_slope_limit_cell(
+    struct part *p) {}
+
+#endif
+
+#endif /* SWIFT_HYDRO_SLOPE_LIMITERS_H */
diff --git a/src/hydro/GizmoMFV/hydro_slope_limiters_cell.h b/src/hydro/GizmoMFV/hydro_slope_limiters_cell.h
new file mode 100644
index 0000000000000000000000000000000000000000..130a87def95a3198f0871ce485f0a9d377a96cd5
--- /dev/null
+++ b/src/hydro/GizmoMFV/hydro_slope_limiters_cell.h
@@ -0,0 +1,186 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Copyright (c) 2016 Bert Vandenbroucke (bert.vandenbroucke@gmail.com)
+ *
+ * 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/>.
+ *
+ ******************************************************************************/
+#ifndef SWIFT_GIZMO_MFV_SLOPE_LIMITER_CELL_H
+#define SWIFT_GIZMO_MFV_SLOPE_LIMITER_CELL_H
+
+#include <float.h>
+
+/**
+ * @brief Initialize variables for the cell wide slope limiter
+ *
+ * @param p Particle.
+ */
+__attribute__((always_inline)) INLINE static void hydro_slope_limit_cell_init(
+    struct part* p) {
+
+  p->primitives.limiter.rho[0] = FLT_MAX;
+  p->primitives.limiter.rho[1] = -FLT_MAX;
+  p->primitives.limiter.v[0][0] = FLT_MAX;
+  p->primitives.limiter.v[0][1] = -FLT_MAX;
+  p->primitives.limiter.v[1][0] = FLT_MAX;
+  p->primitives.limiter.v[1][1] = -FLT_MAX;
+  p->primitives.limiter.v[2][0] = FLT_MAX;
+  p->primitives.limiter.v[2][1] = -FLT_MAX;
+  p->primitives.limiter.P[0] = FLT_MAX;
+  p->primitives.limiter.P[1] = -FLT_MAX;
+
+  p->primitives.limiter.maxr = -FLT_MAX;
+}
+
+/**
+ * @brief Collect information for the cell wide slope limiter during the
+ * neighbour loop
+ *
+ * @param pi Particle i.
+ * @param pj Particle j.
+ * @param r Distance between particle i and particle j.
+ */
+__attribute__((always_inline)) INLINE static void
+hydro_slope_limit_cell_collect(struct part* pi, struct part* pj, float r) {
+
+  /* basic slope limiter: collect the maximal and the minimal value for the
+   * primitive variables among the ngbs */
+  pi->primitives.limiter.rho[0] =
+      min(pj->primitives.rho, pi->primitives.limiter.rho[0]);
+  pi->primitives.limiter.rho[1] =
+      max(pj->primitives.rho, pi->primitives.limiter.rho[1]);
+
+  pi->primitives.limiter.v[0][0] =
+      min(pj->primitives.v[0], pi->primitives.limiter.v[0][0]);
+  pi->primitives.limiter.v[0][1] =
+      max(pj->primitives.v[0], pi->primitives.limiter.v[0][1]);
+  pi->primitives.limiter.v[1][0] =
+      min(pj->primitives.v[1], pi->primitives.limiter.v[1][0]);
+  pi->primitives.limiter.v[1][1] =
+      max(pj->primitives.v[1], pi->primitives.limiter.v[1][1]);
+  pi->primitives.limiter.v[2][0] =
+      min(pj->primitives.v[2], pi->primitives.limiter.v[2][0]);
+  pi->primitives.limiter.v[2][1] =
+      max(pj->primitives.v[2], pi->primitives.limiter.v[2][1]);
+
+  pi->primitives.limiter.P[0] =
+      min(pj->primitives.P, pi->primitives.limiter.P[0]);
+  pi->primitives.limiter.P[1] =
+      max(pj->primitives.P, pi->primitives.limiter.P[1]);
+
+  pi->primitives.limiter.maxr = max(r, pi->primitives.limiter.maxr);
+}
+
+/**
+ * @brief Slope limit cell gradients
+ *
+ * @param p Particle.
+ */
+__attribute__((always_inline)) INLINE static void hydro_slope_limit_cell(
+    struct part* p) {
+
+  float gradtrue, gradrho[3], gradv[3][3], gradP[3];
+
+  gradrho[0] = p->primitives.gradients.rho[0];
+  gradrho[1] = p->primitives.gradients.rho[1];
+  gradrho[2] = p->primitives.gradients.rho[2];
+
+  gradv[0][0] = p->primitives.gradients.v[0][0];
+  gradv[0][1] = p->primitives.gradients.v[0][1];
+  gradv[0][2] = p->primitives.gradients.v[0][2];
+
+  gradv[1][0] = p->primitives.gradients.v[1][0];
+  gradv[1][1] = p->primitives.gradients.v[1][1];
+  gradv[1][2] = p->primitives.gradients.v[1][2];
+
+  gradv[2][0] = p->primitives.gradients.v[2][0];
+  gradv[2][1] = p->primitives.gradients.v[2][1];
+  gradv[2][2] = p->primitives.gradients.v[2][2];
+
+  gradP[0] = p->primitives.gradients.P[0];
+  gradP[1] = p->primitives.gradients.P[1];
+  gradP[2] = p->primitives.gradients.P[2];
+
+  gradtrue = sqrtf(gradrho[0] * gradrho[0] + gradrho[1] * gradrho[1] +
+                   gradrho[2] * gradrho[2]);
+  if (gradtrue) {
+    gradtrue *= p->primitives.limiter.maxr;
+    const float gradmax = p->primitives.limiter.rho[1] - p->primitives.rho;
+    const float gradmin = p->primitives.rho - p->primitives.limiter.rho[0];
+    const float gradtrue_inv = 1.f / gradtrue;
+    const float alpha =
+        min3(1.0f, gradmax * gradtrue_inv, gradmin * gradtrue_inv);
+    p->primitives.gradients.rho[0] *= alpha;
+    p->primitives.gradients.rho[1] *= alpha;
+    p->primitives.gradients.rho[2] *= alpha;
+  }
+
+  gradtrue = sqrtf(gradv[0][0] * gradv[0][0] + gradv[0][1] * gradv[0][1] +
+                   gradv[0][2] * gradv[0][2]);
+  if (gradtrue) {
+    gradtrue *= p->primitives.limiter.maxr;
+    const float gradmax = p->primitives.limiter.v[0][1] - p->primitives.v[0];
+    const float gradmin = p->primitives.v[0] - p->primitives.limiter.v[0][0];
+    const float gradtrue_inv = 1.f / gradtrue;
+    const float alpha =
+        min3(1.0f, gradmax * gradtrue_inv, gradmin * gradtrue_inv);
+    p->primitives.gradients.v[0][0] *= alpha;
+    p->primitives.gradients.v[0][1] *= alpha;
+    p->primitives.gradients.v[0][2] *= alpha;
+  }
+
+  gradtrue = sqrtf(gradv[1][0] * gradv[1][0] + gradv[1][1] * gradv[1][1] +
+                   gradv[1][2] * gradv[1][2]);
+  if (gradtrue) {
+    gradtrue *= p->primitives.limiter.maxr;
+    const float gradmax = p->primitives.limiter.v[1][1] - p->primitives.v[1];
+    const float gradmin = p->primitives.v[1] - p->primitives.limiter.v[1][0];
+    const float gradtrue_inv = 1.f / gradtrue;
+    const float alpha =
+        min3(1.0f, gradmax * gradtrue_inv, gradmin * gradtrue_inv);
+    p->primitives.gradients.v[1][0] *= alpha;
+    p->primitives.gradients.v[1][1] *= alpha;
+    p->primitives.gradients.v[1][2] *= alpha;
+  }
+
+  gradtrue = sqrtf(gradv[2][0] * gradv[2][0] + gradv[2][1] * gradv[2][1] +
+                   gradv[2][2] * gradv[2][2]);
+  if (gradtrue) {
+    gradtrue *= p->primitives.limiter.maxr;
+    const float gradmax = p->primitives.limiter.v[2][1] - p->primitives.v[2];
+    const float gradmin = p->primitives.v[2] - p->primitives.limiter.v[2][0];
+    const float gradtrue_inv = 1.f / gradtrue;
+    const float alpha =
+        min3(1.0f, gradmax * gradtrue_inv, gradmin * gradtrue_inv);
+    p->primitives.gradients.v[2][0] *= alpha;
+    p->primitives.gradients.v[2][1] *= alpha;
+    p->primitives.gradients.v[2][2] *= alpha;
+  }
+
+  gradtrue =
+      sqrtf(gradP[0] * gradP[0] + gradP[1] * gradP[1] + gradP[2] * gradP[2]);
+  if (gradtrue) {
+    gradtrue *= p->primitives.limiter.maxr;
+    const float gradmax = p->primitives.limiter.P[1] - p->primitives.P;
+    const float gradmin = p->primitives.P - p->primitives.limiter.P[0];
+    const float gradtrue_inv = 1.f / gradtrue;
+    const float alpha =
+        min3(1.0f, gradmax * gradtrue_inv, gradmin * gradtrue_inv);
+    p->primitives.gradients.P[0] *= alpha;
+    p->primitives.gradients.P[1] *= alpha;
+    p->primitives.gradients.P[2] *= alpha;
+  }
+}
+
+#endif /* SWIFT_GIZMO_MFV_SLOPE_LIMITER_CELL_H */
diff --git a/src/hydro/GizmoMFV/hydro_slope_limiters_face.h b/src/hydro/GizmoMFV/hydro_slope_limiters_face.h
new file mode 100644
index 0000000000000000000000000000000000000000..b12f15590f51c16f494978d9501401709b2cbf59
--- /dev/null
+++ b/src/hydro/GizmoMFV/hydro_slope_limiters_face.h
@@ -0,0 +1,128 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Copyright (c) 2016 Bert Vandenbroucke (bert.vandenbroucke@gmail.com)
+ *
+ * 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/>.
+ *
+ ******************************************************************************/
+
+/**
+ * @brief Slope limit a single quantity at the interface
+ *
+ * @param phi_i Value of the quantity at the particle position.
+ * @param phi_j Value of the quantity at the neighbouring particle position.
+ * @param phi_mid0 Extrapolated value of the quantity at the interface position.
+ * @param xij_norm Distance between the particle position and the interface
+ * position.
+ * @param r Distance between the particle and its neighbour.
+ * @return The slope limited difference between the quantity at the particle
+ * position and the quantity at the interface position.
+ */
+#ifndef SWIFT_GIZMO_MFV_SLOPE_LIMITER_FACE_H
+#define SWIFT_GIZMO_MFV_SLOPE_LIMITER_FACE_H
+
+/* Some standard headers. */
+#include <float.h>
+
+/* Local headers. */
+#include "minmax.h"
+#include "sign.h"
+
+__attribute__((always_inline)) INLINE static float
+hydro_slope_limit_face_quantity(float phi_i, float phi_j, float phi_mid0,
+                                float xij_norm, float r_inv) {
+
+  const float psi1 = 0.5f;
+  const float psi2 = 0.25f;
+
+  const float delta1 = psi1 * fabsf(phi_i - phi_j);
+  const float delta2 = psi2 * fabsf(phi_i - phi_j);
+
+  const float phimin = min(phi_i, phi_j);
+  const float phimax = max(phi_i, phi_j);
+
+  const float phibar = phi_i + xij_norm * r_inv * (phi_j - phi_i);
+
+  float phiplus, phiminus, phi_mid;
+
+  if (same_signf(phimax + delta1, phimax))
+    phiplus = phimax + delta1;
+  else
+    phiplus = phimax / (1.0f + delta1 / (fabsf(phimax) + FLT_MIN));
+
+  if (same_signf(phimin - delta1, phimin))
+    phiminus = phimin - delta1;
+  else
+    phiminus = phimin / (1.0f + delta1 / (fabsf(phimin) + FLT_MIN));
+
+  if (phi_i < phi_j) {
+    const float temp = min(phibar + delta2, phi_mid0);
+    phi_mid = max(phiminus, temp);
+  } else {
+    const float temp = max(phibar - delta2, phi_mid0);
+    phi_mid = min(phiplus, temp);
+  }
+
+  return phi_mid - phi_i;
+}
+
+/**
+ * @brief Slope limit the slopes at the interface between two particles
+ *
+ * @param Wi Hydrodynamic variables of particle i.
+ * @param Wj Hydrodynamic variables of particle j.
+ * @param dWi Difference between the hydrodynamic variables of particle i at the
+ * position of particle i and at the interface position.
+ * @param dWj Difference between the hydrodynamic variables of particle j at the
+ * position of particle j and at the interface position.
+ * @param xij_i Relative position vector of the interface w.r.t. particle i.
+ * @param xij_j Relative position vector of the interface w.r.t. partilce j.
+ * @param r Distance between particle i and particle j.
+ */
+__attribute__((always_inline)) INLINE static void hydro_slope_limit_face(
+    float *Wi, float *Wj, float *dWi, float *dWj, const float *xij_i,
+    const float *xij_j, float r) {
+
+  const float xij_i_norm =
+      sqrtf(xij_i[0] * xij_i[0] + xij_i[1] * xij_i[1] + xij_i[2] * xij_i[2]);
+
+  const float xij_j_norm =
+      sqrtf(xij_j[0] * xij_j[0] + xij_j[1] * xij_j[1] + xij_j[2] * xij_j[2]);
+
+  const float r_inv = 1.f / r;
+
+  dWi[0] = hydro_slope_limit_face_quantity(Wi[0], Wj[0], Wi[0] + dWi[0],
+                                           xij_i_norm, r_inv);
+  dWi[1] = hydro_slope_limit_face_quantity(Wi[1], Wj[1], Wi[1] + dWi[1],
+                                           xij_i_norm, r_inv);
+  dWi[2] = hydro_slope_limit_face_quantity(Wi[2], Wj[2], Wi[2] + dWi[2],
+                                           xij_i_norm, r_inv);
+  dWi[3] = hydro_slope_limit_face_quantity(Wi[3], Wj[3], Wi[3] + dWi[3],
+                                           xij_i_norm, r_inv);
+  dWi[4] = hydro_slope_limit_face_quantity(Wi[4], Wj[4], Wi[4] + dWi[4],
+                                           xij_i_norm, r_inv);
+
+  dWj[0] = hydro_slope_limit_face_quantity(Wj[0], Wi[0], Wj[0] + dWj[0],
+                                           xij_j_norm, r_inv);
+  dWj[1] = hydro_slope_limit_face_quantity(Wj[1], Wi[1], Wj[1] + dWj[1],
+                                           xij_j_norm, r_inv);
+  dWj[2] = hydro_slope_limit_face_quantity(Wj[2], Wi[2], Wj[2] + dWj[2],
+                                           xij_j_norm, r_inv);
+  dWj[3] = hydro_slope_limit_face_quantity(Wj[3], Wi[3], Wj[3] + dWj[3],
+                                           xij_j_norm, r_inv);
+  dWj[4] = hydro_slope_limit_face_quantity(Wj[4], Wi[4], Wj[4] + dWj[4],
+                                           xij_j_norm, r_inv);
+}
+
+#endif /* SWIFT_GIZMO_MFV_SLOPE_LIMITER_FACE_H */
diff --git a/src/hydro/GizmoMFV/hydro_unphysical.h b/src/hydro/GizmoMFV/hydro_unphysical.h
new file mode 100644
index 0000000000000000000000000000000000000000..81c644e6cce00e0d871aafc39140e420e042a926
--- /dev/null
+++ b/src/hydro/GizmoMFV/hydro_unphysical.h
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Copyright (c) 2017 Bert Vandenbroucke (bert.vandenbroucke@gmail.com)
+ *
+ * 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/>.
+ *
+ ******************************************************************************/
+#ifndef SWIFT_HYDRO_UNPHYSICAL_H
+#define SWIFT_HYDRO_UNPHYSICAL_H
+
+#if defined(GIZMO_UNPHYSICAL_ERROR) || defined(GIZMO_UNPHYSICAL_RESCUE)
+
+#if defined(GIZMO_UNPHYSICAL_ERROR)
+
+/*! @brief Crash whenever an unphysical value is detected. */
+#define gizmo_unphysical_message(name, quantity) \
+  error("Unphysical " name " detected (%g)!", quantity);
+
+#elif defined(GIZMO_UNPHYSICAL_WARNING)
+
+/*! @brief Show a warning whenever an unphysical value is detected. */
+#define gizmo_unphysical_message(name, quantity) \
+  message("Unphysical " name " detected (%g), reset to 0!", quantity);
+
+#else
+
+/*! @brief Don't tell anyone an unphysical value was detected. */
+#define gizmo_unphysical_message(name, quantity)
+
+#endif
+
+#define gizmo_check_physical_quantity(name, quantity) \
+  if (quantity < 0.f) {                               \
+    gizmo_unphysical_message(name, quantity);         \
+    quantity = 0.f;                                   \
+  }
+
+#define gizmo_check_physical_quantities(                                      \
+    mass_name, energy_name, mass, momentum_x, momentum_y, momentum_z, energy) \
+  gizmo_check_physical_quantity(mass_name, mass);                             \
+  gizmo_check_physical_quantity(energy_name, energy);                         \
+  /* now check for vacuum and make sure we have a real vacuum */              \
+  if (mass == 0.f || energy == 0.f) {                                         \
+    mass = 0.f;                                                               \
+    momentum_x = 0.f;                                                         \
+    momentum_y = 0.f;                                                         \
+    momentum_z = 0.f;                                                         \
+    energy = 0.f;                                                             \
+  }
+
+#else  // defined(GIZMO_UNPHYSICAL_ERROR) || defined(GIZMO_UNPHYSICAL_RESCUE)
+
+#define gizmo_check_physical_quantities( \
+    mass_name, energy_name, mass, momentum_x, momentum_y, momentum_z, energy)
+
+#endif  // defined(GIZMO_UNPHYSICAL_ERROR) || defined(GIZMO_UNPHYSICAL_RESCUE)
+
+#endif /* SWIFT_HYDRO_UNPHYSICAL_H */
diff --git a/src/hydro/GizmoMFV/hydro_velocities.h b/src/hydro/GizmoMFV/hydro_velocities.h
new file mode 100644
index 0000000000000000000000000000000000000000..ea30d5a6c9c74d34ffd73fa6ab941640f37b02e4
--- /dev/null
+++ b/src/hydro/GizmoMFV/hydro_velocities.h
@@ -0,0 +1,157 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Coypright (c) 2017 Bert Vandenbroucke (bert.vandenbroucke@gmail.com)
+ *
+ * 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/>.
+ *
+ ******************************************************************************/
+#ifndef SWIFT_HYDRO_VELOCITIES_H
+#define SWIFT_HYDRO_VELOCITIES_H
+
+/**
+ * @brief Initialize the GIZMO particle velocities before the start of the
+ * actual run based on the initial value of the primitive velocity.
+ *
+ * @param p The particle to act upon.
+ * @param xp The extended particle data to act upon.
+ */
+__attribute__((always_inline)) INLINE static void hydro_velocities_init(
+    struct part* restrict p, struct xpart* restrict xp) {
+
+#ifdef GIZMO_FIX_PARTICLES
+  p->v[0] = 0.f;
+  p->v[1] = 0.f;
+  p->v[2] = 0.f;
+#else
+  p->v[0] = p->primitives.v[0];
+  p->v[1] = p->primitives.v[1];
+  p->v[2] = p->primitives.v[2];
+#endif
+
+  xp->v_full[0] = p->v[0];
+  xp->v_full[1] = p->v[1];
+  xp->v_full[2] = p->v[2];
+}
+
+/**
+ * @brief Set the particle velocity field that will be used to deboost fluid
+ * velocities during the force loop.
+ *
+ * @param p The particle to act upon.
+ * @param xp The extended particle data to act upon.
+ */
+__attribute__((always_inline)) INLINE static void
+hydro_velocities_prepare_force(struct part* restrict p,
+                               const struct xpart* restrict xp) {}
+
+/**
+ * @brief Set the variables that will be used to update the smoothing length
+ * during the drift (these will depend on the movement of the particles).
+ *
+ * @param p The particle to act upon.
+ */
+__attribute__((always_inline)) INLINE static void hydro_velocities_end_force(
+    struct part* restrict p) {
+
+#ifdef GIZMO_FIX_PARTICLES
+  /* disable the smoothing length update, since the smoothing lengths should
+     stay the same for all steps (particles don't move) */
+  p->force.h_dt = 0.0f;
+#else
+  /* Add normalization to h_dt. */
+  p->force.h_dt *= p->h * hydro_dimension_inv;
+#endif
+}
+
+/**
+ * @brief Set the velocity of a GIZMO particle, based on the values of its
+ * primitive variables and the geometry of its mesh-free "cell".
+ *
+ * @param p The particle to act upon.
+ * @param xp The extended particle data to act upon.
+ */
+__attribute__((always_inline)) INLINE static void hydro_velocities_set(
+    struct part* restrict p, struct xpart* restrict xp) {
+
+/* We first set the particle velocity. */
+#ifdef GIZMO_FIX_PARTICLES
+
+  p->v[0] = 0.f;
+  p->v[1] = 0.f;
+  p->v[2] = 0.f;
+
+#else  // GIZMO_FIX_PARTICLES
+
+  if (p->conserved.mass > 0.f && p->primitives.rho > 0.f) {
+
+    const float inverse_mass = 1.f / p->conserved.mass;
+
+    /* Normal case: set particle velocity to fluid velocity. */
+    p->v[0] = p->conserved.momentum[0] * inverse_mass;
+    p->v[1] = p->conserved.momentum[1] * inverse_mass;
+    p->v[2] = p->conserved.momentum[2] * inverse_mass;
+
+#ifdef GIZMO_STEER_MOTION
+
+    /* Add a correction to the velocity to keep particle positions close enough
+       to
+       the centroid of their mesh-free "cell". */
+    /* The correction term below is the same one described in Springel (2010).
+     */
+    float ds[3];
+    ds[0] = p->geometry.centroid[0];
+    ds[1] = p->geometry.centroid[1];
+    ds[2] = p->geometry.centroid[2];
+    const float d = sqrtf(ds[0] * ds[0] + ds[1] * ds[1] + ds[2] * ds[2]);
+    const float R = get_radius_dimension_sphere(p->geometry.volume);
+    const float eta = 0.25f;
+    const float etaR = eta * R;
+    const float xi = 1.f;
+    const float soundspeed =
+        sqrtf(hydro_gamma * p->primitives.P / p->primitives.rho);
+    /* We only apply the correction if the offset between centroid and position
+       is too large. */
+    if (d > 0.9f * etaR) {
+      float fac = xi * soundspeed / d;
+      if (d < 1.1f * etaR) {
+        fac *= 5.f * (d - 0.9f * etaR) / etaR;
+      }
+      p->v[0] -= ds[0] * fac;
+      p->v[1] -= ds[1] * fac;
+      p->v[2] -= ds[2] * fac;
+    }
+
+#endif  // GIZMO_STEER_MOTION
+  } else {
+    /* Vacuum particles have no fluid velocity. */
+    p->v[0] = 0.f;
+    p->v[1] = 0.f;
+    p->v[2] = 0.f;
+  }
+
+#endif  // GIZMO_FIX_PARTICLES
+
+  /* Now make sure all velocity variables are up to date. */
+  xp->v_full[0] = p->v[0];
+  xp->v_full[1] = p->v[1];
+  xp->v_full[2] = p->v[2];
+
+  if (p->gpart) {
+    p->gpart->v_full[0] = p->v[0];
+    p->gpart->v_full[1] = p->v[1];
+    p->gpart->v_full[2] = p->v[2];
+  }
+}
+
+#endif /* SWIFT_HYDRO_VELOCITIES_H */
diff --git a/src/hydro/MinimalMultiMat/hydro_io.h b/src/hydro/MinimalMultiMat/hydro_io.h
index 6e55497dc42111de291b8984a7dca048bb774722..2a5eeb6a54d079ae72e1591116a8984b0d7a6f38 100644
--- a/src/hydro/MinimalMultiMat/hydro_io.h
+++ b/src/hydro/MinimalMultiMat/hydro_io.h
@@ -72,6 +72,12 @@ void hydro_read_particles(struct part* parts, struct io_props* list,
       io_make_input_field("MaterialID", INT, 1, OPTIONAL, 1, parts, mat_id);
 }
 
+void convert_S(const struct engine* e, const struct part* p,
+               const struct xpart* xp, float* ret) {
+
+  ret[0] = hydro_get_comoving_entropy(p);
+}
+
 void convert_P(const struct engine* e, const struct part* p,
                const struct xpart* xp, float* ret) {
 
@@ -146,7 +152,7 @@ void convert_part_potential(const struct engine* e, const struct part* p,
 void hydro_write_particles(const struct part* parts, const struct xpart* xparts,
                            struct io_props* list, int* num_fields) {
 
-  *num_fields = 10;
+  *num_fields = 11;
 
   /* List what we want to write */
   list[0] = io_make_output_field_convert_part("Coordinates", DOUBLE, 3,
@@ -164,13 +170,16 @@ void hydro_write_particles(const struct part* parts, const struct xpart* xparts,
                                  UNIT_CONV_NO_UNITS, parts, id);
   list[6] =
       io_make_output_field("Density", FLOAT, 1, UNIT_CONV_DENSITY, parts, rho);
-  list[7] = io_make_output_field("MaterialID", INT, 1, UNIT_CONV_NO_UNITS,
+  list[7] = io_make_output_field_convert_part("Entropy", FLOAT, 1,
+                                              UNIT_CONV_ENTROPY_PER_UNIT_MASS,
+                                              parts, xparts, convert_S);
+  list[8] = io_make_output_field("MaterialID", INT, 1, UNIT_CONV_NO_UNITS,
                                  parts, mat_id);
-  list[8] = io_make_output_field_convert_part(
+  list[9] = io_make_output_field_convert_part(
       "Pressure", FLOAT, 1, UNIT_CONV_PRESSURE, parts, xparts, convert_P);
-  list[9] = io_make_output_field_convert_part("Potential", FLOAT, 1,
-                                              UNIT_CONV_POTENTIAL, parts,
-                                              xparts, convert_part_potential);
+  list[10] = io_make_output_field_convert_part("Potential", FLOAT, 1,
+                                               UNIT_CONV_POTENTIAL, parts,
+                                               xparts, convert_part_potential);
 }
 
 /**
diff --git a/src/hydro_io.h b/src/hydro_io.h
index b1d43592d504f82a2db1a9f265d30c20d6eddc35..d752bb8bc03f619fe759fc8f5de32a01b3a61abe 100644
--- a/src/hydro_io.h
+++ b/src/hydro_io.h
@@ -33,8 +33,10 @@
 #include "./hydro/PressureEnergy/hydro_io.h"
 #elif defined(DEFAULT_SPH)
 #include "./hydro/Default/hydro_io.h"
-#elif defined(GIZMO_SPH)
-#include "./hydro/Gizmo/hydro_io.h"
+#elif defined(GIZMO_MFV_SPH)
+#include "./hydro/GizmoMFV/hydro_io.h"
+#elif defined(GIZMO_MFM_SPH)
+#include "./hydro/GizmoMFM/hydro_io.h"
 #elif defined(SHADOWFAX_SPH)
 #include "./hydro/Shadowswift/hydro_io.h"
 #elif defined(MINIMAL_MULTI_MAT_SPH)
diff --git a/src/part.h b/src/part.h
index a207e82c2ee19f6ddad6dd261167a3360e23bfdd..7a1b6dd2b0e6a8f062658c5fac41f3534baa522e 100644
--- a/src/part.h
+++ b/src/part.h
@@ -57,8 +57,12 @@
 #elif defined(DEFAULT_SPH)
 #include "./hydro/Default/hydro_part.h"
 #define hydro_need_extra_init_loop 0
-#elif defined(GIZMO_SPH)
-#include "./hydro/Gizmo/hydro_part.h"
+#elif defined(GIZMO_MFV_SPH)
+#include "./hydro/GizmoMFV/hydro_part.h"
+#define hydro_need_extra_init_loop 0
+#define EXTRA_HYDRO_LOOP
+#elif defined(GIZMO_MFM_SPH)
+#include "./hydro/GizmoMFM/hydro_part.h"
 #define hydro_need_extra_init_loop 0
 #define EXTRA_HYDRO_LOOP
 #elif defined(SHADOWFAX_SPH)
diff --git a/src/riemann/riemann_exact.h b/src/riemann/riemann_exact.h
index 0c6c1c86273b42f521102e6e91d642d3dff30b27..9a671559c12a9df6d1e11016adc619c6043c83a9 100644
--- a/src/riemann/riemann_exact.h
+++ b/src/riemann/riemann_exact.h
@@ -485,6 +485,87 @@ __attribute__((always_inline)) INLINE static void riemann_solver_solve(
   Whalf[3] += vhalf * n_unit[2];
 }
 
+/**
+ * @brief Solve the Riemann problem between the given left and right state and
+ * return the velocity and pressure in the middle state
+ *
+ * Based on chapter 4 in Toro
+ *
+ * @param WL Left state.
+ * @param vL Left state velocity.
+ * @param WR Right state.
+ * @param vR Right state velocity.
+ * @param vM Middle state velocity.
+ * @param PM Middle state pressure.
+ */
+__attribute__((always_inline)) INLINE static void
+riemann_solver_solve_middle_state(const float* WL, const float vL,
+                                  const float* WR, const float vR, float* vM,
+                                  float* PM) {
+
+  /* sound speeds */
+  float aL, aR;
+  /* variables used for finding pstar */
+  float p, pguess, fp, fpguess;
+
+  /* calculate sound speeds */
+  aL = sqrtf(hydro_gamma * WL[4] / WL[0]);
+  aR = sqrtf(hydro_gamma * WR[4] / WR[0]);
+
+  /* vacuum */
+  /* check vacuum (generation) condition */
+  if (riemann_is_vacuum(WL, WR, vL, vR, aL, aR)) {
+    *vM = 0.0f;
+    *PM = 0.0f;
+    return;
+  }
+
+  /* values are ok: let's find pstar (riemann_f(pstar) = 0)! */
+  /* We normally use a Newton-Raphson iteration to find the zeropoint
+     of riemann_f(p), but if pstar is close to 0, we risk negative p values.
+     Since riemann_f(p) is undefined for negative pressures, we don't
+     want this to happen.
+     We therefore use Brent's method if riemann_f(0) is larger than some
+     value. -5 makes the iteration fail safe while almost never invoking
+     the expensive Brent solver. */
+  p = 0.0f;
+  /* obtain a first guess for p */
+  pguess = riemann_guess_p(WL, WR, vL, vR, aL, aR);
+  fp = riemann_f(p, WL, WR, vL, vR, aL, aR);
+  fpguess = riemann_f(pguess, WL, WR, vL, vR, aL, aR);
+  /* ok, pstar is close to 0, better use Brent's method... */
+  /* we use Newton-Raphson until we find a suitable interval */
+  if (fp * fpguess >= 0.0f) {
+    /* Newton-Raphson until convergence or until suitable interval is found
+       to use Brent's method */
+    unsigned int counter = 0;
+    while (fabs(p - pguess) > 1.e-6f * 0.5f * (p + pguess) && fpguess < 0.0f) {
+      p = pguess;
+      pguess = pguess - fpguess / riemann_fprime(pguess, WL, WR, aL, aR);
+      fpguess = riemann_f(pguess, WL, WR, vL, vR, aL, aR);
+      counter++;
+      if (counter > 1000) {
+        error("Stuck in Newton-Raphson!\n");
+      }
+    }
+  }
+  /* As soon as there is a suitable interval: use Brent's method */
+  if (1.e6 * fabs(p - pguess) > 0.5f * (p + pguess) && fpguess > 0.0f) {
+    p = 0.0f;
+    fp = riemann_f(p, WL, WR, vL, vR, aL, aR);
+    /* use Brent's method to find the zeropoint */
+    p = riemann_solve_brent(p, pguess, fp, fpguess, 1.e-6, WL, WR, vL, vR, aL,
+                            aR);
+  } else {
+    p = pguess;
+  }
+
+  *PM = p;
+  /* calculate the velocity in the intermediate state */
+  *vM =
+      0.5f * (vL + vR) + 0.5f * (riemann_fb(p, WR, aR) - riemann_fb(p, WL, aL));
+}
+
 __attribute__((always_inline)) INLINE static void riemann_solve_for_flux(
     const float* Wi, const float* Wj, const float* n_unit, const float* vij,
     float* totflux) {
@@ -543,4 +624,43 @@ __attribute__((always_inline)) INLINE static void riemann_solve_for_flux(
 #endif
 }
 
+__attribute__((always_inline)) INLINE static void
+riemann_solve_for_middle_state_flux(const float* Wi, const float* Wj,
+                                    const float* n_unit, const float* vij,
+                                    float* totflux) {
+
+#ifdef SWIFT_DEBUG_CHECKS
+  riemann_check_input(Wi, Wj, n_unit, vij);
+#endif
+
+  /* vacuum? */
+  if (Wi[0] == 0.0f || Wj[0] == 0.0f) {
+    totflux[0] = 0.0f;
+    totflux[1] = 0.0f;
+    totflux[2] = 0.0f;
+    totflux[3] = 0.0f;
+    totflux[4] = 0.0f;
+    return;
+  }
+
+  const float vL = Wi[1] * n_unit[0] + Wi[2] * n_unit[1] + Wi[3] * n_unit[2];
+  const float vR = Wj[1] * n_unit[0] + Wj[2] * n_unit[1] + Wj[3] * n_unit[2];
+
+  float vM, PM;
+  riemann_solver_solve_middle_state(Wi, vL, Wj, vR, &vM, &PM);
+
+  const float vface =
+      vij[0] * n_unit[0] + vij[1] * n_unit[1] + vij[2] * n_unit[2];
+
+  totflux[0] = 0.0f;
+  totflux[1] = PM * n_unit[0];
+  totflux[2] = PM * n_unit[1];
+  totflux[3] = PM * n_unit[2];
+  totflux[4] = (vM + vface) * PM;
+
+#ifdef SWIFT_DEBUG_CHECKS
+  riemann_check_output(Wi, Wj, n_unit, vij, totflux);
+#endif
+}
+
 #endif /* SWIFT_RIEMANN_EXACT_H */
diff --git a/src/riemann/riemann_hllc.h b/src/riemann/riemann_hllc.h
index 26fcd627fcf11769baf18955af53ed6e948ba513..68a92111d8e075faff5f93ab9c3d8a1ebc496cb0 100644
--- a/src/riemann/riemann_hllc.h
+++ b/src/riemann/riemann_hllc.h
@@ -185,4 +185,77 @@ __attribute__((always_inline)) INLINE static void riemann_solve_for_flux(
 #endif
 }
 
+__attribute__((always_inline)) INLINE static void
+riemann_solve_for_middle_state_flux(const float *WL, const float *WR,
+                                    const float *n, const float *vij,
+                                    float *totflux) {
+
+#ifdef SWIFT_DEBUG_CHECKS
+  riemann_check_input(WL, WR, n, vij);
+#endif
+
+  /* Handle pure vacuum */
+  if (!WL[0] && !WR[0]) {
+    totflux[0] = 0.f;
+    totflux[1] = 0.f;
+    totflux[2] = 0.f;
+    totflux[3] = 0.f;
+    totflux[4] = 0.f;
+    return;
+  }
+
+  /* STEP 0: obtain velocity in interface frame */
+  const float uL = WL[1] * n[0] + WL[2] * n[1] + WL[3] * n[2];
+  const float uR = WR[1] * n[0] + WR[2] * n[1] + WR[3] * n[2];
+  const float aL = sqrtf(hydro_gamma * WL[4] / WL[0]);
+  const float aR = sqrtf(hydro_gamma * WR[4] / WR[0]);
+
+  /* Handle vacuum: vacuum does not require iteration and is always exact */
+  if (riemann_is_vacuum(WL, WR, uL, uR, aL, aR)) {
+    totflux[0] = 0.f;
+    totflux[1] = 0.f;
+    totflux[2] = 0.f;
+    totflux[3] = 0.f;
+    totflux[4] = 0.f;
+    return;
+  }
+
+  /* STEP 1: pressure estimate */
+  const float rhobar = 0.5f * (WL[0] + WR[0]);
+  const float abar = 0.5f * (aL + aR);
+  const float pPVRS = 0.5f * (WL[4] + WR[4]) - 0.5f * (uR - uL) * rhobar * abar;
+  const float pstar = max(0.f, pPVRS);
+
+  /* STEP 2: wave speed estimates
+     all these speeds are along the interface normal, since uL and uR are */
+  float qL = 1.f;
+  if (pstar > WL[4] && WL[4] > 0.f) {
+    qL = sqrtf(1.f +
+               0.5f * hydro_gamma_plus_one * hydro_one_over_gamma *
+                   (pstar / WL[4] - 1.f));
+  }
+  float qR = 1.f;
+  if (pstar > WR[4] && WR[4] > 0.f) {
+    qR = sqrtf(1.f +
+               0.5f * hydro_gamma_plus_one * hydro_one_over_gamma *
+                   (pstar / WR[4] - 1.f));
+  }
+  const float SL = uL - aL * qL;
+  const float SR = uR + aR * qR;
+  const float Sstar =
+      (WR[4] - WL[4] + WL[0] * uL * (SL - uL) - WR[0] * uR * (SR - uR)) /
+      (WL[0] * (SL - uL) - WR[0] * (SR - uR));
+
+  totflux[0] = 0.0f;
+  totflux[1] = pstar * n[0];
+  totflux[2] = pstar * n[1];
+  totflux[3] = pstar * n[2];
+  const float vface = vij[0] * n[0] + vij[1] * n[1] + vij[2] * n[2];
+  totflux[4] = pstar * (Sstar + vface);
+
+#ifdef SWIFT_DEBUG_CHECKS
+  riemann_check_output(WL, WR, n, vij, totflux);
+#endif
+}
+
 #endif /* SWIFT_RIEMANN_HLLC_H */
diff --git a/src/riemann/riemann_trrs.h b/src/riemann/riemann_trrs.h
index 597f6f8edd9690dbdd34a3c9885ae228c2af734c..c19ff70f62a9018f4d121f8b689a0a13c371d86a 100644
--- a/src/riemann/riemann_trrs.h
+++ b/src/riemann/riemann_trrs.h
@@ -219,4 +219,64 @@ __attribute__((always_inline)) INLINE static void riemann_solve_for_flux(
 #endif
 }
 
+__attribute__((always_inline)) INLINE static void
+riemann_solve_for_middle_state_flux(const float* Wi, const float* Wj,
+                                    const float* n_unit, const float* vij,
+                                    float* totflux) {
+
+#ifdef SWIFT_DEBUG_CHECKS
+  riemann_check_input(Wi, Wj, n_unit, vij);
+#endif
+
+  if (Wi[0] == 0.0f || Wj[0] == 0.0f) {
+    totflux[0] = 0.0f;
+    totflux[1] = 0.0f;
+    totflux[2] = 0.0f;
+    totflux[3] = 0.0f;
+    totflux[4] = 0.0f;
+    return;
+  }
+
+  /* calculate the velocities along the interface normal */
+  const float vL = Wi[1] * n_unit[0] + Wi[2] * n_unit[1] + Wi[3] * n_unit[2];
+  const float vR = Wj[1] * n_unit[0] + Wj[2] * n_unit[1] + Wj[3] * n_unit[2];
+
+  /* calculate the sound speeds */
+  const float aL = sqrtf(hydro_gamma * Wi[4] / Wi[0]);
+  const float aR = sqrtf(hydro_gamma * Wj[4] / Wj[0]);
+
+  if (riemann_is_vacuum(Wi, Wj, vL, vR, aL, aR)) {
+    totflux[0] = 0.0f;
+    totflux[1] = 0.0f;
+    totflux[2] = 0.0f;
+    totflux[3] = 0.0f;
+    totflux[4] = 0.0f;
+    return;
+  }
+
+  /* calculate the velocity and pressure in the intermediate state */
+  const float PLR = pow_gamma_minus_one_over_two_gamma(Wi[4] / Wj[4]);
+  const float ustar = (PLR * vL / aL + vR / aR +
+                       hydro_two_over_gamma_minus_one * (PLR - 1.0f)) /
+                      (PLR / aL + 1.0f / aR);
+  const float pstar =
+      0.5f *
+      (Wi[4] * pow_two_gamma_over_gamma_minus_one(
+                   1.0f + hydro_gamma_minus_one_over_two / aL * (vL - ustar)) +
+       Wj[4] * pow_two_gamma_over_gamma_minus_one(
+                   1.0f + hydro_gamma_minus_one_over_two / aR * (ustar - vR)));
+
+  totflux[0] = 0.0f;
+  totflux[1] = pstar * n_unit[0];
+  totflux[2] = pstar * n_unit[1];
+  totflux[3] = pstar * n_unit[2];
+  const float vface =
+      vij[0] * n_unit[0] + vij[1] * n_unit[1] + vij[2] * n_unit[2];
+  totflux[4] = pstar * (ustar + vface);
+
+#ifdef SWIFT_DEBUG_CHECKS
+  riemann_check_output(Wi, Wj, n_unit, vij, totflux);
+#endif
+}
+
 #endif /* SWIFT_RIEMANN_TRRS_H */
diff --git a/src/utilities.h b/src/utilities.h
new file mode 100644
index 0000000000000000000000000000000000000000..28faf6b1e59159af4ee4a7b87054ab6a36478c9c
--- /dev/null
+++ b/src/utilities.h
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Copyright (c) 2018 Jacob Kegerreis (jacob.kegerreis@durham.ac.uk)
+ *
+ * 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/>.
+ *
+ ******************************************************************************/
+
+#ifndef SWIFT_UTILITIES_H
+#define SWIFT_UTILITIES_H
+
+/**
+ * @brief Search for a value in a monotonically increasing array to find the
+ *      index such that array[index] < value < array[index + 1]
+ *
+ * @param x The value to find
+ * @param array The array to search
+ * @param n The length of the array
+ *
+ * Return -1 and n for x below and above the array edge values respectively.
+ */
+INLINE static int find_value_in_monot_incr_array(const float x,
+                                                 const float *array,
+                                                 const int n) {
+
+  int index_mid, index_low = 0, index_high = n;
+
+  // Until array[index_low] < x < array[index_high=index_low+1]
+  while (index_high - index_low > 1) {
+    index_mid = (index_high + index_low) / 2;  // Middle index
+
+    // Replace the low or high index with the middle
+    if (array[index_mid] <= x)
+      index_low = index_mid;
+    else
+      index_high = index_mid;
+  }
+
+  // Set index with the found index_low or an error value if outside the array
+  if (x < array[0])
+    return -1;
+  else if (array[n - 1] <= x)
+    return n;
+  else
+    return index_low;
+}
+
+#endif /* SWIFT_UTILITIES_H */
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 2dfe760d80332f7da8de4cf11c0f15e21c231089..891eef3f518f83c17b66623e3dac1832512d31f3 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -27,7 +27,7 @@ TESTS = testGreetings testMaths testReading.sh testSingle testKernel testSymmetr
         testMatrixInversion testThreadpool testDump testLogger testInteractions.sh \
         testVoronoi1D testVoronoi2D testVoronoi3D testGravityDerivatives \
 	testPeriodicBC.sh testPeriodicBCPerturbed.sh testPotentialSelf \
-	testPotentialPair testEOS
+	testPotentialPair testEOS testUtilities
 
 # List of test programs to compile
 check_PROGRAMS = testGreetings testReading testSingle testTimeIntegration \
@@ -37,7 +37,7 @@ check_PROGRAMS = testGreetings testReading testSingle testTimeIntegration \
                  testAdiabaticIndex testRiemannExact testRiemannTRRS \
                  testRiemannHLLC testMatrixInversion testDump testLogger \
 		 testVoronoi1D testVoronoi2D testVoronoi3D testPeriodicBC \
-		 testGravityDerivatives testPotentialSelf testPotentialPair testEOS
+		 testGravityDerivatives testPotentialSelf testPotentialPair testEOS testUtilities
 
 # Rebuild tests when SWIFT is updated.
 $(check_PROGRAMS): ../src/.libs/libswiftsim.a
@@ -110,6 +110,8 @@ testPotentialPair_SOURCES = testPotentialPair.c
 
 testEOS_SOURCES = testEOS.c
 
+testUtilities_SOURCES = testUtilities.c
+
 # Files necessary for distribution
 EXTRA_DIST = testReading.sh makeInput.py testActivePair.sh \
 	     test27cells.sh test27cellsPerturbed.sh testParser.sh testPeriodicBC.sh \
diff --git a/tests/test125cells.c b/tests/test125cells.c
index 5195f431c23067a732ae9d060ffc6d2b01b5feaf..a1661bb93bfdac3b6111148f9fae42b243c04742 100644
--- a/tests/test125cells.c
+++ b/tests/test125cells.c
@@ -122,7 +122,7 @@ void set_energy_state(struct part *part, enum pressure_field press, float size,
   part->u = pressure / (hydro_gamma_minus_one * density);
 #elif defined(MINIMAL_MULTI_MAT_SPH)
   part->u = pressure / (hydro_gamma_minus_one * density);
-#elif defined(GIZMO_SPH) || defined(SHADOWFAX_SPH)
+#elif defined(GIZMO_MFV_SPH) || defined(SHADOWFAX_SPH)
   part->primitives.P = pressure;
 #else
   error("Need to define pressure here !");
@@ -222,9 +222,9 @@ void reset_particles(struct cell *c, struct hydro_space *hs,
 
     hydro_init_part(p, hs);
 
-#if defined(GIZMO_SPH) || defined(SHADOWFAX_SPH)
+#if defined(GIZMO_MFV_SPH) || defined(SHADOWFAX_SPH)
     float volume = p->conserved.mass / density;
-#if defined(GIZMO_SPH)
+#if defined(GIZMO_MFV_SPH)
     p->geometry.volume = volume;
 #else
     p->cell.volume = volume;
@@ -300,7 +300,7 @@ struct cell *make_cell(size_t n, const double offset[3], double size, double h,
         part->h = size * h / (float)n;
         h_max = fmax(h_max, part->h);
 
-#if defined(GIZMO_SPH) || defined(SHADOWFAX_SPH)
+#if defined(GIZMO_MFV_SPH) || defined(SHADOWFAX_SPH)
         part->conserved.mass = density * volume / count;
 #else
         part->mass = density * volume / count;
@@ -314,7 +314,7 @@ struct cell *make_cell(size_t n, const double offset[3], double size, double h,
         part->id = ++(*partId);
         part->time_bin = 1;
 
-#if defined(GIZMO_SPH)
+#if defined(GIZMO_MFV_SPH)
         part->geometry.volume = part->conserved.mass / density;
         part->primitives.rho = density;
         part->primitives.v[0] = part->v[0];
@@ -406,7 +406,7 @@ void dump_particle_fields(char *fileName, struct cell *main_cell,
             main_cell->parts[pid].v[2], main_cell->parts[pid].h,
             hydro_get_comoving_density(&main_cell->parts[pid]),
 #if defined(MINIMAL_SPH) || defined(MINIMAL_MULTI_MAT_SPH) || \
-    defined(SHADOWFAX_SPH) || defined(HOPKINS_PU_SPH)
+    defined(GIZMO_MFV_SPH) || defined(SHADOWFAX_SPH) || defined(HOPKINS_PU_SPH)
             0.f,
 #else
             main_cell->parts[pid].density.div_v,
diff --git a/tests/test27cells.c b/tests/test27cells.c
index 1934ca84b2610ec565503a319bd798f88c279cce..bf226335793060b338fadf97756d22e4abdc518f 100644
--- a/tests/test27cells.c
+++ b/tests/test27cells.c
@@ -150,7 +150,7 @@ struct cell *make_cell(size_t n, double *offset, double size, double h,
         h_max = fmaxf(h_max, part->h);
         part->id = ++(*partId);
 
-#if defined(GIZMO_SPH) || defined(SHADOWFAX_SPH)
+#if defined(GIZMO_MFV_SPH) || defined(SHADOWFAX_SPH)
         part->conserved.mass = density * volume / count;
 
 #ifdef SHADOWFAX_SPH
@@ -261,7 +261,7 @@ void dump_particle_fields(char *fileName, struct cell *main_cell,
             main_cell->parts[pid].v[0], main_cell->parts[pid].v[1],
             main_cell->parts[pid].v[2],
             hydro_get_comoving_density(&main_cell->parts[pid]),
-#if defined(GIZMO_SPH) || defined(SHADOWFAX_SPH)
+#if defined(GIZMO_MFV_SPH) || defined(SHADOWFAX_SPH)
             0.f,
 #elif defined(HOPKINS_PU_SPH)
             main_cell->parts[pid].density.pressure_bar_dh,
@@ -300,7 +300,7 @@ void dump_particle_fields(char *fileName, struct cell *main_cell,
               cj->parts[pjd].id, cj->parts[pjd].x[0], cj->parts[pjd].x[1],
               cj->parts[pjd].x[2], cj->parts[pjd].v[0], cj->parts[pjd].v[1],
               cj->parts[pjd].v[2], hydro_get_comoving_density(&cj->parts[pjd]),
-#if defined(GIZMO_SPH) || defined(SHADOWFAX_SPH)
+#if defined(GIZMO_MFV_SPH) || defined(SHADOWFAX_SPH)
               0.f,
 #else
               main_cell->parts[pjd].density.rho_dh,
diff --git a/tests/testActivePair.c b/tests/testActivePair.c
index 4b0b63d9766dbfd313fd60610705ede3eea29141..0453f6d5896eaa53b0f44a567d353d7d8e8fb7df 100644
--- a/tests/testActivePair.c
+++ b/tests/testActivePair.c
@@ -94,7 +94,7 @@ struct cell *make_cell(size_t n, double *offset, double size, double h,
         part->id = ++(*partId);
 
 /* Set the mass */
-#if defined(GIZMO_SPH) || defined(SHADOWFAX_SPH)
+#if defined(GIZMO_MFV_SPH) || defined(SHADOWFAX_SPH)
         part->conserved.mass = density * volume / count;
 
 #ifdef SHADOWFAX_SPH
@@ -105,7 +105,7 @@ struct cell *make_cell(size_t n, double *offset, double size, double h,
 
 #else
         part->mass = density * volume / count;
-#endif /* GIZMO_SPH */
+#endif /* GIZMO_MFV_SPH */
 
 /* Set the thermodynamic variable */
 #if defined(GADGET2_SPH)
diff --git a/tests/testInteractions.c b/tests/testInteractions.c
index 8e29bf9b3ceb519d8a6a8271f290e0c9121d3362..f288ab3c9ac6c625075b0334e1a0e26a3d5a082b 100644
--- a/tests/testInteractions.c
+++ b/tests/testInteractions.c
@@ -74,7 +74,7 @@ struct part *make_particles(size_t count, double *offset, double spacing,
   p->h = h;
   p->id = ++(*partId);
 
-#if !defined(GIZMO_SPH) && !defined(SHADOWFAX_SPH)
+#if !defined(GIZMO_MFV_SPH) && !defined(SHADOWFAX_SPH)
   p->mass = 1.0f;
 #endif
 
@@ -107,8 +107,9 @@ struct part *make_particles(size_t count, double *offset, double spacing,
  */
 void prepare_force(struct part *parts, size_t count) {
 
-#if !defined(GIZMO_SPH) && !defined(SHADOWFAX_SPH) && !defined(MINIMAL_SPH) && \
-    !defined(MINIMAL_MULTI_MAT_SPH) && !defined(HOPKINS_PU_SPH)
+#if !defined(GIZMO_MFV_SPH) && !defined(SHADOWFAX_SPH) && \
+    !defined(MINIMAL_SPH) && !defined(MINIMAL_MULTI_MAT_SPH) && \
+    !defined(HOPKINS_PU_SPH)
   struct part *p;
   for (size_t i = 0; i < count; ++i) {
     p = &parts[i];
diff --git a/tests/testPeriodicBC.c b/tests/testPeriodicBC.c
index 2aa15f0aa94acafa20c56767fa6d739798f6c7f3..385de9752f361f4f015eb64a466473324901030f 100644
--- a/tests/testPeriodicBC.c
+++ b/tests/testPeriodicBC.c
@@ -129,7 +129,7 @@ struct cell *make_cell(size_t n, double *offset, double size, double h,
         h_max = fmax(h_max, part->h);
         part->id = ++(*partId);
 
-#if defined(GIZMO_SPH) || defined(SHADOWFAX_SPH)
+#if defined(GIZMO_MFV_SPH) || defined(SHADOWFAX_SPH)
         part->conserved.mass = density * volume / count;
 
 #ifdef SHADOWFAX_SPH
@@ -237,7 +237,7 @@ void dump_particle_fields(char *fileName, struct cell *main_cell, int i, int j,
             main_cell->parts[pid].v[0], main_cell->parts[pid].v[1],
             main_cell->parts[pid].v[2],
             hydro_get_comoving_density(&main_cell->parts[pid]),
-#if defined(GIZMO_SPH) || defined(SHADOWFAX_SPH)
+#if defined(GIZMO_MFV_SPH) || defined(SHADOWFAX_SPH)
             0.f,
 #else
             main_cell->parts[pid].density.rho_dh,
diff --git a/tests/testRiemannExact.c b/tests/testRiemannExact.c
index b72b7b6ce9d7fb4c6f7449af73c6a67ce4d8d1e7..bce7c52d422f966e10d530cdcbc8f6d20431e153 100644
--- a/tests/testRiemannExact.c
+++ b/tests/testRiemannExact.c
@@ -23,6 +23,12 @@
 #include <stdio.h>
 #include <string.h>
 
+/* Force use of exact Riemann solver */
+#undef RIEMANN_SOLVER_TRRS
+#undef RIEMANN_SOLVER_HLLC
+#undef RIEMANN_SOLVER_EXACT
+#define RIEMANN_SOLVER_EXACT 1
+
 /* Local headers. */
 #include "riemann/riemann_exact.h"
 #include "swift.h"
diff --git a/tests/testRiemannHLLC.c b/tests/testRiemannHLLC.c
index e843b29093f88d54dd931becf966d46670707091..b988825eb0535fcdc46baa1db1203d0dbac3537a 100644
--- a/tests/testRiemannHLLC.c
+++ b/tests/testRiemannHLLC.c
@@ -24,6 +24,12 @@
 #include <stdio.h>
 #include <string.h>
 
+/* Force use of the HLLC Riemann solver */
+#undef RIEMANN_SOLVER_TRRS
+#undef RIEMANN_SOLVER_EXACT
+#undef RIEMANN_SOLVER_HLLC
+#define RIEMANN_SOLVER_HLLC 1
+
 /* Local headers. */
 #include "riemann/riemann_hllc.h"
 #include "swift.h"
diff --git a/tests/testSymmetry.c b/tests/testSymmetry.c
index 1caae903418294439a107ce3a0972f15850ad5d1..1ab493a7c149070dc667a2377ab205df7f873856 100644
--- a/tests/testSymmetry.c
+++ b/tests/testSymmetry.c
@@ -41,7 +41,7 @@ void test() {
 /*  voronoi_set_box(box_anchor, box_side);*/
 #endif
 
-  /* Start with some values for the cosmological paramters */
+  /* Start with some values for the cosmological parameters */
   const float a = (float)random_uniform(0.8, 1.);
   const float H = 1.f;
 
@@ -62,7 +62,7 @@ void test() {
   pi.time_bin = 1;
   pj.time_bin = 1;
 
-#if defined(GIZMO_SPH) || defined(SHADOWFAX_SPH)
+#if defined(GIZMO_MFV_SPH) || defined(SHADOWFAX_SPH)
   /* Give the primitive variables sensible values, since the Riemann solver does
      not like negative densities and pressures */
   pi.primitives.rho = random_uniform(0.1f, 1.0f);
@@ -106,11 +106,12 @@ void test() {
   pj.primitives.gradients.P[0] = 0.0f;
   pj.primitives.gradients.P[1] = 0.0f;
   pj.primitives.gradients.P[2] = 0.0f;
+
+#ifdef SHADOWFAX_SPH
   /* set time step to reasonable value */
   pi.force.dt = 0.001;
   pj.force.dt = 0.001;
 
-#ifdef SHADOWFAX_SPH
   voronoi_cell_init(&pi.cell, pi.x, box_anchor, box_side);
   voronoi_cell_init(&pj.cell, pj.x, box_anchor, box_side);
 #endif
@@ -187,33 +188,33 @@ void test() {
   runner_iact_nonsym_force(r2, dx, pj2.h, pi2.h, &pj2, &pi2, a, H);
 
 /* Check that the particles are the same */
-#if defined(GIZMO_SPH)
+#if defined(GIZMO_MFV_SPH)
   i_not_ok = 0;
   j_not_ok = 0;
   for (size_t i = 0; i < sizeof(struct part) / sizeof(float); ++i) {
-    float a = *(((float *)&pi) + i);
-    float b = *(((float *)&pi2) + i);
-    float c = *(((float *)&pj) + i);
-    float d = *(((float *)&pj2) + i);
+    float aa = *(((float *)&pi) + i);
+    float bb = *(((float *)&pi2) + i);
+    float cc = *(((float *)&pj) + i);
+    float dd = *(((float *)&pj2) + i);
 
     int a_is_b;
-    if ((a + b)) {
-      a_is_b = (fabs((a - b) / (a + b)) > 1.e-4);
+    if ((aa + bb)) {
+      a_is_b = (fabs((aa - bb) / (aa + bb)) > 1.e-4);
     } else {
-      a_is_b = !(a == 0.0f);
+      a_is_b = !(aa == 0.0f);
     }
     int c_is_d;
-    if ((c + d)) {
-      c_is_d = (fabs((c - d) / (c + d)) > 1.e-4);
+    if ((cc + dd)) {
+      c_is_d = (fabs((cc - dd) / (cc + dd)) > 1.e-4);
     } else {
-      c_is_d = !(c == 0.0f);
+      c_is_d = !(cc == 0.0f);
     }
 
     if (a_is_b) {
-      message("%.8e, %.8e, %lu", a, b, i);
+      message("%.8e, %.8e, %lu", aa, bb, i);
     }
     if (c_is_d) {
-      message("%.8e, %.8e, %lu", c, d, i);
+      message("%.8e, %.8e, %lu", cc, dd, i);
     }
 
     i_not_ok |= a_is_b;
diff --git a/tests/testUtilities.c b/tests/testUtilities.c
new file mode 100644
index 0000000000000000000000000000000000000000..b835faba9026661361c8828fce5c18beb2b80889
--- /dev/null
+++ b/tests/testUtilities.c
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Copyright (C) 2018 Jacob Kegerreis (jacob.kegerreis@durham.ac.uk)
+ *
+ * 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/>.
+ *
+ ******************************************************************************/
+
+#include "swift.h"
+#include "utilities.h"
+
+/**
+ * @brief Test generic utility functions
+ */
+int main() {
+  /// Test find_value_in_monot_incr_array()
+  int n = 100;
+  float array[n];
+  int index;
+  float x;
+
+  // Initialise test array
+  for (int j = 0; j < n; j++) {
+    array[j] = j;
+  }
+
+  // Typical value
+  x = 42.42f;
+  index = find_value_in_monot_incr_array(x, array, n);
+  if (index != 42) {
+    error("Failed with a typical value ");
+  }
+
+  // Value on array element
+  x = 33.f;
+  index = find_value_in_monot_incr_array(x, array, n);
+  if (index != 33) {
+    error("Failed with an array element ");
+  }
+
+  // Value below array
+  x = -123.f;
+  index = find_value_in_monot_incr_array(x, array, n);
+  if (index != -1) {
+    error("Failed with a value below the array ");
+  }
+
+  // Value above array
+  x = 123.f;
+  index = find_value_in_monot_incr_array(x, array, n);
+  if (index != n) {
+    error("Failed with a value above the array ");
+  }
+
+  // Array slice with typical value
+  x = 9.81f;
+  n = 10;
+  index = find_value_in_monot_incr_array(x, array + 5, n);
+  if (index != 4) {
+    error("Failed with an array slice ");
+  }
+
+  return 0;
+}