diff --git a/examples/CoolingBox/analytical_test.py b/examples/CoolingBox/analytical_test.py
index b468cb059e559392d57a7673d069d1ac3781f607..281de2b9b90f65e4c7e483778c197f71261b923f 100644
--- a/examples/CoolingBox/analytical_test.py
+++ b/examples/CoolingBox/analytical_test.py
@@ -86,7 +86,7 @@ temp_0 = 1.0e7
 rho = rho*unit_mass/(unit_length**3)
 
 # Read snapshots
-nsnap = 150
+nsnap = 110
 npart = 4096
 u_snapshots_cgs = zeros(nsnap)
 u_part_snapshots_cgs = zeros((nsnap,npart))
@@ -137,6 +137,7 @@ p = figure()
 p1, = plot(t_sol,temp_sol,linewidth = 0.5,color = 'k',label = 'analytical')
 p2, = plot(t_snapshots_cgs,mean_temp,linewidth = 0.5,color = 'r',label = 'swift mean')
 l = legend(handles = [p1,p2])
+plt.ticklabel_format(style='sci', axis='y', scilimits=(0,0))
 xlabel("${\\rm{Time~[s]}}$", labelpad=0)
 ylabel("${\\rm{Temperature~[K]}}$")
 
diff --git a/examples/CoolingBox/makeIC.py b/examples/CoolingBox/makeIC.py
index 23de7674c8fddfc44e6f5201b4f35f3dc5dc808e..4c376663bf1987203334d1199295e04c65c7c13d 100644
--- a/examples/CoolingBox/makeIC.py
+++ b/examples/CoolingBox/makeIC.py
@@ -27,7 +27,7 @@ from numpy import *
 # Parameters
 periodic= 1           # 1 For periodic box
 boxSize = 1           # 1 kiloparsec    
-rho = 3.2e3           # Density in code units (3.2e6 is 0.1 hydrogen atoms per cm^3)
+rho = 3.2e6           # Density in code units (3.2e6 is 0.1 hydrogen atoms per cm^3)
 P = 4.5e7             # Pressure in code units (at 10^6K)
 gamma = 5./3.         # Gas adiabatic index
 eta = 1.2349          # 48 ngbs with cubic spline kernel
diff --git a/examples/CoolingBox/run.sh b/examples/CoolingBox/run.sh
index 232bd54650330dafc62d37bbd97552ed319ad732..d84ffb4a99cf4abd01b6c6a4935e4e4394589745 100755
--- a/examples/CoolingBox/run.sh
+++ b/examples/CoolingBox/run.sh
@@ -21,7 +21,7 @@ then
 fi
 
 # Run SWIFT
-../swift -s -C -t 8 coolingBox.yml
+../swift -s -C -t 16 coolingBox.yml
 
 # Check energy conservation and cooling rate
 python energy_plot.py
diff --git a/examples/EAGLE_12/eagle_12.yml b/examples/EAGLE_12/eagle_12.yml
index c567fa91fcdc53091ff4acda8334551664ded952..f973fc62b25fc9c2f4c395cbc75ef2c8978b02a6 100644
--- a/examples/EAGLE_12/eagle_12.yml
+++ b/examples/EAGLE_12/eagle_12.yml
@@ -54,5 +54,22 @@ SPH:
 InitialConditions:
   file_name:  ./EAGLE_ICs_12.hdf5    # The file to read
   cleanup_h_factors: 1               # Remove the h-factors inherited from Gadget
-  cleanup_velocity_factors: 1        # Remove the sqrt(a) factor in the velocities inherited from Gadget
+
+EAGLEChemistry:
+  InitMetallicity:         0.014
+  InitAbundance_Hydrogen:  0.70649785
+  InitAbundance_Helium:    0.28055534
+  InitAbundance_Carbon:    2.0665436e-3
+  InitAbundance_Nitrogen:  8.3562563e-4
+  InitAbundance_Oxygen:    5.4926244e-3
+  InitAbundance_Neon:      1.4144605e-3
+  InitAbundance_Magnesium: 5.907064e-4
+  InitAbundance_Silicon:   6.825874e-4
+  InitAbundance_Iron:      1.1032152e-3
+  CalciumOverSilicon:      0.0941736
+  SulphurOverSilicon:      0.6054160
+
+EagleCooling:
+  filename:                /cosma5/data/Eagle/BG_Tables/CoolingTables/
+  reionisation_redshift:   8.898
 
diff --git a/examples/EAGLE_12/run.sh b/examples/EAGLE_12/run.sh
index 67f1c24a1ead927823b9240cdeb718b35580d573..0e35e36d26e110f244265d2e2d3a21381104d655 100755
--- a/examples/EAGLE_12/run.sh
+++ b/examples/EAGLE_12/run.sh
@@ -7,5 +7,5 @@ then
     ./getIC.sh
 fi
 
-../swift -c -s -G -S -t 16 eagle_12.yml 2>&1 | tee output.log
+../swift -s -c -C -t 16 eagle_12.yml 2>&1 | tee output.log
 
diff --git a/examples/EAGLE_6/eagle_6.yml b/examples/EAGLE_6/eagle_6.yml
index eb374df964e8b021ef2b7d90caf8a1824cf3a833..024602428409f9cee42db57870f4bd3896094298 100644
--- a/examples/EAGLE_6/eagle_6.yml
+++ b/examples/EAGLE_6/eagle_6.yml
@@ -70,3 +70,40 @@ InitialConditions:
   cleanup_velocity_factors: 1        # Remove the sqrt(a) factor in the velocities inherited from Gadget
 
 
+EAGLEChemistry:
+  InitMetallicity:         0.014
+  InitAbundance_Hydrogen:  0.70649785
+  InitAbundance_Helium:    0.28055534
+  InitAbundance_Carbon:    2.0665436e-3
+  InitAbundance_Nitrogen:  8.3562563e-4
+  InitAbundance_Oxygen:    5.4926244e-3
+  InitAbundance_Neon:      1.4144605e-3
+  InitAbundance_Magnesium: 5.907064e-4
+  InitAbundance_Silicon:   6.825874e-4
+  InitAbundance_Iron:      1.1032152e-3
+  CalciumOverSilicon:      0.0941736
+  SulphurOverSilicon:      0.6054160
+
+EagleCooling:
+  filename:                /cosma5/data/Eagle/BG_Tables/CoolingTables/
+  reionisation_redshift:   8.898
+
+#Cosmology:
+#  Omega_m:        0.307
+#  Omega_lambda:   0.693
+#  Omega_b:        0.0455
+#  h:              0.6777
+#  #a_begin:        0.0078125
+#  a_begin:        1.0
+#  #a_begin:        0.5
+#  a_end:          1.0
+
+# Cosmological parameters
+Cosmology:
+  h:              0.6777        # Reduced Hubble constant
+  a_begin:        0.9090909     # Initial scale-factor of the simulation
+  a_end:          1.0           # Final scale factor of the simulation
+  Omega_m:        0.307         # Matter density parameter
+  Omega_lambda:   0.693         # Dark-energy density parameter
+  Omega_b:        0.0455        # Baryon density parameter
+
diff --git a/examples/EAGLE_6/run.sh b/examples/EAGLE_6/run.sh
index 7ef3fc2abdd1bb3fed1a228bf993bf09fb13f42c..5025b778a1bed22d950464ac13a6e2eec3f55623 100755
--- a/examples/EAGLE_6/run.sh
+++ b/examples/EAGLE_6/run.sh
@@ -7,5 +7,5 @@ then
     ./getIC.sh
 fi
 
-../swift -c -s -G -S -t 16 eagle_6.yml 2>&1 | tee output.log
+../swift -c -C -s -t 16 eagle_6.yml 2>&1 | tee output.log
 
diff --git a/examples/main.c b/examples/main.c
index 116d422c9adae14d4b14ec4467378c65a53aa0da..3f4837a154b230d1914d9c73eb2f3dbec467492c 100644
--- a/examples/main.c
+++ b/examples/main.c
@@ -51,6 +51,12 @@
 /* Global profiler. */
 struct profiler prof;
 
+/* number of calls to eagle cooling rate */
+int n_eagle_cooling_rate_calls_1 = 0;
+int n_eagle_cooling_rate_calls_2 = 0;
+int n_eagle_cooling_rate_calls_3 = 0;
+int n_eagle_cooling_rate_calls_4 = 0;
+
 /**
  * @brief Help messages for the command line parameters.
  */
@@ -125,7 +131,7 @@ int main(int argc, char *argv[]) {
 
   struct clocks_time tic, toc;
   struct engine e;
-
+  
   /* Structs used by the engine. Declare now to make sure these are always in
    * scope.  */
   struct chemistry_global_data chemistry;
diff --git a/src/cooling/EAGLE/cooling.h b/src/cooling/EAGLE/cooling.h
index 64b2ea17c50e88e2c569f88f174a396b001d1e47..671c3400a24e477f233f29d753d031fbd5656fd3 100644
--- a/src/cooling/EAGLE/cooling.h
+++ b/src/cooling/EAGLE/cooling.h
@@ -45,6 +45,12 @@
 #include "units.h"
 #include "eagle_cool_tables.h"
 
+/* number of calls to eagle cooling rate */
+//extern int n_eagle_cooling_rate_calls_1;
+//extern int n_eagle_cooling_rate_calls_2;
+//extern int n_eagle_cooling_rate_calls_3;
+//extern int n_eagle_cooling_rate_calls_4;
+
 static int get_redshift_index_first_call = 0;
 static int get_redshift_index_previous = -1;
 
@@ -59,20 +65,23 @@ enum hdf5_allowed_types {
 
 __attribute__((always_inline)) INLINE int row_major_index_2d(int i, int j,
                                                                int nx, int ny) {
-  int index = (i % nx) * ny + (j % ny);
-//#ifdef SWIFT_DEBUG_CHECKS
-//  if (index >= nx*ny) fprintf(stderr, "row_major_index_2d out of bounds, i, j, nx, ny, index, nx*ny %d, %d, %d, %d, %d, %d \n",i,j,nx,ny,index,nx*ny); 
-//#endif
+  int index = i * ny + j;
+#ifdef SWIFT_DEBUG_CHECKS
+  assert(i < nx);
+  assert(j < ny);
+#endif
   return index;
 }
 
 __attribute__((always_inline)) INLINE int row_major_index_3d(int i, int j,
                                                               int k, int nx, 
 							      int ny, int nz) {
-  int index = (i % nx) * ny * nz + (j % ny) * nz + (k % nz);
-//#ifdef SWIFT_DEBUG_CHECKS
-//  if (index >= nx*ny*nz) fprintf(stderr, "row_major_index_3d out of bounds, i, j, k, nx, ny, nz, index, nx*ny*nz %d, %d, %d, %d, %d, %d, %d, %d \n",i,j,k,nx,ny,nz,index,nx*ny*nz); 
-//#endif
+  int index = i * ny * nz + j * nz + k;
+#ifdef SWIFT_DEBUG_CHECKS
+  assert(i < nx);
+  assert(j < ny);
+  assert(k < nz);
+#endif
   return index;
 }
 
@@ -80,10 +89,14 @@ __attribute__((always_inline)) INLINE int row_major_index_4d(int i, int j,
                                                               int k, int l, 
 							      int nx, int ny, 
 							      int nz, int nw) {
-  int index = (i % nx) * ny * nz * nw + (j % ny) * nz * nw + (k % nz) * nw + (l % nw);
-//#ifdef SWIFT_DEBUG_CHECKS
-//  if (index >= nx*ny*nz*nw) fprintf(stderr, "row_major_index_4d out of bounds, i, j, k, l, nx, ny, nz, nw, index, nx*ny*nz*nw %d, %d, %d, %d, %d, %d, %d, %d, %d, %d \n",i,j,k,l,nx,ny,nz,nw,index,nx*ny*nz*nw); 
-//#endif
+  int index = i * ny * nz * nw + j * nz * nw + k * nw + l;
+#ifdef SWIFT_DEBUG_CHECKS
+  //printf("Eagle cooling.h j, ny %d %d\n",j,ny);
+  assert(i < nx);
+  assert(j < ny);
+  assert(k < nz);
+  assert(l < nw);
+#endif
   return index;
 }
 
@@ -118,6 +131,60 @@ __attribute__((always_inline)) INLINE void get_index_1d(float *table, int ntable
   }
 }
 
+/*
+ * ----------------------------------------------------------------------
+ * Get cooling table redshift index
+ * ----------------------------------------------------------------------
+ */
+
+__attribute__((always_inline)) INLINE void get_redshift_index(float z, int *z_index, float *dz, const struct cooling_function_data* restrict cooling) {
+  int i, iz;
+
+  if (get_redshift_index_first_call == 0) {
+    get_redshift_index_first_call = 1;
+    get_redshift_index_previous = cooling->N_Redshifts - 2;
+
+    /* this routine assumes cooling_redshifts table is in increasing order. Test
+     * this. */
+    for (i = 0; i < cooling->N_Redshifts - 2; i++)
+      if (cooling->Redshifts[i + 1] < cooling->Redshifts[i]) {
+        error("[get_redshift_index]: table should be in increasing order\n");
+      }
+  }
+
+  /* before the earliest redshift or before hydrogen reionization, flag for
+   * collisional cooling */
+  if (z > cooling->reionisation_redshift) {
+    *z_index = cooling->N_Redshifts;
+    *dz = 0.0;
+  }
+  /* from reionization use the cooling tables */
+  else if (z > cooling->Redshifts[cooling->N_Redshifts - 1] &&
+           z <= cooling->reionisation_redshift) {
+    *z_index = cooling->N_Redshifts + 1;
+    *dz = 0.0;
+  }
+  /* at the end, just use the last value */
+  else if (z <= cooling->Redshifts[0]) {
+    *z_index = 0;
+    *dz = 0.0;
+  } else {
+    /* start at the previous index and search */
+    for (iz = get_redshift_index_previous; iz >= 0; iz--) {
+      if (z > cooling->Redshifts[iz]) {
+        *dz = (z - cooling->Redshifts[iz]) /
+              (cooling->Redshifts[iz + 1] - cooling->Redshifts[iz]);
+
+        get_redshift_index_previous = *z_index = iz;
+
+        break;
+      }
+    //printf("Eagle cooling.h z, z_index, z_index_previous, redshifts grid elem, dz %.5e %d %d %.5e %.5e %.5e\n", z,iz,get_redshift_index_previous,*dz, cooling->Redshifts[iz], cooling->Redshifts[iz+1]);
+    }
+  }
+}
+
+
 /*
  * ----------------------------------------------------------------------
  * This routine performs a linear interpolation
@@ -160,12 +227,12 @@ __attribute__((always_inline)) INLINE float interpol_2d(float *table, int i, int
   index[1] = row_major_index_2d(i,j+1,nx,ny);
   index[2] = row_major_index_2d(i+1,j,nx,ny);
   index[3] = row_major_index_2d(i+1,j+1,nx,ny);
-//#ifdef SWIFT_DEBUG_CHECKS
-//  if(index[0] >= nx*ny || index[0] < 0) fprintf(stderr,"index 0 out of bounds %d, i,j %d, %d, table size %d\n", index[0],i,j,nx*ny);
-//  if(index[1] >= nx*ny || index[1] < 0) fprintf(stderr,"index 1 out of bounds %d, i,j %d, %d, table size %d\n", index[1],i,j+1,nx*ny);
-//  if(index[2] >= nx*ny || index[2] < 0) fprintf(stderr,"index 2 out of bounds %d, i,j %d, %d, table size %d\n", index[2],i+1,j,nx*ny);
-//  if(index[3] >= nx*ny || index[3] < 0) fprintf(stderr,"index 3 out of bounds %d, i,j %d, %d, table size %d\n", index[3],i+1,j+1,nx*ny);
-//#endif
+#ifdef SWIFT_DEBUG_CHECKS
+  if(index[0] >= nx*ny || index[0] < 0) fprintf(stderr,"index 0 out of bounds %d, i,j %d, %d, table size %d\n", index[0],i,j,nx*ny);
+  if(index[1] >= nx*ny || index[1] < 0) fprintf(stderr,"index 1 out of bounds %d, i,j %d, %d, table size %d\n", index[1],i,j+1,nx*ny);
+  if(index[2] >= nx*ny || index[2] < 0) fprintf(stderr,"index 2 out of bounds %d, i,j %d, %d, table size %d\n", index[2],i+1,j,nx*ny);
+  if(index[3] >= nx*ny || index[3] < 0) fprintf(stderr,"index 3 out of bounds %d, i,j %d, %d, table size %d\n", index[3],i+1,j+1,nx*ny);
+#endif
 
   result = (1 - dx) * (1 - dy) * table[index[0]] + (1 - dx) * dy * table[index[1]] +
            dx * (1 - dy) * table[index[2]] + dx * dy * table[index[3]];
@@ -187,12 +254,12 @@ __attribute__((always_inline)) INLINE double interpol_2d_dbl(double *table, int
   index[1] = row_major_index_2d(i,j+1,nx,ny);
   index[2] = row_major_index_2d(i+1,j,nx,ny);
   index[3] = row_major_index_2d(i+1,j+1,nx,ny);
-//#ifdef SWIFT_DEBUG_CHECKS
-//  if(index[0] >= nx*ny || index[0] < 0) fprintf(stderr,"index 0 out of bounds %d, i,j %d, %d, table size %d\n", index[0],i,j,nx*ny);
-//  if(index[1] >= nx*ny || index[1] < 0) fprintf(stderr,"index 1 out of bounds %d, i,j %d, %d, table size %d\n", index[1],i,j+1,nx*ny);
-//  if(index[2] >= nx*ny || index[2] < 0) fprintf(stderr,"index 2 out of bounds %d, i,j %d, %d, table size %d\n", index[2],i+1,j,nx*ny);
-//  if(index[3] >= nx*ny || index[3] < 0) fprintf(stderr,"index 3 out of bounds %d, i,j %d, %d, table size %d\n", index[3],i+1,j+1,nx*ny);
-//#endif
+#ifdef SWIFT_DEBUG_CHECKS
+  if(index[0] >= nx*ny || index[0] < 0) fprintf(stderr,"index 0 out of bounds %d, i,j %d, %d, table size %d\n", index[0],i,j,nx*ny);
+  if(index[1] >= nx*ny || index[1] < 0) fprintf(stderr,"index 1 out of bounds %d, i,j %d, %d, table size %d\n", index[1],i,j+1,nx*ny);
+  if(index[2] >= nx*ny || index[2] < 0) fprintf(stderr,"index 2 out of bounds %d, i,j %d, %d, table size %d\n", index[2],i+1,j,nx*ny);
+  if(index[3] >= nx*ny || index[3] < 0) fprintf(stderr,"index 3 out of bounds %d, i,j %d, %d, table size %d\n", index[3],i+1,j+1,nx*ny);
+#endif
 
   result = (1 - dx) * (1 - dy) * table[index[0]] + (1 - dx) * dy * table[index[1]] +
            dx * (1 - dy) * table[index[2]] + dx * dy * table[index[3]];
@@ -219,16 +286,16 @@ __attribute__((always_inline)) INLINE float interpol_3d(float *table, int i, int
   index[5] = row_major_index_3d(i+1,j,k+1,nx,ny,nz);
   index[6] = row_major_index_3d(i+1,j+1,k,nx,ny,nz);
   index[7] = row_major_index_3d(i+1,j+1,k+1,nx,ny,nz);
-//#ifdef SWIFT_DEBUG_CHECKS
-//  if(index[0] >= nx*ny*nz || index[0] < 0) fprintf(stderr,"index 0 out of bounds %d, i,j,k %d, %d, %d, table size %d\n", index[0],i,j,k,nx*ny*nz);
-//  if(index[1] >= nx*ny*nz || index[1] < 0) fprintf(stderr,"index 1 out of bounds %d, i,j,k %d, %d, %d, table size %d\n", index[1],i,j,k+1,nx*ny*nz);
-//  if(index[2] >= nx*ny*nz || index[2] < 0) fprintf(stderr,"index 2 out of bounds %d, i,j,k %d, %d, %d, table size %d\n", index[2],i,j+1,k,nx*ny*nz);
-//  if(index[3] >= nx*ny*nz || index[3] < 0) fprintf(stderr,"index 3 out of bounds %d, i,j,k %d, %d, %d, table size %d\n", index[3],i,j+1,k+1,nx*ny*nz);
-//  if(index[4] >= nx*ny*nz || index[4] < 0) fprintf(stderr,"index 4 out of bounds %d, i,j,k %d, %d, %d, table size %d\n", index[4],i+1,j,k,nx*ny*nz);
-//  if(index[5] >= nx*ny*nz || index[5] < 0) fprintf(stderr,"index 5 out of bounds %d, i,j,k %d, %d, %d, table size %d\n", index[5],i+1,j,k+1,nx*ny*nz);
-//  if(index[6] >= nx*ny*nz || index[6] < 0) fprintf(stderr,"index 6 out of bounds %d, i,j,k %d, %d, %d, table size %d\n", index[6],i+1,j+1,k,nx*ny*nz);
-//  if(index[7] >= nx*ny*nz || index[7] < 0) fprintf(stderr,"index 7 out of bounds %d, i,j,k %d, %d, %d, table size %d\n", index[7],i+1,j+1,k+1,nx*ny*nz);
-//#endif
+#ifdef SWIFT_DEBUG_CHECKS
+  if(index[0] >= nx*ny*nz || index[0] < 0) fprintf(stderr,"index 0 out of bounds %d, i,j,k %d, %d, %d, table size %d\n", index[0],i,j,k,nx*ny*nz);
+  if(index[1] >= nx*ny*nz || index[1] < 0) fprintf(stderr,"index 1 out of bounds %d, i,j,k %d, %d, %d, table size %d\n", index[1],i,j,k+1,nx*ny*nz);
+  if(index[2] >= nx*ny*nz || index[2] < 0) fprintf(stderr,"index 2 out of bounds %d, i,j,k %d, %d, %d, table size %d\n", index[2],i,j+1,k,nx*ny*nz);
+  if(index[3] >= nx*ny*nz || index[3] < 0) fprintf(stderr,"index 3 out of bounds %d, i,j,k %d, %d, %d, table size %d\n", index[3],i,j+1,k+1,nx*ny*nz);
+  if(index[4] >= nx*ny*nz || index[4] < 0) fprintf(stderr,"index 4 out of bounds %d, i,j,k %d, %d, %d, table size %d\n", index[4],i+1,j,k,nx*ny*nz);
+  if(index[5] >= nx*ny*nz || index[5] < 0) fprintf(stderr,"index 5 out of bounds %d, i,j,k %d, %d, %d, table size %d\n", index[5],i+1,j,k+1,nx*ny*nz);
+  if(index[6] >= nx*ny*nz || index[6] < 0) fprintf(stderr,"index 6 out of bounds %d, i,j,k %d, %d, %d, table size %d\n", index[6],i+1,j+1,k,nx*ny*nz);
+  if(index[7] >= nx*ny*nz || index[7] < 0) fprintf(stderr,"index 7 out of bounds %d, i,j,k %d, %d, %d, table size %d\n", index[7],i+1,j+1,k+1,nx*ny*nz);
+#endif
 
   result = (1 - dx) * (1 - dy) * (1 - dz) * table[index[0]] +
            (1 - dx) * (1 - dy) * dz * table[index[1]] +
@@ -269,24 +336,24 @@ __attribute__((always_inline)) INLINE float interpol_4d(float *table, int i, int
   index[13] = row_major_index_4d(i+1,j+1,k,l+1,nx,ny,nz,nw);
   index[14] = row_major_index_4d(i+1,j+1,k+1,l,nx,ny,nz,nw);
   index[15] = row_major_index_4d(i+1,j+1,k+1,l+1,nx,ny,nz,nw);
-//#ifdef SWIFT_DEBUG_CHECKS
-//  if(index[0] >= nx*ny*nz*nw || index[0] < 0) fprintf(stderr,"index 0 out of bounds %d, i,j,k,l, %d, %d, %d, %d, table size %d\n", index[0],i,j,k,l,nx*ny*nz*nw);
-//  if(index[1] >= nx*ny*nz*nw || index[1] < 0) fprintf(stderr,"index 1 out of bounds %d, i,j,k,l, %d, %d, %d, %d, table size %d\n", index[1],i,j,k,l+1,nx*ny*nz*nw);
-//  if(index[2] >= nx*ny*nz*nw || index[2] < 0) fprintf(stderr,"index 2 out of bounds %d, i,j,k,l, %d, %d, %d, %d, table size %d\n", index[2],i,j,k+1,l,nx*ny*nz*nw);
-//  if(index[3] >= nx*ny*nz*nw || index[3] < 0) fprintf(stderr,"index 3 out of bounds %d, i,j,k,l, %d, %d, %d, %d, table size %d\n", index[3],i,j,k+1,l+1,nx*ny*nz*nw);
-//  if(index[4] >= nx*ny*nz*nw || index[4] < 0) fprintf(stderr,"index 4 out of bounds %d, i,j,k,l, %d, %d, %d, %d, table size %d\n", index[4],i,j+1,k,l,nx*ny*nz*nw);
-//  if(index[5] >= nx*ny*nz*nw || index[5] < 0) fprintf(stderr,"index 5 out of bounds %d, i,j,k,l, %d, %d, %d, %d, table size %d\n", index[5],i,j+1,k,l+1,nx*ny*nz*nw);
-//  if(index[6] >= nx*ny*nz*nw || index[6] < 0) fprintf(stderr,"index 6 out of bounds %d, i,j,k,l, %d, %d, %d, %d, table size %d\n", index[6],i,j+1,k+1,l,nx*ny*nz*nw);
-//  if(index[7] >= nx*ny*nz*nw || index[7] < 0) fprintf(stderr,"index 7 out of bounds %d, i,j,k,l, %d, %d, %d, %d, table size %d\n", index[7],i,j+1,k+1,l+1,nx*ny*nz*nw);
-//  if(index[8] >= nx*ny*nz*nw || index[8] < 0) fprintf(stderr,"index 8 out of bounds %d, i,j,k,l, %d, %d, %d, %d, table size %d\n", index[8],i+1,j,k,l,nx*ny*nz*nw);
-//  if(index[9] >= nx*ny*nz*nw || index[9] < 0) fprintf(stderr,"index 9 out of bounds %d, i,j,k,l, %d, %d, %d, %d, table size %d\n", index[9],i+1,j,k,l+1,nx*ny*nz*nw);
-//  if(index[10] >= nx*ny*nz*nw || index[10] < 0) fprintf(stderr,"index 10 out of bounds %d, i,j,k,l, %d, %d, %d, %d, table size %d\n", index[10],i+1,j,k+1,l,nx*ny*nz*nw);
-//  if(index[11] >= nx*ny*nz*nw || index[11] < 0) fprintf(stderr,"index 11 out of bounds %d, i,j,k,l, %d, %d, %d, %d, table size %d\n", index[11],i+1,j,k+1,l+1,nx*ny*nz*nw);
-//  if(index[12] >= nx*ny*nz*nw || index[12] < 0) fprintf(stderr,"index 12 out of bounds %d, i,j,k,l, %d, %d, %d, %d, table size %d\n", index[12],i+1,j+1,k,l,nx*ny*nz*nw);
-//  if(index[13] >= nx*ny*nz*nw || index[13] < 0) fprintf(stderr,"index 13 out of bounds %d, i,j,k,l, %d, %d, %d, %d, table size %d\n", index[13],i+1,j+1,k,l+1,nx*ny*nz*nw);
-//  if(index[14] >= nx*ny*nz*nw || index[14] < 0) fprintf(stderr,"index 14 out of bounds %d, i,j,k,l, %d, %d, %d, %d, table size %d\n", index[14],i+1,j+1,k+1,l,nx*ny*nz*nw);
-//  if(index[15] >= nx*ny*nz*nw || index[15] < 0) fprintf(stderr,"index 15 out of bounds %d, i,j,k,l, %d, %d, %d, %d, table size %d\n", index[15],i+1,j+1,k+1,l+1,nx*ny*nz*nw);
-//#endif
+#ifdef SWIFT_DEBUG_CHECKS
+  if(index[0] >= nx*ny*nz*nw || index[0] < 0) fprintf(stderr,"index 0 out of bounds %d, i,j,k,l, %d, %d, %d, %d, table size %d\n", index[0],i,j,k,l,nx*ny*nz*nw);
+  if(index[1] >= nx*ny*nz*nw || index[1] < 0) fprintf(stderr,"index 1 out of bounds %d, i,j,k,l, %d, %d, %d, %d, table size %d\n", index[1],i,j,k,l+1,nx*ny*nz*nw);
+  if(index[2] >= nx*ny*nz*nw || index[2] < 0) fprintf(stderr,"index 2 out of bounds %d, i,j,k,l, %d, %d, %d, %d, table size %d\n", index[2],i,j,k+1,l,nx*ny*nz*nw);
+  if(index[3] >= nx*ny*nz*nw || index[3] < 0) fprintf(stderr,"index 3 out of bounds %d, i,j,k,l, %d, %d, %d, %d, table size %d\n", index[3],i,j,k+1,l+1,nx*ny*nz*nw);
+  if(index[4] >= nx*ny*nz*nw || index[4] < 0) fprintf(stderr,"index 4 out of bounds %d, i,j,k,l, %d, %d, %d, %d, table size %d\n", index[4],i,j+1,k,l,nx*ny*nz*nw);
+  if(index[5] >= nx*ny*nz*nw || index[5] < 0) fprintf(stderr,"index 5 out of bounds %d, i,j,k,l, %d, %d, %d, %d, table size %d\n", index[5],i,j+1,k,l+1,nx*ny*nz*nw);
+  if(index[6] >= nx*ny*nz*nw || index[6] < 0) fprintf(stderr,"index 6 out of bounds %d, i,j,k,l, %d, %d, %d, %d, table size %d\n", index[6],i,j+1,k+1,l,nx*ny*nz*nw);
+  if(index[7] >= nx*ny*nz*nw || index[7] < 0) fprintf(stderr,"index 7 out of bounds %d, i,j,k,l, %d, %d, %d, %d, table size %d\n", index[7],i,j+1,k+1,l+1,nx*ny*nz*nw);
+  if(index[8] >= nx*ny*nz*nw || index[8] < 0) fprintf(stderr,"index 8 out of bounds %d, i,j,k,l, %d, %d, %d, %d, table size %d\n", index[8],i+1,j,k,l,nx*ny*nz*nw);
+  if(index[9] >= nx*ny*nz*nw || index[9] < 0) fprintf(stderr,"index 9 out of bounds %d, i,j,k,l, %d, %d, %d, %d, table size %d\n", index[9],i+1,j,k,l+1,nx*ny*nz*nw);
+  if(index[10] >= nx*ny*nz*nw || index[10] < 0) fprintf(stderr,"index 10 out of bounds %d, i,j,k,l, %d, %d, %d, %d, table size %d\n", index[10],i+1,j,k+1,l,nx*ny*nz*nw);
+  if(index[11] >= nx*ny*nz*nw || index[11] < 0) fprintf(stderr,"index 11 out of bounds %d, i,j,k,l, %d, %d, %d, %d, table size %d\n", index[11],i+1,j,k+1,l+1,nx*ny*nz*nw);
+  if(index[12] >= nx*ny*nz*nw || index[12] < 0) fprintf(stderr,"index 12 out of bounds %d, i,j,k,l, %d, %d, %d, %d, table size %d\n", index[12],i+1,j+1,k,l,nx*ny*nz*nw);
+  if(index[13] >= nx*ny*nz*nw || index[13] < 0) fprintf(stderr,"index 13 out of bounds %d, i,j,k,l, %d, %d, %d, %d, table size %d\n", index[13],i+1,j+1,k,l+1,nx*ny*nz*nw);
+  if(index[14] >= nx*ny*nz*nw || index[14] < 0) fprintf(stderr,"index 14 out of bounds %d, i,j,k,l, %d, %d, %d, %d, table size %d\n", index[14],i+1,j+1,k+1,l,nx*ny*nz*nw);
+  if(index[15] >= nx*ny*nz*nw || index[15] < 0) fprintf(stderr,"index 15 out of bounds %d, i,j,k,l, %d, %d, %d, %d, table size %d\n", index[15],i+1,j+1,k+1,l+1,nx*ny*nz*nw);
+#endif
 
   result = (1 - dx) * (1 - dy) * (1 - dz) * (1 - dw) * table[index[0]] +
            (1 - dx) * (1 - dy) * (1 - dz) * dw * table[index[1]] +
@@ -308,6 +375,86 @@ __attribute__((always_inline)) INLINE float interpol_4d(float *table, int i, int
   return result;
 }
 
+__attribute__((always_inline)) INLINE static void construct_1d_table_from_3d(const struct part* restrict p,const struct cooling_function_data* restrict cooling,const struct cosmology* restrict cosmo, const struct phys_const *internal_const, float *table,float *result_table){
+  int index[4];
+  int He_i, n_h_i, z_i;
+  float d_He, d_n_h, d_z;
+  float inHe = p->chemistry_data.metal_mass_fraction[chemistry_element_He]/(p->chemistry_data.metal_mass_fraction[chemistry_element_H]+p->chemistry_data.metal_mass_fraction[chemistry_element_He]);
+  float inn_h = chemistry_get_number_density(p,cosmo,chemistry_element_H,internal_const)*cooling->number_density_scale;
+  
+  get_redshift_index(cosmo->z,&z_i,&d_z,cooling);	
+  get_index_1d(cooling->HeFrac, cooling->N_He, inHe, &He_i, &d_He);
+  get_index_1d(cooling->nH, cooling->N_nH, log10(inn_h), &n_h_i, &d_n_h);
+
+  for(int i = 0; i < cooling->N_Temp; i++){
+    index[0] = row_major_index_3d(z_i,   n_h_i,   i, cooling->N_Redshifts, cooling->N_nH, cooling->N_Temp);
+    index[1] = row_major_index_3d(z_i,   n_h_i+1, i, cooling->N_Redshifts, cooling->N_nH, cooling->N_Temp);
+    index[2] = row_major_index_3d(z_i+1, n_h_i,   i, cooling->N_Redshifts, cooling->N_nH, cooling->N_Temp);
+    index[3] = row_major_index_3d(z_i+1, n_h_i+1, i, cooling->N_Redshifts, cooling->N_nH, cooling->N_Temp);
+    
+    result_table[i] = (1 - d_z) * (1 - d_n_h) * table[index[0]] +
+                      (1 - d_z) * d_n_h       * table[index[1]] +
+                      d_z       * (1 - d_n_h) * table[index[2]] +
+                      d_z       * d_n_h       * table[index[3]];
+  }
+}
+
+__attribute__((always_inline)) INLINE static void construct_1d_table_from_4d(const struct part* restrict p,const struct cooling_function_data* restrict cooling,const struct cosmology* restrict cosmo, const struct phys_const *internal_const, float *table,float *result_table){
+  int index[8];
+  int He_i, n_h_i, z_i;
+  float d_He, d_n_h, d_z;
+  float inHe = p->chemistry_data.metal_mass_fraction[chemistry_element_He]/(p->chemistry_data.metal_mass_fraction[chemistry_element_H]+p->chemistry_data.metal_mass_fraction[chemistry_element_He]);
+  float inn_h = chemistry_get_number_density(p,cosmo,chemistry_element_H,internal_const)*cooling->number_density_scale;
+  
+  get_redshift_index(cosmo->z,&z_i,&d_z,cooling);	
+  get_index_1d(cooling->HeFrac, cooling->N_He, inHe, &He_i, &d_He);
+  get_index_1d(cooling->nH, cooling->N_nH, log10(inn_h), &n_h_i, &d_n_h);
+
+  for(int i = 0; i < cooling->N_Temp; i++){
+    index[0] = row_major_index_4d(z_i,   n_h_i,   He_i,   i, cooling->N_Redshifts, cooling->N_nH, cooling->N_He, cooling->N_Temp);
+    index[1] = row_major_index_4d(z_i,   n_h_i,   He_i+1, i, cooling->N_Redshifts, cooling->N_nH, cooling->N_He, cooling->N_Temp);
+    index[2] = row_major_index_4d(z_i,   n_h_i+1, He_i,   i, cooling->N_Redshifts, cooling->N_nH, cooling->N_He, cooling->N_Temp);
+    index[3] = row_major_index_4d(z_i,   n_h_i+1, He_i+1, i, cooling->N_Redshifts, cooling->N_nH, cooling->N_He, cooling->N_Temp);
+    index[4] = row_major_index_4d(z_i+1, n_h_i,   He_i,   i, cooling->N_Redshifts, cooling->N_nH, cooling->N_He, cooling->N_Temp);
+    index[5] = row_major_index_4d(z_i+1, n_h_i,   He_i+1, i, cooling->N_Redshifts, cooling->N_nH, cooling->N_He, cooling->N_Temp);
+    index[6] = row_major_index_4d(z_i+1, n_h_i+1, He_i,   i, cooling->N_Redshifts, cooling->N_nH, cooling->N_He, cooling->N_Temp);
+    index[7] = row_major_index_4d(z_i+1, n_h_i+1, He_i+1, i, cooling->N_Redshifts, cooling->N_nH, cooling->N_He, cooling->N_Temp);
+    
+    result_table[i] = (1 - d_z) * (1 - d_n_h) * (1 - d_He) * table[index[0]] +
+                      (1 - d_z) * (1 - d_n_h) * d_He       * table[index[1]] +
+                      (1 - d_z) * d_n_h       * (1 - d_He) * table[index[2]] +
+                      (1 - d_z) * d_n_h       * d_He       * table[index[3]] +
+                      d_z       * (1 - d_n_h) * (1 - d_He) * table[index[4]] +
+                      d_z       * (1 - d_n_h) * d_He       * table[index[5]] +
+                      d_z       * d_n_h       * (1 - d_He) * table[index[6]] +
+                      d_z       * d_n_h       * d_He       * table[index[7]];
+  }
+}
+
+__attribute__((always_inline)) INLINE static void construct_1d_table_from_4d_elements(const struct part* restrict p,const struct cooling_function_data* restrict cooling,const struct cosmology* restrict cosmo, const struct phys_const *internal_const, float *table,float *result_table){
+  int index[4];
+  int n_h_i, z_i;
+  float d_n_h, d_z;
+  float inn_h = chemistry_get_number_density(p,cosmo,chemistry_element_H,internal_const)*cooling->number_density_scale;
+  
+  get_redshift_index(cosmo->z,&z_i,&d_z,cooling);	
+  get_index_1d(cooling->nH, cooling->N_nH, log10(inn_h), &n_h_i, &d_n_h);
+
+  for(int j = 0; j < cooling->N_Elements; j++){
+    for(int i = 0; i < cooling->N_Temp; i++){
+      index[0] = row_major_index_4d(z_i,   j, n_h_i,   i, cooling->N_Redshifts, cooling->N_Elements, cooling->N_nH, cooling->N_Temp);
+      index[1] = row_major_index_4d(z_i,   j, n_h_i+1, i, cooling->N_Redshifts, cooling->N_Elements, cooling->N_nH, cooling->N_Temp);
+      index[2] = row_major_index_4d(z_i+1, j, n_h_i,   i, cooling->N_Redshifts, cooling->N_Elements, cooling->N_nH, cooling->N_Temp);
+      index[3] = row_major_index_4d(z_i+1, j, n_h_i+1, i, cooling->N_Redshifts, cooling->N_Elements, cooling->N_nH, cooling->N_Temp);
+      
+      result_table[i+j*cooling->N_Temp] = (1 - d_z) * (1 - d_n_h) * table[index[0]] +
+                                          (1 - d_z) * d_n_h       * table[index[1]] +
+                                          d_z       * (1 - d_n_h) * table[index[2]] +
+                                          d_z       * d_n_h       * table[index[3]];
+    }
+  }
+}
+
 inline int set_cooling_SolarAbundances(const float *element_abundance,
                                 double *cooling_element_abundance,
                                 const struct cooling_function_data* restrict cooling,
@@ -421,59 +568,6 @@ inline int set_cooling_SolarAbundances(const float *element_abundance,
 }
 
 
-/*
- * ----------------------------------------------------------------------
- * Get cooling table redshift index
- * ----------------------------------------------------------------------
- */
-
-__attribute__((always_inline)) INLINE void get_redshift_index(float z, int *z_index, float *dz, const struct cooling_function_data* restrict cooling) {
-  int i, iz;
-
-  if (get_redshift_index_first_call == 0) {
-    get_redshift_index_first_call = 1;
-    get_redshift_index_previous = cooling->N_Redshifts - 2;
-
-    /* this routine assumes cooling_redshifts table is in increasing order. Test
-     * this. */
-    for (i = 0; i < cooling->N_Redshifts - 2; i++)
-      if (cooling->Redshifts[i + 1] < cooling->Redshifts[i]) {
-        error("[get_redshift_index]: table should be in increasing order\n");
-      }
-  }
-
-  /* before the earliest redshift or before hydrogen reionization, flag for
-   * collisional cooling */
-  if (z > cooling->reionisation_redshift) {
-    *z_index = cooling->N_Redshifts;
-    *dz = 0.0;
-  }
-  /* from reionization use the cooling tables */
-  else if (z > cooling->Redshifts[cooling->N_Redshifts - 1] &&
-           z <= cooling->reionisation_redshift) {
-    *z_index = cooling->N_Redshifts + 1;
-    *dz = 0.0;
-  }
-  /* at the end, just use the last value */
-  else if (z <= cooling->Redshifts[0]) {
-    *z_index = 0;
-    *dz = 0.0;
-  } else {
-    /* start at the previous index and search */
-    for (iz = get_redshift_index_previous; iz >= 0; iz--) {
-      if (z > cooling->Redshifts[iz]) {
-        *dz = (z - cooling->Redshifts[iz]) /
-              (cooling->Redshifts[iz + 1] - cooling->Redshifts[iz]);
-
-        get_redshift_index_previous = *z_index = iz;
-
-        break;
-      }
-    //printf("Eagle cooling.h z, z_index, z_index_previous, redshifts grid elem, dz %.5e %d %d %.5e %.5e %.5e\n", z,iz,get_redshift_index_previous,*dz, cooling->Redshifts[iz], cooling->Redshifts[iz+1]);
-    }
-  }
-}
-
 
 /*
  * @brief interpolates temperature from internal energy based on table
@@ -494,14 +588,20 @@ __attribute__((always_inline)) INLINE static double eagle_convert_u_to_temp(doub
   get_redshift_index(z,&z_index,&dz,cooling);	
   get_index_1d(cooling->HeFrac, cooling->N_He, inHe, &He_i, &d_He);
   get_index_1d(cooling->nH, cooling->N_nH, log10(inn_h), &n_h_i, &d_n_h);
+#ifdef SWIFT_DEBUG_CHECKS
+      if (isnan(u)) printf("Eagle cooling.h convert u to temp u is nan");
+      if (log10(u) <= cooling->Therm[0]) printf("Eagle cooling.h convert u to temp particle id, u, u_min %llu %.5e %.5e\n", p->id, u, cooling->Therm[0]);
+      if (log10(u) >= cooling->Therm[cooling->N_Temp - 1]) printf("Eagle cooling.h convert u to temp particle id, u, u_max %llu %.5e %.5e\n", p->id, u, cooling->Therm[cooling->N_Temp - 1]);
+#endif
   get_index_1d(cooling->Therm, cooling->N_Temp, log10(u), &u_i, &d_u);
+
   
   //logT = interpol_2d(cooling->table.collisional_cooling.temperature, He_i, u_i, d_He, d_u, cooling->N_He, cooling->N_Temp);
 
   //logT = interpol_3d(cooling->table.photodissociation_cooling.temperature, He_i,
   //                   u_i, n_h_i, d_He, d_u, d_n_h,cooling->N_He,cooling->N_Temp,cooling->N_nH);
-  logT = interpol_4d(cooling->table.element_cooling.temperature,z_index, He_i,
-                     u_i, n_h_i, dz, d_He, d_u, d_n_h,cooling->N_Redshifts,cooling->N_He,cooling->N_Temp,cooling->N_nH);
+  logT = interpol_4d(cooling->table.element_cooling.temperature,z_index,
+                     n_h_i, He_i, u_i, dz, d_n_h, d_He, d_u,cooling->N_Redshifts,cooling->N_nH,cooling->N_He,cooling->N_Temp);
 
   T = pow(10.0, logT);
 
@@ -510,6 +610,133 @@ __attribute__((always_inline)) INLINE static double eagle_convert_u_to_temp(doub
   return T;
 }
 
+/*
+ * @brief calculates cooling rate
+ *
+ */
+__attribute__((always_inline)) INLINE static double eagle_metal_cooling_rate_1d_table(double u,
+									              float *H_plus_He_heat_table,
+										      float *H_plus_He_electron_abundance_table,
+										      float *element_cooling_table,
+										      float *element_electron_abundance_table,
+										      const struct part* restrict p, 
+										      const struct cooling_function_data* restrict cooling, 
+										      const struct cosmology* restrict cosmo, 
+										      const struct phys_const *internal_const, 
+										      double* element_lambda) {
+  double T_gam, solar_electron_abundance;
+  double n_h = chemistry_get_number_density(p,cosmo,chemistry_element_H,internal_const)*cooling->number_density_scale; // chemistry_data
+  double z = cosmo->z;
+  double cooling_rate = 0.0, temp_lambda;
+  float dz; 
+  int z_index;
+  float h_plus_he_electron_abundance;
+
+  int i;
+  double temp;
+  int n_h_i, He_i, temp_i;
+  float d_n_h, d_He, d_temp;
+  float HeFrac = p->chemistry_data.metal_mass_fraction[chemistry_element_He]/(p->chemistry_data.metal_mass_fraction[chemistry_element_H]+p->chemistry_data.metal_mass_fraction[chemistry_element_He]);
+  
+  get_redshift_index(z,&z_index,&dz,cooling);	
+  
+  //temp = eagle_convert_u_to_temp_1d_table(u,temp_table,p,cooling,cosmo,internal_const);
+
+  temp = eagle_convert_u_to_temp(u,p,cooling,cosmo,internal_const);
+
+  get_index_1d(cooling->Temp, cooling->N_Temp, log10(temp), &temp_i, &d_temp);
+  get_index_1d(cooling->HeFrac, cooling->N_He, HeFrac, &He_i, &d_He);
+  get_index_1d(cooling->nH, cooling->N_nH, log10(n_h), &n_h_i, &d_n_h);
+
+  /* ------------------ */
+  /* Metal-free cooling */
+  /* ------------------ */
+
+    /* Collisional cooling */
+    //element_lambda[0] =
+    //    interpol_2d(cooling->table.collisional_cooling.H_plus_He_heating, He_i,
+    //                 temp_i, d_He, d_temp,cooling->N_He,cooling->N_Temp);
+    //h_plus_he_electron_abundance =
+    //    interpol_2d(cooling->table.collisional_cooling.H_plus_He_electron_abundance, He_i,
+    //                 temp_i, d_He, d_temp,cooling->N_He,cooling->N_Temp);
+    
+    /* Photodissociation */
+    //element_lambda[0] =
+    //    interpol_3d(cooling->table.photodissociation_cooling.H_plus_He_heating, He_i,
+    //                 temp_i, n_h_i, d_He, d_temp, d_n_h,cooling->N_He,cooling->N_Temp,cooling->N_nH);
+    //h_plus_he_electron_abundance =
+    //    interpol_3d(cooling->table.photodissociation_cooling.H_plus_He_electron_abundance, He_i,
+    //                 temp_i, n_h_i, d_He, d_temp, d_n_h,cooling->N_He,cooling->N_Temp,cooling->N_nH);
+
+    /* redshift tables */
+    temp_lambda = interpol_1d(H_plus_He_heat_table, temp_i, d_temp);
+    h_plus_he_electron_abundance = interpol_1d(H_plus_He_electron_abundance_table, temp_i, d_temp);
+    cooling_rate += temp_lambda;
+    if (element_lambda != NULL) element_lambda[0] = temp_lambda;
+
+  /* ------------------ */
+  /* Compton cooling    */
+  /* ------------------ */
+
+  if (z > cooling->Redshifts[cooling->N_Redshifts - 1] ||
+      z > cooling->reionisation_redshift) {
+    /* inverse Compton cooling is not in collisional table
+       before reionisation so add now */
+
+    T_gam = eagle_cmb_temperature * (1 + z);
+
+    temp_lambda = -eagle_compton_rate * (temp - eagle_cmb_temperature * (1 + z)) * pow((1 + z), 4) *
+                 h_plus_he_electron_abundance / n_h;
+    cooling_rate += temp_lambda;
+    if (element_lambda != NULL) element_lambda[1] = temp_lambda;
+  }
+
+  /* ------------- */
+  /* Metal cooling */
+  /* ------------- */
+
+    /* for each element, find the abundance and multiply it
+       by the interpolated heating-cooling */
+
+    set_cooling_SolarAbundances(p->chemistry_data.metal_mass_fraction, cooling->solar_abundances, cooling, p);
+
+    /* Collisional cooling */
+    //solar_electron_abundance =
+    //    interpol_1d(cooling->table.collisional_cooling.electron_abundance, temp_i, d_temp); /* ne/n_h */
+
+    //for (i = 0; i < cooling->N_Elements; i++){
+    //    element_lambda[i+2] = interpol_2d(cooling->table.collisional_cooling.metal_heating, i,
+    //                    temp_i, 0.0, d_temp,cooling->N_Elements,cooling->N_Temp) *
+    //        (h_plus_he_electron_abundance / solar_electron_abundance) *
+    //        cooling->solar_abundances[i];
+    //}
+    
+    /* Photodissociation */
+    //solar_electron_abundance =
+    //    interpol_2d(cooling->table.photodissociation_cooling.electron_abundance, temp_i, n_h_i, d_temp, d_n_h, cooling->N_Temp, cooling->N_nH); /* ne/n_h */
+      
+    //for (i = 0; i < cooling->N_Elements; i++){
+    //    element_lambda[i+2] = interpol_3d(cooling->table.photodissociation_cooling.metal_heating, i,
+    //                    temp_i, n_h_i, 0.0, d_temp, d_n_h,cooling->N_Elements,cooling->N_Temp,cooling->N_nH) *
+    //        (h_plus_he_electron_abundance / solar_electron_abundance) *
+    //        cooling->solar_abundances[i];
+    //}
+    
+    /* redshift tables */
+    solar_electron_abundance = interpol_1d(element_electron_abundance_table, temp_i, d_temp);
+    
+    for (i = 0; i < cooling->N_Elements; i++){
+	//temp_lambda = interpol_1d(element_cooling_table + i*cooling->N_Temp, temp_i, d_temp) *
+	temp_lambda = interpol_1d(element_cooling_table + i*cooling->N_Temp, temp_i, d_temp) *
+            (h_plus_he_electron_abundance / solar_electron_abundance) *
+            cooling->solar_abundances[i];
+        cooling_rate += temp_lambda;
+        if (element_lambda != NULL) element_lambda[i+2] = temp_lambda;
+    }
+
+    return cooling_rate;
+}
+
 /*
  * @brief calculates cooling rate
  *
@@ -560,11 +787,11 @@ __attribute__((always_inline)) INLINE static double eagle_metal_cooling_rate(dou
 
     /* redshift tables */
     temp_lambda =
-        interpol_4d(cooling->table.element_cooling.H_plus_He_heating, z_index, He_i,
-                     temp_i, n_h_i, dz, d_He, d_temp, d_n_h,cooling->N_Redshifts,cooling->N_He,cooling->N_Temp,cooling->N_nH);
+        interpol_4d(cooling->table.element_cooling.H_plus_He_heating, z_index,
+                     n_h_i, He_i, temp_i, dz, d_n_h, d_He, d_temp,cooling->N_Redshifts,cooling->N_nH,cooling->N_He,cooling->N_Temp);
     h_plus_he_electron_abundance =
-        interpol_4d(cooling->table.element_cooling.H_plus_He_electron_abundance, z_index, He_i,
-                     temp_i, n_h_i, dz, d_He, d_temp, d_n_h,cooling->N_Redshifts,cooling->N_He,cooling->N_Temp,cooling->N_nH);
+        interpol_4d(cooling->table.element_cooling.H_plus_He_electron_abundance, z_index,
+                    n_h_i, He_i, temp_i,  dz, d_n_h, d_He, d_temp,cooling->N_Redshifts,cooling->N_nH,cooling->N_He,cooling->N_Temp);
     cooling_rate += temp_lambda;
     if (element_lambda != NULL) element_lambda[0] = temp_lambda;
 
@@ -618,20 +845,60 @@ __attribute__((always_inline)) INLINE static double eagle_metal_cooling_rate(dou
     
     /* redshift tables */
     solar_electron_abundance =
-        interpol_3d(cooling->table.element_cooling.electron_abundance, z_index, temp_i, n_h_i, dz, d_temp, d_n_h, cooling->N_Redshifts, cooling->N_Temp, cooling->N_nH); /* ne/n_h */
+        interpol_3d(cooling->table.element_cooling.electron_abundance, z_index, n_h_i, temp_i, dz, d_n_h, d_temp, cooling->N_Redshifts, cooling->N_nH, cooling->N_Temp); /* ne/n_h */
     
-    for (i = 0; i < cooling->N_Elements; i++){
+    for (i = 0; i < cooling->N_Elements - 1; i++){
         temp_lambda = interpol_4d(cooling->table.element_cooling.metal_heating, z_index, i,
-                        temp_i, n_h_i, dz, 0.0, d_temp, d_n_h,cooling->N_Redshifts,cooling->N_Elements,cooling->N_Temp,cooling->N_nH) *
+                        n_h_i, temp_i, dz, 0.0, d_n_h, d_temp,cooling->N_Redshifts,cooling->N_Elements,cooling->N_nH,cooling->N_Temp) *
             (h_plus_he_electron_abundance / solar_electron_abundance) *
             cooling->solar_abundances[i];
         cooling_rate += temp_lambda;
         if (element_lambda != NULL) element_lambda[i+2] = temp_lambda;
     }
+    // Deal with last element separately so that interpol_4d doesn't try accessing element out of bounds
+    temp_lambda = interpol_4d(cooling->table.element_cooling.metal_heating, z_index, cooling->N_Elements-2,
+                    n_h_i, temp_i, dz, 1.0, d_n_h, d_temp,cooling->N_Redshifts,cooling->N_Elements,cooling->N_nH,cooling->N_Temp) *
+        (h_plus_he_electron_abundance / solar_electron_abundance) *
+        cooling->solar_abundances[cooling->N_Elements-1];
+    cooling_rate += temp_lambda;
+    if (element_lambda != NULL) element_lambda[cooling->N_Elements+1] = temp_lambda;
 
     return cooling_rate;
 }
 
+__attribute__((always_inline)) INLINE static double eagle_cooling_rate_1d_table(double u,
+										double *dLambdaNet_du,
+									        float *H_plus_He_heat_table,
+										float *H_plus_He_electron_abundance_table,
+										float *element_cooling_table,
+										float *element_electron_abundance_table,
+										const struct part* restrict p, 
+										const struct cooling_function_data* restrict cooling, 
+										const struct cosmology* restrict cosmo, 
+										const struct phys_const *internal_const) {
+  double *element_lambda = NULL, lambda_net1 = 0.0, lambda_net2 = 0.0, delta;
+  float d_u;
+  int u_i;
+  if (log10(u) > cooling->Therm[cooling->N_Temp-1] || log10(u) < cooling->Therm[0] || isnan(u)) {
+    printf("Eagle cooling.h u %.5e \n", u);
+    fflush(stdout);
+  }
+  get_index_1d(cooling->Therm, cooling->N_Temp, log10(u), &u_i, &d_u);
+  if (u_i >= cooling->N_Temp-2){
+    delta = pow(10.0,cooling->Therm[cooling->N_Temp-2]) - u;
+  } else {
+    delta = pow(10.0,cooling->Therm[u_i+1]) - pow(10.0,cooling->Therm[u_i]);
+  }
+  delta *= 0.1;
+  //delta = pow(10.0,cooling->Therm[1]) - pow(10.0,cooling->Therm[0]);
+
+  lambda_net1 = eagle_metal_cooling_rate_1d_table(u, H_plus_He_heat_table, H_plus_He_electron_abundance_table, element_cooling_table, element_electron_abundance_table, p, cooling, cosmo, internal_const, element_lambda);
+  lambda_net2 = eagle_metal_cooling_rate_1d_table(u + delta, H_plus_He_heat_table, H_plus_He_electron_abundance_table, element_cooling_table, element_electron_abundance_table, p, cooling, cosmo, internal_const, element_lambda);
+  *dLambdaNet_du = (lambda_net2 - lambda_net1)/delta;
+  //printf("Eagle cooling.h dLambdaNet_du, lambda_net1, lambda_net2, delta_u u %.5e %.5e %.5e %.5e %.5e\n ", *dLambdaNet_du, lambda_net1, lambda_net2, delta, u);
+
+  return lambda_net1;
+}
 
 __attribute__((always_inline)) INLINE static double eagle_cooling_rate(double u, const struct part* restrict p, const struct cooling_function_data* restrict cooling, const struct cosmology* restrict cosmo, const struct phys_const *internal_const) {
   double *element_lambda = NULL, lambda_net = 0.0;
@@ -641,6 +908,42 @@ __attribute__((always_inline)) INLINE static double eagle_cooling_rate(double u,
   return lambda_net;
 }
 
+__attribute__((always_inline)) INLINE static double eagle_print_metal_cooling_rate_1d_table(float *H_plus_He_heat_table,
+											    float *H_plus_He_electron_abundance_table,
+											    float *element_cooling_table,
+											    float *element_electron_abundance_table,
+											    const struct part* restrict p, 
+											    const struct cooling_function_data* restrict cooling, 
+											    const struct cosmology* restrict cosmo, 
+											    const struct phys_const *internal_const) {
+  double *element_lambda, lambda_net = 0.0;
+  element_lambda = malloc((cooling->N_Elements+2)*sizeof(double));
+  double u = hydro_get_physical_internal_energy(p,cosmo)*cooling->internal_energy_scale;
+  
+  char output_filename[21];
+  FILE** output_file = malloc((cooling->N_Elements+2)*sizeof(FILE*));
+  for (int element = 0; element < cooling->N_Elements+2; element++){
+    sprintf(output_filename, "%s%d%s", "cooling_output_",element,".dat");
+    output_file[element] = fopen(output_filename, "a");
+    if (output_file == NULL)
+    {   
+        printf("Error opening file!\n");
+        exit(1);
+    }
+  }
+
+  for (int j = 0; j < cooling->N_Elements+2; j++) element_lambda[j] = 0.0;
+  lambda_net = eagle_metal_cooling_rate_1d_table(u, H_plus_He_heat_table, H_plus_He_electron_abundance_table, element_cooling_table, element_electron_abundance_table, p, cooling, cosmo, internal_const, element_lambda);
+  for (int j = 0; j < cooling->N_Elements+2; j++) {
+    fprintf(output_file[j],"%.5e\n",element_lambda[j]);
+  }
+  
+  for (int i = 0; i < cooling->N_Elements+2; i++) fclose(output_file[i]);
+
+  return lambda_net;
+}
+
+
 __attribute__((always_inline)) INLINE static double eagle_print_metal_cooling_rate(const struct part* restrict p, const struct cooling_function_data* restrict cooling, const struct cosmology* restrict cosmo, const struct phys_const *internal_const) {
   double *element_lambda, lambda_net = 0.0;
   element_lambda = malloc((cooling->N_Elements+2)*sizeof(double));
@@ -660,6 +963,7 @@ __attribute__((always_inline)) INLINE static double eagle_print_metal_cooling_ra
 
   for (int j = 0; j < cooling->N_Elements+2; j++) element_lambda[j] = 0.0;
   lambda_net = eagle_metal_cooling_rate(u, p, cooling, cosmo, internal_const, element_lambda);
+  //lambda_net = eagle_metal_cooling_rate_1d_table(u, H_plus_He_heat_table, H_plus_He_electron_abundance_table, element_cooling_table, element_electron_abundance_table, p, cooling, cosmo, internal_const, element_lambda);
   for (int j = 0; j < cooling->N_Elements+2; j++) {
     fprintf(output_file[j],"%.5e\n",element_lambda[j]);
   }
@@ -688,11 +992,6 @@ __attribute__((always_inline)) INLINE static void cooling_cool_part(
     struct part* restrict p, struct xpart* restrict xp, float dt) {
   
   double u_old = hydro_get_physical_internal_energy(p,cosmo)*cooling->internal_energy_scale;
-  if (u_old < 0){
-    printf("Eagle cooling.h u_old, physical u, comoving u, energy scale %.5e %.5e %.5e %.5e \n", u_old,hydro_get_physical_internal_energy(p,cosmo),hydro_get_comoving_internal_energy(p),cooling->internal_energy_scale);
-    fflush(stdout);
-  }
-  //double u_old = hydro_get_comoving_internal_energy(p)*cooling->internal_energy_scale;
   float dz; 
   int z_index;
   get_redshift_index(cosmo->z,&z_index,&dz,cooling);
@@ -700,15 +999,13 @@ __attribute__((always_inline)) INLINE static void cooling_cool_part(
   float XH, HeFrac;
   double inn_h;
 
-  double du, ratefact, u, u_upper, u_lower, LambdaNet, LambdaTune = 0;
+  double ratefact, u, LambdaNet, LambdaTune = 0;
   int i;
 
   static double zold = 100, LambdaCumul = 0;
   dt *= units_cgs_conversion_factor(us,UNIT_CONV_TIME);
 
   u = u_old;
-  u_lower = u;
-  u_upper = u;
 
   XH = p->chemistry_data.metal_mass_fraction[chemistry_element_H];
   HeFrac = p->chemistry_data.metal_mass_fraction[chemistry_element_He] / (XH + p->chemistry_data.metal_mass_fraction[chemistry_element_He]);
@@ -728,101 +1025,60 @@ __attribute__((always_inline)) INLINE static void cooling_cool_part(
     zold = z_index;
   }
 
-  /* iterative, implicit cooling */
-  if (dt > 0)
-    {
-      LambdaNet = (LambdaTune / (dt * ratefact)) + eagle_cooling_rate(u, p, cooling, cosmo, phys_const);
-    }                                                                                                                  
-  else
-    {
-      LambdaNet = eagle_cooling_rate(u, p, cooling, cosmo, phys_const);
-    }
+  // construct 1d table of cooling rates wrt temperature
+  float H_plus_He_heat_table[176]; 			// WARNING sort out how it is declared/allocated
+  float H_plus_He_electron_abundance_table[176]; 	// WARNING sort out how it is declared/allocated
+  float element_cooling_table[9*176]; 			// WARNING sort out how it is declared/allocated
+  float element_electron_abundance_table[176]; 		// WARNING sort out how it is declared/allocated
+  construct_1d_table_from_4d(p,cooling,cosmo,phys_const,cooling->table.element_cooling.H_plus_He_heating,H_plus_He_heat_table);
+  construct_1d_table_from_4d(p,cooling,cosmo,phys_const,cooling->table.element_cooling.H_plus_He_electron_abundance,H_plus_He_electron_abundance_table);
+  construct_1d_table_from_4d_elements(p,cooling,cosmo,phys_const,cooling->table.element_cooling.metal_heating,element_cooling_table);
+  construct_1d_table_from_3d(p,cooling,cosmo,phys_const,cooling->table.element_cooling.electron_abundance,element_electron_abundance_table);
 
-  if (fabs(ratefact * LambdaNet * dt) < 0.05 * u_old) {
-    /* cooling rate is small, take the explicit solution */
-    u = u_old + ratefact * LambdaNet * dt;
-  }
-  else
-  {
-    i = 0;
-
-    /* bracketing  */
-    if (u - u_old - ratefact * LambdaNet * dt < 0) /* heating  */
-      {
-        u_upper *= sqrt(1.1);
-        u_lower /= sqrt(1.1);
-
-        while (u_upper - u_old - LambdaTune - ratefact * eagle_cooling_rate(u_upper, p, cooling, cosmo, phys_const) * dt < 0
-               && i < eagle_max_iterations) {
-          u_upper *= 1.1;
-          u_lower *= 1.1;
-          i++;
-        }
-      }
+  i = 0;
 
-    //if (i == eagle_max_iterations) printf("Problem with cooling finding upper bound\n");
+  double u_ini = u_old, dLambdaNet_du;
+  do /* iterate to convergence */
+    {
 #ifdef SWIFT_DEBUG_CHECKS
-    //if (i < eagle_max_iterations) printf("Eagle cooling.h heating bound converged number of iterations, u_upper, u_lower, u, u_old, cooling %d %.8e %.8e %.8e %.8e %.8e\n", i, u_upper, u_lower, u, u_old,ratefact*eagle_cooling_rate(u_upper, p,cooling,cosmo,phys_const)*dt);
-    if (i == eagle_max_iterations){
-      printf("Problem with cooling finding upper bound, u_upper, u_lower, u, u_old, cooling %.5e %.5e %.5e %.5e %.5e\n", u_upper, u_lower, u, u_old,ratefact*eagle_cooling_rate(u_upper, p,cooling,cosmo,phys_const)*dt);
-    }
+      if (isnan(u)) printf("Eagle cooling.h u is nan");
+      //if (log10(u) <= cooling->Therm[0]) printf("Eagle cooling.h particle id, iteration, u, u_max %llu %d %.5e %.5e\n", p->id, i, u, cooling->Therm[0]);
+      //if (log10(u) >= cooling->Therm[cooling->N_Temp - 1]) printf("Eagle cooling.h particle id, iteration, u, u_max %llu %d %.5e %.5e\n", p->id, i, u, cooling->Therm[cooling->N_Temp - 1]);
 #endif
-
-    if (u - u_old - ratefact * LambdaNet * dt > 0) /* cooling */
-      {
-        u_lower /= sqrt(1.1);
-        u_upper *= sqrt(1.1);
-
-        i = 0;
-
-        while(u_lower - u_old - LambdaTune - ratefact * eagle_cooling_rate(u_lower, p, cooling, cosmo, phys_const) * dt > 0
-              && i < eagle_max_iterations)
-          {
-            u_upper /= 1.1;
-            u_lower /= 1.1;
-            i++;
-          }
+      if (i == 0) {
+        u_old = 2.0e11;
+      } else {
+        u_old = u;
       }
 
-#ifdef SWIFT_DEBUG_CHECKS
-    //if (i < eagle_max_iterations) printf("Eagle cooling.h cooling bound converged number of iterations, u_upper, u_lower, u, u_old, cooling %d %.8e %.8e %.8e %.8e %.8e\n", i, u_upper, u_lower, u, u_old,ratefact*eagle_cooling_rate(u_lower, p,cooling,cosmo,phys_const)*dt);
-    if (i == eagle_max_iterations){
-      printf("Problem with cooling finding lower bound, u_upper, u_lower, u, u_old, cooling %.5e %.5e %.5e %.5e %.5e\n", u_upper, u_lower, u, u_old,ratefact*eagle_cooling_rate(u_lower, p,cooling,cosmo,phys_const)*dt);
-    }
-#endif
-
-    i = 0;
-
-    do /* iterate to convergence */
-      {
-        u = 0.5 * (u_lower + u_upper);
-
-        LambdaNet = (LambdaTune / (dt * ratefact)) + eagle_cooling_rate(u, p, cooling, cosmo, phys_const);
+      LambdaNet = (LambdaTune / (dt * ratefact)) + eagle_cooling_rate_1d_table(u_old, &dLambdaNet_du, H_plus_He_heat_table, H_plus_He_electron_abundance_table, element_cooling_table, element_electron_abundance_table, p, cooling, cosmo, phys_const);
+      //n_eagle_cooling_rate_calls_1 += 2;
+      
+      u = u_old - (u_old - u_ini - LambdaNet*dt*ratefact)/(1.0 - dLambdaNet_du*dt*ratefact); // Newton's method
 
-        if (u - u_old - ratefact * LambdaNet * dt > 0)
-          u_upper = u;
-        else
-          u_lower = u;
+      i++;
 
-        du = u_upper - u_lower;
+      //if (i % 10 == 0) {
+      //  printf("Eagle cooling.h error, u, u_old, u_ini, lambda_net, dlambda_net_dt, ratefact, dt, terms, iteration %.5e %.5e %.5e %.5e %.5e %.5e %.5e %.5e %.5e %d\n", fabs((u - u_old) / u), u, u_ini, LambdaNet, dLambdaNet_du, ratefact, dt, (u_old - u_ini - LambdaNet*dt*ratefact), (1.0 - dLambdaNet_du*dt*ratefact), i);
+      //}
 
-        i++;
+      if (u < 0) {
+	printf("Eagle cooling.h particle u negative, u_old, lambda_net %llu %.5e %.5e %.5e\n", p->id, u, u_old, LambdaNet);
+	//u = pow(10.0,cooling->Therm[0]);
+      }
 
-        if (i >= (eagle_max_iterations - 10)) printf("u = %g\n", u);
-      } while (fabs(du / u) > 1.0e-6 && i < eagle_max_iterations);
-    
+    } while (fabs((u - u_old) / u) > 1.0e-5 && i < eagle_max_iterations);
+  
 #ifdef SWIFT_DEBUG_CHECKS
-    if (i >= eagle_max_iterations){
-      printf("particle ID %llu, du, u %.5e %.5e\n",p->id,du,u);
-      error("failed to converge in EagleDoCooling()\n");
-    }
-#endif
-
+  if (i >= eagle_max_iterations){
+    printf("particle ID %llu, u %.5e \n",p->id,u);
+    //error("failed to converge in EagleDoCooling()\n");
   }
+#endif
 
   float cooling_du_dt = 0.0;
   if (dt > 0){ 
-    cooling_du_dt = (u - u_old)/dt/cooling->power_scale;
+    cooling_du_dt = (u - u_ini)/dt/cooling->power_scale;
   }
 
   const float hydro_du_dt = hydro_get_internal_energy_dt(p);
@@ -835,6 +1091,192 @@ __attribute__((always_inline)) INLINE static void cooling_cool_part(
 
 }
 
+/**
+ * @brief Apply the cooling function to a particle.
+ *
+ * @param phys_const The physical constants in internal units.
+ * @param us The internal system of units.
+ * @param cosmo cosmology struct
+ * @param cooling The #cooling_function_data used in the run.
+ * @param p Pointer to the particle data.
+ * @param xp Pointer to the extended particle data.
+ * @param dt The time-step of this particle.
+ */
+//__attribute__((always_inline)) INLINE static void cooling_cool_part_eagle(
+//    const struct phys_const* restrict phys_const,
+//    const struct unit_system* restrict us,
+//    const struct cosmology* restrict cosmo,
+//    const struct cooling_function_data* restrict cooling,
+//    struct part* restrict p, struct xpart* restrict xp, float dt) {
+//  
+//  double u_old = hydro_get_physical_internal_energy(p,cosmo)*cooling->internal_energy_scale;
+//  if (u_old < 0){
+//    printf("Eagle cooling.h u_old, physical u, comoving u, energy scale %.5e %.5e %.5e %.5e \n", u_old,hydro_get_physical_internal_energy(p,cosmo),hydro_get_comoving_internal_energy(p),cooling->internal_energy_scale);
+//    fflush(stdout);
+//  }
+//  //double u_old = hydro_get_comoving_internal_energy(p)*cooling->internal_energy_scale;
+//  float dz; 
+//  int z_index;
+//  get_redshift_index(cosmo->z,&z_index,&dz,cooling);
+//
+//  float XH, HeFrac;
+//  double inn_h;
+//
+//  double du, ratefact, u, u_upper, u_lower, LambdaNet, LambdaTune = 0;
+//  int i;
+//
+//  static double zold = 100, LambdaCumul = 0;
+//  dt *= units_cgs_conversion_factor(us,UNIT_CONV_TIME);
+//
+//  u = u_old;
+//  u_lower = u;
+//  u_upper = u;
+//
+//  XH = p->chemistry_data.metal_mass_fraction[chemistry_element_H];
+//  HeFrac = p->chemistry_data.metal_mass_fraction[chemistry_element_He] / (XH + p->chemistry_data.metal_mass_fraction[chemistry_element_He]);
+//  //printf("Eagle cooling.h density %.5e\n", hydro_get_physical_density(p,cosmo)*units_cgs_conversion_factor(us,UNIT_CONV_DENSITY));
+//
+//  /* convert Hydrogen mass fraction in Hydrogen number density */
+//  inn_h = chemistry_get_number_density(p,cosmo,chemistry_element_H,phys_const)*cooling->number_density_scale;
+//  //inn_h = hydro_get_physical_density(p,cosmo)*units_cgs_conversion_factor(us,UNIT_CONV_DENSITY) * XH / eagle_proton_mass_cgs;
+//  /* ratefact = inn_h * inn_h / rho; Might lead to round-off error: replaced by
+//   * equivalent expression  below */
+//  ratefact = inn_h * (XH / eagle_proton_mass_cgs);
+//  /* set helium and hydrogen reheating term */
+//  //LambdaTune = eagle_helium_reionization_extraheat(z_index, dz); // INCLUDE HELIUM REIONIZATION????
+//  if (zold > z_index) {
+//    LambdaCumul += LambdaTune;
+//    printf(" EagleDoCooling %d %g %g %g\n", z_index, dz, LambdaTune, LambdaCumul);
+//    zold = z_index;
+//  }
+//
+//  // construct 1d table of cooling rates wrt temperature
+//  float H_plus_He_heat_table[176]; 			// WARNING sort out how it is declared/allocated
+//  float H_plus_He_electron_abundance_table[176]; 	// WARNING sort out how it is declared/allocated
+//  float element_cooling_table[9*176]; 			// WARNING sort out how it is declared/allocated
+//  float element_electron_abundance_table[176]; 		// WARNING sort out how it is declared/allocated
+//  construct_1d_table_from_4d(p,cooling,cosmo,phys_const,cooling->table.element_cooling.H_plus_He_heating,H_plus_He_heat_table);
+//  construct_1d_table_from_4d(p,cooling,cosmo,phys_const,cooling->table.element_cooling.H_plus_He_electron_abundance,H_plus_He_electron_abundance_table);
+//  construct_1d_table_from_4d_elements(p,cooling,cosmo,phys_const,cooling->table.element_cooling.metal_heating,element_cooling_table);
+//  construct_1d_table_from_3d(p,cooling,cosmo,phys_const,cooling->table.element_cooling.electron_abundance,element_electron_abundance_table);
+//
+//  /* iterative, implicit cooling */
+//  if (dt > 0)
+//    {
+//      //LambdaNet = (LambdaTune / (dt * ratefact)) + eagle_cooling_rate(u, p, cooling, cosmo, phys_const);
+//      LambdaNet = (LambdaTune / (dt * ratefact)) + eagle_cooling_rate_1d_table(u, H_plus_He_heat_table, H_plus_He_electron_abundance_table, element_cooling_table, element_electron_abundance_table, p, cooling, cosmo, phys_const);
+//      //n_eagle_cooling_rate_calls_1++;
+//    }                                                                                                                  
+//  else
+//    {
+//      //LambdaNet = eagle_cooling_rate(u, p, cooling, cosmo, phys_const);
+//      LambdaNet = eagle_cooling_rate_1d_table(u, H_plus_He_heat_table, H_plus_He_electron_abundance_table, element_cooling_table, element_electron_abundance_table, p, cooling, cosmo, phys_const);
+//    }
+//
+//  if (fabs(ratefact * LambdaNet * dt) < 0.05 * u_old) {
+//    /* cooling rate is small, take the explicit solution */
+//    u = u_old + ratefact * LambdaNet * dt;
+//  }
+//  else
+//  {
+//    i = 0;
+//
+//    /* bracketing  */
+//    if (u - u_old - ratefact * LambdaNet * dt < 0) /* heating  */
+//      {
+//        u_upper *= sqrt(1.1);
+//        u_lower /= sqrt(1.1);
+//
+//        //while (u_upper - u_old - LambdaTune - ratefact * eagle_cooling_rate(u_upper, p, cooling, cosmo, phys_const) * dt < 0
+//        //       && i < eagle_max_iterations) {
+//        while (u_upper - u_old - LambdaTune - ratefact * eagle_cooling_rate_1d_table(u_upper, H_plus_He_heat_table, H_plus_He_electron_abundance_table, element_cooling_table, element_electron_abundance_table, p, cooling, cosmo, phys_const) * dt < 0
+//               && i < eagle_max_iterations) {
+//          u_upper *= 1.1;
+//          u_lower *= 1.1;
+//          i++;
+//          //n_eagle_cooling_rate_calls_2++;
+//        }
+//      }
+//
+//    //if (i == eagle_max_iterations) printf("Problem with cooling finding upper bound\n");
+//#ifdef SWIFT_DEBUG_CHECKS
+//    //if (i < eagle_max_iterations) printf("Eagle cooling.h heating bound converged number of iterations, u_upper, u_lower, u, u_old, cooling %d %.8e %.8e %.8e %.8e %.8e\n", i, u_upper, u_lower, u, u_old,ratefact*eagle_cooling_rate(u_upper, p,cooling,cosmo,phys_const)*dt);
+//    if (i == eagle_max_iterations){
+//      printf("Problem with cooling finding upper bound, u_upper, u_lower, u, u_old, cooling %.5e %.5e %.5e %.5e %.5e\n", u_upper, u_lower, u, u_old,ratefact*eagle_cooling_rate(u_upper, p,cooling,cosmo,phys_const)*dt);
+//    }
+//#endif
+//
+//    if (u - u_old - ratefact * LambdaNet * dt > 0) /* cooling */
+//      {
+//        u_lower /= sqrt(1.1);
+//        u_upper *= sqrt(1.1);
+//
+//        i = 0;
+//
+//        //while(u_lower - u_old - LambdaTune - ratefact * eagle_cooling_rate(u_lower, p, cooling, cosmo, phys_const) * dt > 0
+//        //      && i < eagle_max_iterations)
+//        while(u_lower - u_old - LambdaTune - ratefact * eagle_cooling_rate_1d_table(u_lower, H_plus_He_heat_table, H_plus_He_electron_abundance_table, element_cooling_table, element_electron_abundance_table, p, cooling, cosmo, phys_const) * dt > 0
+//              && i < eagle_max_iterations)
+//          {
+//            u_upper /= 1.1;
+//            u_lower /= 1.1;
+//            i++;
+//            //n_eagle_cooling_rate_calls_3++;
+//          }
+//      }
+//
+//#ifdef SWIFT_DEBUG_CHECKS
+//    if (i == eagle_max_iterations){
+//      printf("Problem with cooling finding lower bound, u_upper, u_lower, u, u_old, cooling %.5e %.5e %.5e %.5e %.5e\n", u_upper, u_lower, u, u_old,ratefact*eagle_cooling_rate(u_lower, p,cooling,cosmo,phys_const)*dt);
+//    }
+//#endif
+//
+//    i = 0;
+//
+//    do /* iterate to convergence */
+//      {
+//        u = 0.5 * (u_lower + u_upper);
+//
+//        //LambdaNet = (LambdaTune / (dt * ratefact)) + eagle_cooling_rate(u, p, cooling, cosmo, phys_const);
+//        LambdaNet = (LambdaTune / (dt * ratefact)) + eagle_cooling_rate_1d_table(u, H_plus_He_heat_table, H_plus_He_electron_abundance_table, element_cooling_table, element_electron_abundance_table, p, cooling, cosmo, phys_const);
+//        //n_eagle_cooling_rate_calls_4++;
+//
+//        if (u - u_old - ratefact * LambdaNet * dt > 0)
+//          u_upper = u;
+//        else
+//          u_lower = u;
+//
+//        du = u_upper - u_lower;
+//
+//        i++;
+//
+//        if (i >= (eagle_max_iterations - 10)) printf("u = %g\n", u);
+//      } while (fabs(du / u) > 1.0e-6 && i < eagle_max_iterations);
+//    
+//#ifdef SWIFT_DEBUG_CHECKS
+//    if (i >= eagle_max_iterations){
+//      printf("particle ID %llu, du, u %.5e %.5e\n",p->id,du,u);
+//      error("failed to converge in EagleDoCooling()\n");
+//    }
+//#endif
+//
+//  }
+//
+//  float cooling_du_dt = 0.0;
+//  if (dt > 0){ 
+//    cooling_du_dt = (u - u_old)/dt/cooling->power_scale;
+//  }
+//
+//  const float hydro_du_dt = hydro_get_internal_energy_dt(p);
+//
+//  /* Update the internal energy time derivative */
+//  hydro_set_internal_energy_dt(p, hydro_du_dt + cooling_du_dt);
+//
+//  /* Store the radiated energy */
+//  xp->cooling_data.radiated_energy += -hydro_get_mass(p) * cooling_du_dt * (dt/units_cgs_conversion_factor(us,UNIT_CONV_TIME));
+//
+//}
+
 /**
  * @brief Writes the current model of SPH to the file
  * @param h_grpsph The HDF5 group in which to write
@@ -926,6 +1368,8 @@ static INLINE void cooling_init_backend(
   cooling->ElementAbundance_SOLARM1 = malloc(cooling->N_SolarAbundances*sizeof(float));
   cooling->solar_abundances = malloc(cooling->N_Elements*sizeof(double));
 
+  cooling->delta_u = cooling->Therm[1] - cooling->Therm[0];
+
   cooling->internal_energy_scale = units_cgs_conversion_factor(us,UNIT_CONV_ENERGY)/units_cgs_conversion_factor(us,UNIT_CONV_MASS);
   cooling->number_density_scale = units_cgs_conversion_factor(us,UNIT_CONV_DENSITY)/units_cgs_conversion_factor(us,UNIT_CONV_MASS);
   cooling->power_scale = units_cgs_conversion_factor(us,UNIT_CONV_POWER)/units_cgs_conversion_factor(us,UNIT_CONV_MASS);
diff --git a/src/cooling/EAGLE/cooling_struct.h b/src/cooling/EAGLE/cooling_struct.h
index e51b8933c6bfb75446ea7335a1d800df380d5566..77c168964af9c05a8bb53daaf83022d451f2c9c4 100644
--- a/src/cooling/EAGLE/cooling_struct.h
+++ b/src/cooling/EAGLE/cooling_struct.h
@@ -120,6 +120,8 @@ struct cooling_function_data {
   float calcium_over_silicon_ratio;
   float sulphur_over_silicon_ratio;
 
+  double delta_u;
+
 };
 
 /**
diff --git a/src/cooling/EAGLE/eagle_cool_tables.h b/src/cooling/EAGLE/eagle_cool_tables.h
index 9edb81d333e450b99806260177ee3e197c453af3..f6271e1076a774e540f3bc319040028cc26deb11 100644
--- a/src/cooling/EAGLE/eagle_cool_tables.h
+++ b/src/cooling/EAGLE/eagle_cool_tables.h
@@ -610,7 +610,7 @@ inline struct cooling_tables get_cooling_table(char *cooling_table_path, const s
       for (i = 0; i < cooling->N_nH; i++){
         for (j = 0; j < cooling->N_Temp; j++){
           table_index = row_major_index_2d(j,i,cooling->N_Temp,cooling->N_nH);
-          cooling_index = row_major_index_4d(z_index,specs,j,i,cooling->N_Redshifts,cooling->N_Elements,cooling->N_Temp,cooling->N_nH); 
+          cooling_index = row_major_index_4d(z_index,specs,i,j,cooling->N_Redshifts,cooling->N_Elements,cooling->N_nH,cooling->N_Temp); 
           //cooling_index = row_major_index_3d(specs,j,i,cooling->N_Elements,cooling->N_Temp,cooling->N_nH); 
           cooling_table.metal_heating[cooling_index] = -net_cooling_rate[table_index];
         }
@@ -640,7 +640,7 @@ inline struct cooling_tables get_cooling_table(char *cooling_table_path, const s
       for (j = 0; j < cooling->N_Temp; j++){
         for (k = 0; k < cooling->N_nH; k++) {
           table_index = row_major_index_3d(i,j,k,cooling->N_He,cooling->N_Temp,cooling->N_nH);
-          cooling_index = row_major_index_4d(z_index,i,j,k,cooling->N_Redshifts,cooling->N_He,cooling->N_Temp,cooling->N_nH); 
+          cooling_index = row_major_index_4d(z_index,k,i,j,cooling->N_Redshifts,cooling->N_nH,cooling->N_He,cooling->N_Temp); 
           //cooling_index = row_major_index_3d(i,j,k,cooling->N_He,cooling->N_Temp,cooling->N_nH); 
           cooling_table.H_plus_He_heating[cooling_index] = -he_net_cooling_rate[table_index];
           cooling_table.H_plus_He_electron_abundance[cooling_index] =
@@ -659,7 +659,7 @@ inline struct cooling_tables get_cooling_table(char *cooling_table_path, const s
     for (i = 0; i < cooling->N_Temp; i++){
       for (j = 0; j < cooling->N_nH; j++){
         table_index = row_major_index_2d(i,j,cooling->N_Temp,cooling->N_nH);
-        cooling_index = row_major_index_3d(z_index,i,j,cooling->N_Redshifts,cooling->N_Temp,cooling->N_nH); 
+        cooling_index = row_major_index_3d(z_index,j,i,cooling->N_Redshifts,cooling->N_nH,cooling->N_Temp); 
         //cooling_index = row_major_index_2d(i,j,cooling->N_Temp,cooling->N_nH); 
         cooling_table.electron_abundance[cooling_index] = electron_abundance[table_index];
       }
diff --git a/tests/plots.py b/tests/plots.py
index 56d90d1dc79fed9c6ca9e24b64697c45a30f9baa..73b95bed5789a00409edb0c0b06f0577bbaf3086 100644
--- a/tests/plots.py
+++ b/tests/plots.py
@@ -3,6 +3,8 @@ import matplotlib.pyplot as plt
 elements = 11
 temperature = []
 cooling_rate = [[] for i in range(elements+1)]
+u = []
+fu = []
 length = 0
 file_in = open('cooling_output.dat', 'r')
 for line in file_in:
@@ -19,22 +21,38 @@ for elem in range(elements):
         	cooling_rate[elem+1].append(-float(data[0]))
 	file_in.close()
 
+file_in = open('newton_output.dat', 'r')
+for line in file_in:
+	data = line.split()
+	u.append(float(data[0]))
+	fu.append(float(data[1]))
 
-p0, = plt.loglog(temperature, cooling_rate[0], linewidth = 0.5, color = 'k', label = 'Total')
-p1, = plt.loglog(temperature, cooling_rate[1], linewidth = 0.5, color = 'k', linestyle = '--', label = 'H + He')
-p2, = plt.loglog(temperature, cooling_rate[3], linewidth = 0.5, color = 'b', label = 'Carbon')
-p3, = plt.loglog(temperature, cooling_rate[4], linewidth = 0.5, color = 'g', label = 'Nitrogen')
-p4, = plt.loglog(temperature, cooling_rate[5], linewidth = 0.5, color = 'r', label = 'Oxygen')
-p5, = plt.loglog(temperature, cooling_rate[6], linewidth = 0.5, color = 'c', label = 'Neon')
-p6, = plt.loglog(temperature, cooling_rate[7], linewidth = 0.5, color = 'm', label = 'Magnesium')
-p7, = plt.loglog(temperature, cooling_rate[8], linewidth = 0.5, color = 'y', label = 'Silicon')
-p8, = plt.loglog(temperature, cooling_rate[9], linewidth = 0.5, color = 'lightgray', label = 'Sulphur')
-p9, = plt.loglog(temperature, cooling_rate[10], linewidth = 0.5, color = 'olive', label = 'Calcium')
-p10, = plt.loglog(temperature, cooling_rate[11], linewidth = 0.5, color = 'saddlebrown', label = 'Iron')
-plt.ylim([1e-24,1e-21])
-plt.xlim([1e4,1e8])
-plt.xlabel('Temperature (K)')
-plt.ylabel('Cooling rate (eagle units...)')
-plt.legend(handles = [p0,p1,p2,p3,p4,p5,p6,p7,p8,p9])
-#plt.legend(handles = [p0,p2,p3,p4,p5,p6,p7,p8,p9])
+file_in.close()
+
+p0, = plt.plot(u,fu, color = 'k')
+#p1, = plt.plot(u,[0 for x in u], color = 'r')
+#p1, = plt.loglog(u,[-x for x in fu], color = 'r')
+plt.xlim([1e13,2.0e14])
+plt.ylim([0e13,2e14])
+plt.xlabel('u')
+plt.ylabel('f(u)')
 plt.show()
+
+#p0, = plt.loglog(temperature, cooling_rate[0], linewidth = 0.5, color = 'k', label = 'Total')
+#p1, = plt.loglog(temperature, cooling_rate[1], linewidth = 0.5, color = 'k', linestyle = '--', label = 'H + He')
+#p2, = plt.loglog(temperature, cooling_rate[3], linewidth = 0.5, color = 'b', label = 'Carbon')
+#p3, = plt.loglog(temperature, cooling_rate[4], linewidth = 0.5, color = 'g', label = 'Nitrogen')
+#p4, = plt.loglog(temperature, cooling_rate[5], linewidth = 0.5, color = 'r', label = 'Oxygen')
+#p5, = plt.loglog(temperature, cooling_rate[6], linewidth = 0.5, color = 'c', label = 'Neon')
+#p6, = plt.loglog(temperature, cooling_rate[7], linewidth = 0.5, color = 'm', label = 'Magnesium')
+#p7, = plt.loglog(temperature, cooling_rate[8], linewidth = 0.5, color = 'y', label = 'Silicon')
+#p8, = plt.loglog(temperature, cooling_rate[9], linewidth = 0.5, color = 'lightgray', label = 'Sulphur')
+#p9, = plt.loglog(temperature, cooling_rate[10], linewidth = 0.5, color = 'olive', label = 'Calcium')
+#p10, = plt.loglog(temperature, cooling_rate[11], linewidth = 0.5, color = 'saddlebrown', label = 'Iron')
+#plt.ylim([1e-24,1e-21])
+#plt.xlim([1e4,1e8])
+#plt.xlabel('Temperature (K)')
+#plt.ylabel('Cooling rate (eagle units...)')
+#plt.legend(handles = [p0,p1,p2,p3,p4,p5,p6,p7,p8,p9])
+##plt.legend(handles = [p0,p2,p3,p4,p5,p6,p7,p8,p9])
+#plt.show()
diff --git a/tests/testCooling.c b/tests/testCooling.c
index 27b1b0fab2ab2e8b39d64a45ed6fc61804ed8eb5..d8e345163e0ed68933a503f2f4f85ded9525ebc0 100644
--- a/tests/testCooling.c
+++ b/tests/testCooling.c
@@ -49,9 +49,10 @@ int main() {
   units_init(&us, params, "InternalUnitSystem");
   phys_const_init(&us, params, &internal_const);
 
-  double hydrogen_number_density_cgs = 1e-4;
-  double u, hydrogen_number_density, pressure, gamma, cooling_du_dt, temperature_cgs;
+  double hydrogen_number_density_cgs = 1e-1;
+  double u,u_cgs, hydrogen_number_density, pressure, gamma, cooling_du_dt, temperature_cgs, newton_func, u_ini_cgs, ratefact, dt_cgs;
   int n_t_i = 2000;
+  dt_cgs = 4.0e-8*units_cgs_conversion_factor(&us,UNIT_CONV_TIME);
 
   char *output_filename = "cooling_output.dat";
   FILE *output_file = fopen(output_filename, "w");
@@ -67,6 +68,13 @@ int main() {
       printf("Error opening file!\n");
       exit(1);
   }
+  char *output_filename3 = "newton_output.dat";
+  FILE *output_file3 = fopen(output_filename3, "w");
+  if (output_file3 == NULL)
+  {
+      printf("Error opening file!\n");
+      exit(1);
+  }
 
   gamma = 5.0/3.0;
 
@@ -77,12 +85,9 @@ int main() {
   cosmology_init(params, &us, &internal_const, &cosmo);
   cosmology_print(&cosmo);
 
-  //float scale_factor = 1.0/(1.0 + cosmo.z);
-  //float scaled_hydrogen_number_density_cgs = hydrogen_number_density_cgs/pow(scale_factor,3);
     
   u = 1.0*pow(10.0,11)/(units_cgs_conversion_factor(&us,UNIT_CONV_ENERGY)/units_cgs_conversion_factor(&us,UNIT_CONV_MASS));
   pressure = u*p.rho*(gamma -1.0);
-  //hydrogen_number_density = scaled_hydrogen_number_density_cgs*pow(units_cgs_conversion_factor(&us,UNIT_CONV_LENGTH),3);
   hydrogen_number_density = hydrogen_number_density_cgs*pow(units_cgs_conversion_factor(&us,UNIT_CONV_LENGTH),3);
   p.rho = hydrogen_number_density*internal_const.const_proton_mass*(1.0+p.chemistry_data.metal_mass_fraction[EAGLE_Helium]/p.chemistry_data.metal_mass_fraction[EAGLE_Hydrogen]);
   p.entropy = pressure/(pow(p.rho,gamma));
@@ -91,22 +96,43 @@ int main() {
   cooling_init(params, &us, &internal_const, &cooling);
   cooling_print(&cooling);
 
+  // construct 1d table of cooling rates wrt temperature
+  float H_plus_He_heat_table[176];                      // WARNING sort out how it is declared/allocated
+  float H_plus_He_electron_abundance_table[176];        // WARNING sort out how it is declared/allocated
+  float element_cooling_table[9*176];                   // WARNING sort out how it is declared/allocated
+  float element_electron_abundance_table[176];          // WARNING sort out how it is declared/allocated
+  construct_1d_table_from_4d(&p,&cooling,&cosmo,&internal_const,cooling.table.element_cooling.H_plus_He_heating,H_plus_He_heat_table);
+  construct_1d_table_from_4d(&p,&cooling,&cosmo,&internal_const,cooling.table.element_cooling.H_plus_He_electron_abundance,H_plus_He_electron_abundance_table);
+  construct_1d_table_from_4d_elements(&p,&cooling,&cosmo,&internal_const,cooling.table.element_cooling.metal_heating,element_cooling_table);
+  construct_1d_table_from_3d(&p,&cooling,&cosmo,&internal_const,cooling.table.element_cooling.electron_abundance,element_electron_abundance_table);
+
+  float XH = p.chemistry_data.metal_mass_fraction[chemistry_element_H];
+  float inn_h = chemistry_get_number_density(&p,&cosmo,chemistry_element_H,&internal_const)*cooling.number_density_scale;
+  ratefact = inn_h * (XH / eagle_proton_mass_cgs);
+  u_ini_cgs = pow(10.0,14);
 
   for(int t_i = 0; t_i < n_t_i; t_i++){
     
-    u = 1.0*pow(10.0,11 + t_i*6.0/n_t_i)/(units_cgs_conversion_factor(&us,UNIT_CONV_ENERGY)/units_cgs_conversion_factor(&us,UNIT_CONV_MASS));
+    u_cgs = pow(10.0,11 + t_i*6.0/n_t_i);
+    u = u_cgs/(units_cgs_conversion_factor(&us,UNIT_CONV_ENERGY)/units_cgs_conversion_factor(&us,UNIT_CONV_MASS));
     pressure = u*p.rho*(gamma -1.0);
     hydrogen_number_density = hydrogen_number_density_cgs*pow(units_cgs_conversion_factor(&us,UNIT_CONV_LENGTH),3);
     p.rho = hydrogen_number_density*internal_const.const_proton_mass*(1.0+p.chemistry_data.metal_mass_fraction[EAGLE_Helium]/p.chemistry_data.metal_mass_fraction[EAGLE_Hydrogen]);
     p.entropy = pressure/(pow(p.rho,gamma));
 
-    cooling_du_dt = eagle_print_metal_cooling_rate(&p,&cooling,&cosmo,&internal_const);
-    temperature_cgs = eagle_convert_u_to_temp(&p,&cooling,&cosmo,&internal_const);
+    //cooling_du_dt = eagle_print_metal_cooling_rate(&p,&cooling,&cosmo,&internal_const);
+    cooling_du_dt = eagle_print_metal_cooling_rate_1d_table(H_plus_He_heat_table,H_plus_He_electron_abundance_table,element_cooling_table,element_electron_abundance_table,&p,&cooling,&cosmo,&internal_const);
+    temperature_cgs = eagle_convert_u_to_temp(u_cgs,&p,&cooling,&cosmo,&internal_const);
     fprintf(output_file,"%.5e %.5e\n",temperature_cgs,cooling_du_dt);
     fprintf(output_file2,"%.5e %.5e\n",u*(units_cgs_conversion_factor(&us,UNIT_CONV_ENERGY)/units_cgs_conversion_factor(&us,UNIT_CONV_MASS)), temperature_cgs);
+
+    newton_func = u_cgs - u_ini_cgs - cooling_du_dt*ratefact*dt_cgs;
+    fprintf(output_file3,"%.5e %.5e\n",u_cgs,newton_func);
+    //printf("u,u_ini,cooling_du_dt,ratefact,dt %.5e %.5e %.5e %.5e %.5e \n",u_cgs,u_ini_cgs,cooling_du_dt,ratefact,dt_cgs);
   }
   fclose(output_file);
   fclose(output_file2);
+  fclose(output_file3);
 
   free(params);