diff --git a/.gitignore b/.gitignore
index d1c23c053c237b0af5a5c2228b21735417f4e8d8..619c2e78a22ce2752d0495179384b078868761ef 100644
--- a/.gitignore
+++ b/.gitignore
@@ -43,9 +43,12 @@ examples/*/*.mpg
 examples/*/*/gravity_checks_*.dat
 examples/*/*/coolingtables.tar.gz
 examples/*/*/coolingtables
+examples/*/*/yieldtables.tar.gz
+examples/*/*/yieldtables
 examples/Cooling/CoolingRates/cooling_rates
 examples/Cooling/CoolingRates/cooling_element_*.dat
 examples/Cooling/CoolingRates/cooling_output.dat
+examples/SubgridTests/StellarEvolution/StellarEvolutionSolution*
 
 tests/testActivePair
 tests/testActivePair.sh
@@ -104,6 +107,7 @@ tests/testMaths
 tests/testRandom
 tests/testThreadpool
 tests/testParser
+tests/testFeedback
 tests/parser_output.yml
 tests/testPeriodicBC.sh
 tests/testPeriodicBCPerturbed.sh
diff --git a/configure.ac b/configure.ac
index 59a9826767fd0ad82ceda23657b143c377e14472..c0ce630351f471de337d73a0f401227a91a38dc2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1329,7 +1329,7 @@ case "$with_subgrid" in
 	with_subgrid_entropy_floor=none
 	with_subgrid_stars=GEAR
 	with_subgrid_star_formation=GEAR
-	with_subgrid_feedback=thermal
+	with_subgrid_feedback=none
 	with_subgrid_black_holes=none
    ;;
    EAGLE)
@@ -1339,7 +1339,7 @@ case "$with_subgrid" in
 	with_subgrid_entropy_floor=EAGLE
 	with_subgrid_stars=EAGLE
 	with_subgrid_star_formation=EAGLE
-	with_subgrid_feedback=none
+	with_subgrid_feedback=EAGLE
 	with_subgrid_black_holes=none
    ;;
    *)
@@ -1730,7 +1730,7 @@ case "$with_stars" in
       AC_DEFINE([STARS_GEAR], [1], [GEAR stellar model])
    ;;
    none)
-      AC_DEFINE([STARS_NONE], [1], [None stellar model])
+      AC_DEFINE([STARS_NONE], [1], [Basic stellar model])
    ;;
 
    *)
@@ -1741,7 +1741,7 @@ esac
 # Feedback model
 AC_ARG_WITH([feedback],
    [AS_HELP_STRING([--with-feedback=<model>],
-      [Feedback model to use @<:@none, thermal, debug default: none@:>@]
+      [Feedback model to use @<:@none, EAGLE, debug default: none@:>@]
    )],
    [with_feedback="$withval"],
    [with_feedback="none"]
@@ -1756,10 +1756,11 @@ if test "$with_subgrid" != "none"; then
 fi
 
 case "$with_feedback" in
-   thermal)
-      AC_DEFINE([FEEDBACK_THERMAL], [1], [Thermal Blastwave])
+   EAGLE)
+      AC_DEFINE([FEEDBACK_EAGLE], [1], [EAGLE stellar feedback and evolution model])
    ;;
    none)
+      AC_DEFINE([FEEDBACK_NONE], [1], [No feedback])
    ;;
 
    *)
@@ -1767,7 +1768,7 @@ case "$with_feedback" in
    ;;
 esac
 
-# Stellar model.
+# Black hole model.
 AC_ARG_WITH([black-holes],
    [AS_HELP_STRING([--with-black-holes=<model>],
       [Black holes model to use @<:@none, default: none@:>@]
@@ -1793,11 +1794,10 @@ case "$with_black_holes" in
    ;;
 esac
 
-
 #  External potential
 AC_ARG_WITH([ext-potential],
    [AS_HELP_STRING([--with-ext-potential=<pot>],
-      [external potential @<:@none, point-mass, point-mass-ring, point-mass-softened, isothermal, softened-isothermal, nfw, hernquist, disc-patch, sine-wave, default: none@:>@]
+      [external potential @<:@none, point-mass, point-mass-ring, point-mass-softened, isothermal, nfw, hernquist, disc-patch, sine-wave, default: none@:>@]
    )],
    [with_potential="$withval"],
    [with_potential="none"]
@@ -1915,6 +1915,9 @@ AM_CONDITIONAL([HAVE_DOXYGEN], [test "$ac_cv_path_ac_pt_DX_DOXYGEN" != ""])
 # Check if using EAGLE cooling
 AM_CONDITIONAL([HAVEEAGLECOOLING], [test $with_cooling = "EAGLE"])
 
+# Check if using EAGLE feedback
+AM_CONDITIONAL([HAVEEAGLEFEEDBACK], [test $with_feedback = "EAGLE"])
+
 # Handle .in files.
 AC_CONFIG_FILES([Makefile src/Makefile examples/Makefile examples/Cooling/CoolingRates/Makefile doc/Makefile doc/Doxyfile tests/Makefile])
 AC_CONFIG_FILES([argparse/Makefile tools/Makefile])
diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in
index b90ba8f6e3e0b912c711179afb73e54be5a6d7fc..8e5fa52b236d91cabf51ce0c4f481a7334fd315d 100644
--- a/doc/Doxyfile.in
+++ b/doc/Doxyfile.in
@@ -763,7 +763,6 @@ INPUT                  =  @top_srcdir@ @top_srcdir@/src @top_srcdir@/tests @top_
 INPUT		       += @top_srcdir@/src/hydro/Minimal
 INPUT		       += @top_srcdir@/src/hydro/Gadget2
 INPUT		       += @top_srcdir@/src/gravity/Default
-INPUT		       += @top_srcdir@/src/stars/Default
 INPUT		       += @top_srcdir@/src/riemann
 INPUT		       += @top_srcdir@/src/potential/point_mass
 INPUT		       += @top_srcdir@/src/equation_of_state/ideal_gas
@@ -776,6 +775,7 @@ INPUT		       += @top_srcdir@/src/entropy_floor/EAGLE
 INPUT		       += @top_srcdir@/src/star_formation/EAGLE
 INPUT		       += @top_srcdir@/src/tracers/EAGLE
 INPUT		       += @top_srcdir@/src/stars/EAGLE
+INPUT		       += @top_srcdir@/src/feedback/EAGLE
 INPUT		       += @top_srcdir@/src/black_holes/Default
 
 # This tag can be used to specify the character encoding of the source files
diff --git a/examples/EAGLE_ICs/EAGLE_12/eagle_12.yml b/examples/EAGLE_ICs/EAGLE_12/eagle_12.yml
index df4c05811bae17a65b54e45c6625ff97a21357f6..f163fb64d3b0da8becff5760c21d9d44b0c3e773 100644
--- a/examples/EAGLE_ICs/EAGLE_12/eagle_12.yml
+++ b/examples/EAGLE_ICs/EAGLE_12/eagle_12.yml
@@ -112,3 +112,37 @@ EAGLEEntropyFloor:
   Cool_temperature_norm_K:        8000       # Temperature of the EAGLE Cool limiter entropy floor at the density threshold expressed in Kelvin.
   Cool_gamma_effective:           1.         # Slope the of the EAGLE Cool limiter entropy floor
 
+# EAGLE feedback model
+EAGLEFeedback:
+  use_SNe_feedback:                 1               # Global switch for SNe thermal feedback.
+  use_AGB_enrichment:               1               # Global switch for enrichement from AGB stars.
+  use_SNII_enrichment:              1               # Global switch for enrichement from SNII stars.
+  use_SNIa_enrichment:              1               # Global switch for enrichement from SNIa stars.
+  filename:                         ./yieldtables/  # Path to the directory containing the EAGLE yield tables.
+  IMF_min_mass_Msun:                0.1             # Minimal stellar mass considered for the Chabrier IMF in solar masses.
+  IMF_max_mass_Msun:              100.0             # Maximal stellar mass considered for the Chabrier IMF in solar masses.
+  SNII_min_mass_Msun:               6.0             # Minimal mass considered for SNII feedback (not SNII enrichment!) in solar masses.
+  SNII_max_mass_Msun:             100.0             # Maximal mass considered for SNII feedback (not SNII enrichment!) in solar masses.
+  SNII_wind_delay_Gyr:              0.03            # Time in Gyr between a star's birth and the SNII thermal feedback event.
+  SNII_delta_T_K:                   3.16228e7       # Change in temperature to apply to the gas particle in a SNII thermal feedback event in Kelvin.
+  SNII_Energy_erg:                  1.0e51          # Energy of one SNII explosion in ergs.
+  SNII_Energy_fraction_min:         3.0             # Maximal fraction of energy applied in a SNII feedback event.
+  SNII_Energy_fraction_max:         0.3             # Minimal fraction of energy applied in a SNII feedback event.
+  SNII_Energy_fraction_Z_0:         0.0012663729    # Pivot point for the metallicity dependance of the SNII energy fraction (metal mass fraction).
+  SNII_Energy_fraction_n_0_H_p_cm3: 0.67            # Pivot point for the birth density dependance of the SNII energy fraction in cm^-3.
+  SNII_Energy_fraction_n_Z:         0.8686          # Power-law for the metallicity dependance of the SNII energy fraction.
+  SNII_Energy_fraction_n_n:         0.8686          # Power-law for the birth density dependance of the SNII energy fraction.
+  SNIa_max_mass_Msun:              8.0              # Maximal mass considered for SNIa feedback and enrichment in solar masses.
+  SNIa_timescale_Gyr:              2.0              # Time-scale of the exponential decay of the SNIa rates in Gyr.
+  SNIa_efficiency_p_Msun:          0.002            # Normalisation of the SNIa rates in inverse solar masses.
+  SNIa_Energy_erg:                 1.0e51           # Energy of one SNIa explosion in ergs.
+  AGB_ejecta_velocity_km_p_s:      10.0             # Velocity of the AGB ejectas in km/s.
+  SNII_yield_factor_Hydrogen:       1.0             # (Optional) Correction factor to apply to the Hydrogen yield from the SNII channel.
+  SNII_yield_factor_Helium:         1.0             # (Optional) Correction factor to apply to the Helium yield from the SNII channel.
+  SNII_yield_factor_Carbon:         0.5             # (Optional) Correction factor to apply to the Carbon yield from the SNII channel.
+  SNII_yield_factor_Nitrogen:       1.0             # (Optional) Correction factor to apply to the Nitrogen yield from the SNII channel.
+  SNII_yield_factor_Oxygen:         1.0             # (Optional) Correction factor to apply to the Oxygen yield from the SNII channel.
+  SNII_yield_factor_Neon:           1.0             # (Optional) Correction factor to apply to the Neon yield from the SNII channel.
+  SNII_yield_factor_Magnesium:      2.0             # (Optional) Correction factor to apply to the Magnesium yield from the SNII channel.
+  SNII_yield_factor_Silicon:        1.0             # (Optional) Correction factor to apply to the Silicon yield from the SNII channel.
+  SNII_yield_factor_Iron:           0.5             # (Optional) Correction factor to apply to the Iron yield from the SNII channel.
diff --git a/examples/EAGLE_ICs/EAGLE_25/eagle_25.yml b/examples/EAGLE_ICs/EAGLE_25/eagle_25.yml
index ac8be3ecec4e56af2e910bb104038b033af59078..2065642935e38b87019ea560ed3afcbe2ca9fe77 100644
--- a/examples/EAGLE_ICs/EAGLE_25/eagle_25.yml
+++ b/examples/EAGLE_ICs/EAGLE_25/eagle_25.yml
@@ -113,3 +113,37 @@ EAGLEEntropyFloor:
   Cool_temperature_norm_K:        8000       # Temperature of the EAGLE Cool limiter entropy floor at the density threshold expressed in Kelvin.
   Cool_gamma_effective:           1.         # Slope the of the EAGLE Cool limiter entropy floor
 
+# EAGLE feedback model
+EAGLEFeedback:
+  use_SNe_feedback:                 1               # Global switch for SNe thermal feedback.
+  use_AGB_enrichment:               1               # Global switch for enrichement from AGB stars.
+  use_SNII_enrichment:              1               # Global switch for enrichement from SNII stars.
+  use_SNIa_enrichment:              1               # Global switch for enrichement from SNIa stars.
+  filename:                         ./yieldtables/  # Path to the directory containing the EAGLE yield tables.
+  IMF_min_mass_Msun:                0.1             # Minimal stellar mass considered for the Chabrier IMF in solar masses.
+  IMF_max_mass_Msun:              100.0             # Maximal stellar mass considered for the Chabrier IMF in solar masses.
+  SNII_min_mass_Msun:               6.0             # Minimal mass considered for SNII feedback (not SNII enrichment!) in solar masses.
+  SNII_max_mass_Msun:             100.0             # Maximal mass considered for SNII feedback (not SNII enrichment!) in solar masses.
+  SNII_wind_delay_Gyr:              0.03            # Time in Gyr between a star's birth and the SNII thermal feedback event.
+  SNII_delta_T_K:                   3.16228e7       # Change in temperature to apply to the gas particle in a SNII thermal feedback event in Kelvin.
+  SNII_Energy_erg:                  1.0e51          # Energy of one SNII explosion in ergs.
+  SNII_Energy_fraction_min:         3.0             # Maximal fraction of energy applied in a SNII feedback event.
+  SNII_Energy_fraction_max:         0.3             # Minimal fraction of energy applied in a SNII feedback event.
+  SNII_Energy_fraction_Z_0:         0.0012663729    # Pivot point for the metallicity dependance of the SNII energy fraction (metal mass fraction).
+  SNII_Energy_fraction_n_0_H_p_cm3: 0.67            # Pivot point for the birth density dependance of the SNII energy fraction in cm^-3.
+  SNII_Energy_fraction_n_Z:         0.8686          # Power-law for the metallicity dependance of the SNII energy fraction.
+  SNII_Energy_fraction_n_n:         0.8686          # Power-law for the birth density dependance of the SNII energy fraction.
+  SNIa_max_mass_Msun:              8.0              # Maximal mass considered for SNIa feedback and enrichment in solar masses.
+  SNIa_timescale_Gyr:              2.0              # Time-scale of the exponential decay of the SNIa rates in Gyr.
+  SNIa_efficiency_p_Msun:          0.002            # Normalisation of the SNIa rates in inverse solar masses.
+  SNIa_Energy_erg:                 1.0e51           # Energy of one SNIa explosion in ergs.
+  AGB_ejecta_velocity_km_p_s:      10.0             # Velocity of the AGB ejectas in km/s.
+  SNII_yield_factor_Hydrogen:       1.0             # (Optional) Correction factor to apply to the Hydrogen yield from the SNII channel.
+  SNII_yield_factor_Helium:         1.0             # (Optional) Correction factor to apply to the Helium yield from the SNII channel.
+  SNII_yield_factor_Carbon:         0.5             # (Optional) Correction factor to apply to the Carbon yield from the SNII channel.
+  SNII_yield_factor_Nitrogen:       1.0             # (Optional) Correction factor to apply to the Nitrogen yield from the SNII channel.
+  SNII_yield_factor_Oxygen:         1.0             # (Optional) Correction factor to apply to the Oxygen yield from the SNII channel.
+  SNII_yield_factor_Neon:           1.0             # (Optional) Correction factor to apply to the Neon yield from the SNII channel.
+  SNII_yield_factor_Magnesium:      2.0             # (Optional) Correction factor to apply to the Magnesium yield from the SNII channel.
+  SNII_yield_factor_Silicon:        1.0             # (Optional) Correction factor to apply to the Silicon yield from the SNII channel.
+  SNII_yield_factor_Iron:           0.5             # (Optional) Correction factor to apply to the Iron yield from the SNII channel.
diff --git a/examples/EAGLE_ICs/EAGLE_50/eagle_50.yml b/examples/EAGLE_ICs/EAGLE_50/eagle_50.yml
index 528f11f763274b8d793a525201712f1fb6603e4a..669773d619844ae026f86742475b6e2b6ed334d3 100644
--- a/examples/EAGLE_ICs/EAGLE_50/eagle_50.yml
+++ b/examples/EAGLE_ICs/EAGLE_50/eagle_50.yml
@@ -113,3 +113,37 @@ EAGLEEntropyFloor:
   Cool_temperature_norm_K:        8000       # Temperature of the EAGLE Cool limiter entropy floor at the density threshold expressed in Kelvin.
   Cool_gamma_effective:           1.         # Slope the of the EAGLE Cool limiter entropy floor
 
+# EAGLE feedback model
+EAGLEFeedback:
+  use_SNe_feedback:                 1               # Global switch for SNe thermal feedback.
+  use_AGB_enrichment:               1               # Global switch for enrichement from AGB stars.
+  use_SNII_enrichment:              1               # Global switch for enrichement from SNII stars.
+  use_SNIa_enrichment:              1               # Global switch for enrichement from SNIa stars.
+  filename:                         ./yieldtables/  # Path to the directory containing the EAGLE yield tables.
+  IMF_min_mass_Msun:                0.1             # Minimal stellar mass considered for the Chabrier IMF in solar masses.
+  IMF_max_mass_Msun:              100.0             # Maximal stellar mass considered for the Chabrier IMF in solar masses.
+  SNII_min_mass_Msun:               6.0             # Minimal mass considered for SNII feedback (not SNII enrichment!) in solar masses.
+  SNII_max_mass_Msun:             100.0             # Maximal mass considered for SNII feedback (not SNII enrichment!) in solar masses.
+  SNII_wind_delay_Gyr:              0.03            # Time in Gyr between a star's birth and the SNII thermal feedback event.
+  SNII_delta_T_K:                   3.16228e7       # Change in temperature to apply to the gas particle in a SNII thermal feedback event in Kelvin.
+  SNII_Energy_erg:                  1.0e51          # Energy of one SNII explosion in ergs.
+  SNII_Energy_fraction_min:         3.0             # Maximal fraction of energy applied in a SNII feedback event.
+  SNII_Energy_fraction_max:         0.3             # Minimal fraction of energy applied in a SNII feedback event.
+  SNII_Energy_fraction_Z_0:         0.0012663729    # Pivot point for the metallicity dependance of the SNII energy fraction (metal mass fraction).
+  SNII_Energy_fraction_n_0_H_p_cm3: 0.67            # Pivot point for the birth density dependance of the SNII energy fraction in cm^-3.
+  SNII_Energy_fraction_n_Z:         0.8686          # Power-law for the metallicity dependance of the SNII energy fraction.
+  SNII_Energy_fraction_n_n:         0.8686          # Power-law for the birth density dependance of the SNII energy fraction.
+  SNIa_max_mass_Msun:              8.0              # Maximal mass considered for SNIa feedback and enrichment in solar masses.
+  SNIa_timescale_Gyr:              2.0              # Time-scale of the exponential decay of the SNIa rates in Gyr.
+  SNIa_efficiency_p_Msun:          0.002            # Normalisation of the SNIa rates in inverse solar masses.
+  SNIa_Energy_erg:                 1.0e51           # Energy of one SNIa explosion in ergs.
+  AGB_ejecta_velocity_km_p_s:      10.0             # Velocity of the AGB ejectas in km/s.
+  SNII_yield_factor_Hydrogen:       1.0             # (Optional) Correction factor to apply to the Hydrogen yield from the SNII channel.
+  SNII_yield_factor_Helium:         1.0             # (Optional) Correction factor to apply to the Helium yield from the SNII channel.
+  SNII_yield_factor_Carbon:         0.5             # (Optional) Correction factor to apply to the Carbon yield from the SNII channel.
+  SNII_yield_factor_Nitrogen:       1.0             # (Optional) Correction factor to apply to the Nitrogen yield from the SNII channel.
+  SNII_yield_factor_Oxygen:         1.0             # (Optional) Correction factor to apply to the Oxygen yield from the SNII channel.
+  SNII_yield_factor_Neon:           1.0             # (Optional) Correction factor to apply to the Neon yield from the SNII channel.
+  SNII_yield_factor_Magnesium:      2.0             # (Optional) Correction factor to apply to the Magnesium yield from the SNII channel.
+  SNII_yield_factor_Silicon:        1.0             # (Optional) Correction factor to apply to the Silicon yield from the SNII channel.
+  SNII_yield_factor_Iron:           0.5             # (Optional) Correction factor to apply to the Iron yield from the SNII channel.
diff --git a/examples/EAGLE_low_z/EAGLE_12/eagle_12.yml b/examples/EAGLE_low_z/EAGLE_12/eagle_12.yml
index cc9a3019cc235948c4d8ecc3a6ea7d71da537129..7abfe983b5f0048b610044c27abc924581eccfcc 100644
--- a/examples/EAGLE_low_z/EAGLE_12/eagle_12.yml
+++ b/examples/EAGLE_low_z/EAGLE_12/eagle_12.yml
@@ -104,3 +104,38 @@ EAGLEEntropyFloor:
   Cool_over_density_threshold:    10.        # Overdensity above which the EAGLE Cool limiter entropy floor can kick in.
   Cool_temperature_norm_K:        8000       # Temperature of the EAGLE Cool limiter entropy floor at the density threshold expressed in Kelvin.
   Cool_gamma_effective:           1.         # Slope the of the EAGLE Cool limiter entropy floor
+
+# EAGLE feedback model
+EAGLEFeedback:
+  use_SNe_feedback:                 1               # Global switch for SNe thermal feedback.
+  use_AGB_enrichment:               1               # Global switch for enrichement from AGB stars.
+  use_SNII_enrichment:              1               # Global switch for enrichement from SNII stars.
+  use_SNIa_enrichment:              1               # Global switch for enrichement from SNIa stars.
+  filename:                         ./yieldtables/  # Path to the directory containing the EAGLE yield tables.
+  IMF_min_mass_Msun:                0.1             # Minimal stellar mass considered for the Chabrier IMF in solar masses.
+  IMF_max_mass_Msun:              100.0             # Maximal stellar mass considered for the Chabrier IMF in solar masses.
+  SNII_min_mass_Msun:               6.0             # Minimal mass considered for SNII feedback (not SNII enrichment!) in solar masses.
+  SNII_max_mass_Msun:             100.0             # Maximal mass considered for SNII feedback (not SNII enrichment!) in solar masses.
+  SNII_wind_delay_Gyr:              0.03            # Time in Gyr between a star's birth and the SNII thermal feedback event.
+  SNII_delta_T_K:                   3.16228e7       # Change in temperature to apply to the gas particle in a SNII thermal feedback event in Kelvin.
+  SNII_Energy_erg:                  1.0e51          # Energy of one SNII explosion in ergs.
+  SNII_Energy_fraction_min:         3.0             # Maximal fraction of energy applied in a SNII feedback event.
+  SNII_Energy_fraction_max:         0.3             # Minimal fraction of energy applied in a SNII feedback event.
+  SNII_Energy_fraction_Z_0:         0.0012663729    # Pivot point for the metallicity dependance of the SNII energy fraction (metal mass fraction).
+  SNII_Energy_fraction_n_0_H_p_cm3: 0.67            # Pivot point for the birth density dependance of the SNII energy fraction in cm^-3.
+  SNII_Energy_fraction_n_Z:         0.8686          # Power-law for the metallicity dependance of the SNII energy fraction.
+  SNII_Energy_fraction_n_n:         0.8686          # Power-law for the birth density dependance of the SNII energy fraction.
+  SNIa_max_mass_Msun:              8.0              # Maximal mass considered for SNIa feedback and enrichment in solar masses.
+  SNIa_timescale_Gyr:              2.0              # Time-scale of the exponential decay of the SNIa rates in Gyr.
+  SNIa_efficiency_p_Msun:          0.002            # Normalisation of the SNIa rates in inverse solar masses.
+  SNIa_Energy_erg:                 1.0e51           # Energy of one SNIa explosion in ergs.
+  AGB_ejecta_velocity_km_p_s:      10.0             # Velocity of the AGB ejectas in km/s.
+  SNII_yield_factor_Hydrogen:       1.0             # (Optional) Correction factor to apply to the Hydrogen yield from the SNII channel.
+  SNII_yield_factor_Helium:         1.0             # (Optional) Correction factor to apply to the Helium yield from the SNII channel.
+  SNII_yield_factor_Carbon:         0.5             # (Optional) Correction factor to apply to the Carbon yield from the SNII channel.
+  SNII_yield_factor_Nitrogen:       1.0             # (Optional) Correction factor to apply to the Nitrogen yield from the SNII channel.
+  SNII_yield_factor_Oxygen:         1.0             # (Optional) Correction factor to apply to the Oxygen yield from the SNII channel.
+  SNII_yield_factor_Neon:           1.0             # (Optional) Correction factor to apply to the Neon yield from the SNII channel.
+  SNII_yield_factor_Magnesium:      2.0             # (Optional) Correction factor to apply to the Magnesium yield from the SNII channel.
+  SNII_yield_factor_Silicon:        1.0             # (Optional) Correction factor to apply to the Silicon yield from the SNII channel.
+  SNII_yield_factor_Iron:           0.5             # (Optional) Correction factor to apply to the Iron yield from the SNII channel.
diff --git a/examples/EAGLE_low_z/EAGLE_25/eagle_25.yml b/examples/EAGLE_low_z/EAGLE_25/eagle_25.yml
index 02927925bf9e80a180baa1096b2db40aba2ea0f6..b3e45f1c28ff6e93512de26dfe2a0e559ff33fd7 100644
--- a/examples/EAGLE_low_z/EAGLE_25/eagle_25.yml
+++ b/examples/EAGLE_low_z/EAGLE_25/eagle_25.yml
@@ -111,3 +111,38 @@ EAGLEEntropyFloor:
   Cool_over_density_threshold:    10.        # Overdensity above which the EAGLE Cool limiter entropy floor can kick in.
   Cool_temperature_norm_K:        8000       # Temperature of the EAGLE Cool limiter entropy floor at the density threshold expressed in Kelvin.
   Cool_gamma_effective:           1.         # Slope the of the EAGLE Cool limiter entropy floor
+
+# EAGLE feedback model
+EAGLEFeedback:
+  use_SNe_feedback:                 1               # Global switch for SNe thermal feedback.
+  use_AGB_enrichment:               1               # Global switch for enrichement from AGB stars.
+  use_SNII_enrichment:              1               # Global switch for enrichement from SNII stars.
+  use_SNIa_enrichment:              1               # Global switch for enrichement from SNIa stars.
+  filename:                         ./yieldtables/  # Path to the directory containing the EAGLE yield tables.
+  IMF_min_mass_Msun:                0.1             # Minimal stellar mass considered for the Chabrier IMF in solar masses.
+  IMF_max_mass_Msun:              100.0             # Maximal stellar mass considered for the Chabrier IMF in solar masses.
+  SNII_min_mass_Msun:               6.0             # Minimal mass considered for SNII feedback (not SNII enrichment!) in solar masses.
+  SNII_max_mass_Msun:             100.0             # Maximal mass considered for SNII feedback (not SNII enrichment!) in solar masses.
+  SNII_wind_delay_Gyr:              0.03            # Time in Gyr between a star's birth and the SNII thermal feedback event.
+  SNII_delta_T_K:                   3.16228e7       # Change in temperature to apply to the gas particle in a SNII thermal feedback event in Kelvin.
+  SNII_Energy_erg:                  1.0e51          # Energy of one SNII explosion in ergs.
+  SNII_Energy_fraction_min:         3.0             # Maximal fraction of energy applied in a SNII feedback event.
+  SNII_Energy_fraction_max:         0.3             # Minimal fraction of energy applied in a SNII feedback event.
+  SNII_Energy_fraction_Z_0:         0.0012663729    # Pivot point for the metallicity dependance of the SNII energy fraction (metal mass fraction).
+  SNII_Energy_fraction_n_0_H_p_cm3: 0.67            # Pivot point for the birth density dependance of the SNII energy fraction in cm^-3.
+  SNII_Energy_fraction_n_Z:         0.8686          # Power-law for the metallicity dependance of the SNII energy fraction.
+  SNII_Energy_fraction_n_n:         0.8686          # Power-law for the birth density dependance of the SNII energy fraction.
+  SNIa_max_mass_Msun:              8.0              # Maximal mass considered for SNIa feedback and enrichment in solar masses.
+  SNIa_timescale_Gyr:              2.0              # Time-scale of the exponential decay of the SNIa rates in Gyr.
+  SNIa_efficiency_p_Msun:          0.002            # Normalisation of the SNIa rates in inverse solar masses.
+  SNIa_Energy_erg:                 1.0e51           # Energy of one SNIa explosion in ergs.
+  AGB_ejecta_velocity_km_p_s:      10.0             # Velocity of the AGB ejectas in km/s.
+  SNII_yield_factor_Hydrogen:       1.0             # (Optional) Correction factor to apply to the Hydrogen yield from the SNII channel.
+  SNII_yield_factor_Helium:         1.0             # (Optional) Correction factor to apply to the Helium yield from the SNII channel.
+  SNII_yield_factor_Carbon:         0.5             # (Optional) Correction factor to apply to the Carbon yield from the SNII channel.
+  SNII_yield_factor_Nitrogen:       1.0             # (Optional) Correction factor to apply to the Nitrogen yield from the SNII channel.
+  SNII_yield_factor_Oxygen:         1.0             # (Optional) Correction factor to apply to the Oxygen yield from the SNII channel.
+  SNII_yield_factor_Neon:           1.0             # (Optional) Correction factor to apply to the Neon yield from the SNII channel.
+  SNII_yield_factor_Magnesium:      2.0             # (Optional) Correction factor to apply to the Magnesium yield from the SNII channel.
+  SNII_yield_factor_Silicon:        1.0             # (Optional) Correction factor to apply to the Silicon yield from the SNII channel.
+  SNII_yield_factor_Iron:           0.5             # (Optional) Correction factor to apply to the Iron yield from the SNII channel.
diff --git a/examples/EAGLE_low_z/EAGLE_50/eagle_50.yml b/examples/EAGLE_low_z/EAGLE_50/eagle_50.yml
index 7b7ae35bfa2f72686c7479b8f19ef6c2950c0c22..752769fcec123e99f8157376ce5689e44e370aef 100644
--- a/examples/EAGLE_low_z/EAGLE_50/eagle_50.yml
+++ b/examples/EAGLE_low_z/EAGLE_50/eagle_50.yml
@@ -106,3 +106,38 @@ EAGLEEntropyFloor:
   Cool_over_density_threshold:    10.        # Overdensity above which the EAGLE Cool limiter entropy floor can kick in.
   Cool_temperature_norm_K:        8000       # Temperature of the EAGLE Cool limiter entropy floor at the density threshold expressed in Kelvin.
   Cool_gamma_effective:           1.         # Slope the of the EAGLE Cool limiter entropy floor
+
+# EAGLE feedback model
+EAGLEFeedback:
+  use_SNe_feedback:                 1               # Global switch for SNe thermal feedback.
+  use_AGB_enrichment:               1               # Global switch for enrichement from AGB stars.
+  use_SNII_enrichment:              1               # Global switch for enrichement from SNII stars.
+  use_SNIa_enrichment:              1               # Global switch for enrichement from SNIa stars.
+  filename:                         ./yieldtables/  # Path to the directory containing the EAGLE yield tables.
+  IMF_min_mass_Msun:                0.1             # Minimal stellar mass considered for the Chabrier IMF in solar masses.
+  IMF_max_mass_Msun:              100.0             # Maximal stellar mass considered for the Chabrier IMF in solar masses.
+  SNII_min_mass_Msun:               6.0             # Minimal mass considered for SNII feedback (not SNII enrichment!) in solar masses.
+  SNII_max_mass_Msun:             100.0             # Maximal mass considered for SNII feedback (not SNII enrichment!) in solar masses.
+  SNII_wind_delay_Gyr:              0.03            # Time in Gyr between a star's birth and the SNII thermal feedback event.
+  SNII_delta_T_K:                   3.16228e7       # Change in temperature to apply to the gas particle in a SNII thermal feedback event in Kelvin.
+  SNII_Energy_erg:                  1.0e51          # Energy of one SNII explosion in ergs.
+  SNII_Energy_fraction_min:         3.0             # Maximal fraction of energy applied in a SNII feedback event.
+  SNII_Energy_fraction_max:         0.3             # Minimal fraction of energy applied in a SNII feedback event.
+  SNII_Energy_fraction_Z_0:         0.0012663729    # Pivot point for the metallicity dependance of the SNII energy fraction (metal mass fraction).
+  SNII_Energy_fraction_n_0_H_p_cm3: 0.67            # Pivot point for the birth density dependance of the SNII energy fraction in cm^-3.
+  SNII_Energy_fraction_n_Z:         0.8686          # Power-law for the metallicity dependance of the SNII energy fraction.
+  SNII_Energy_fraction_n_n:         0.8686          # Power-law for the birth density dependance of the SNII energy fraction.
+  SNIa_max_mass_Msun:              8.0              # Maximal mass considered for SNIa feedback and enrichment in solar masses.
+  SNIa_timescale_Gyr:              2.0              # Time-scale of the exponential decay of the SNIa rates in Gyr.
+  SNIa_efficiency_p_Msun:          0.002            # Normalisation of the SNIa rates in inverse solar masses.
+  SNIa_Energy_erg:                 1.0e51           # Energy of one SNIa explosion in ergs.
+  AGB_ejecta_velocity_km_p_s:      10.0             # Velocity of the AGB ejectas in km/s.
+  SNII_yield_factor_Hydrogen:       1.0             # (Optional) Correction factor to apply to the Hydrogen yield from the SNII channel.
+  SNII_yield_factor_Helium:         1.0             # (Optional) Correction factor to apply to the Helium yield from the SNII channel.
+  SNII_yield_factor_Carbon:         0.5             # (Optional) Correction factor to apply to the Carbon yield from the SNII channel.
+  SNII_yield_factor_Nitrogen:       1.0             # (Optional) Correction factor to apply to the Nitrogen yield from the SNII channel.
+  SNII_yield_factor_Oxygen:         1.0             # (Optional) Correction factor to apply to the Oxygen yield from the SNII channel.
+  SNII_yield_factor_Neon:           1.0             # (Optional) Correction factor to apply to the Neon yield from the SNII channel.
+  SNII_yield_factor_Magnesium:      2.0             # (Optional) Correction factor to apply to the Magnesium yield from the SNII channel.
+  SNII_yield_factor_Silicon:        1.0             # (Optional) Correction factor to apply to the Silicon yield from the SNII channel.
+  SNII_yield_factor_Iron:           0.5             # (Optional) Correction factor to apply to the Iron yield from the SNII channel.
diff --git a/examples/EAGLE_low_z/EAGLE_6/eagle_6.yml b/examples/EAGLE_low_z/EAGLE_6/eagle_6.yml
index e4b175b622610bfb4edcd0ad168cf23d1df2b2ba..e486bf74aa515e96f6761191f7eeef4f4019ca37 100644
--- a/examples/EAGLE_low_z/EAGLE_6/eagle_6.yml
+++ b/examples/EAGLE_low_z/EAGLE_6/eagle_6.yml
@@ -115,3 +115,38 @@ EAGLEEntropyFloor:
   Cool_over_density_threshold:    10.        # Overdensity above which the EAGLE Cool limiter entropy floor can kick in.
   Cool_temperature_norm_K:        8000       # Temperature of the EAGLE Cool limiter entropy floor at the density threshold expressed in Kelvin.
   Cool_gamma_effective:           1.         # Slope the of the EAGLE Cool limiter entropy floor
+
+# EAGLE feedback model
+EAGLEFeedback:
+  use_SNe_feedback:                 1               # Global switch for SNe thermal feedback.
+  use_AGB_enrichment:               1               # Global switch for enrichement from AGB stars.
+  use_SNII_enrichment:              1               # Global switch for enrichement from SNII stars.
+  use_SNIa_enrichment:              1               # Global switch for enrichement from SNIa stars.
+  filename:                         ./yieldtables/  # Path to the directory containing the EAGLE yield tables.
+  IMF_min_mass_Msun:                0.1             # Minimal stellar mass considered for the Chabrier IMF in solar masses.
+  IMF_max_mass_Msun:              100.0             # Maximal stellar mass considered for the Chabrier IMF in solar masses.
+  SNII_min_mass_Msun:               6.0             # Minimal mass considered for SNII feedback (not SNII enrichment!) in solar masses.
+  SNII_max_mass_Msun:             100.0             # Maximal mass considered for SNII feedback (not SNII enrichment!) in solar masses.
+  SNII_wind_delay_Gyr:              0.03            # Time in Gyr between a star's birth and the SNII thermal feedback event.
+  SNII_delta_T_K:                   3.16228e7       # Change in temperature to apply to the gas particle in a SNII thermal feedback event in Kelvin.
+  SNII_Energy_erg:                  1.0e51          # Energy of one SNII explosion in ergs.
+  SNII_Energy_fraction_min:         3.0             # Maximal fraction of energy applied in a SNII feedback event.
+  SNII_Energy_fraction_max:         0.3             # Minimal fraction of energy applied in a SNII feedback event.
+  SNII_Energy_fraction_Z_0:         0.0012663729    # Pivot point for the metallicity dependance of the SNII energy fraction (metal mass fraction).
+  SNII_Energy_fraction_n_0_H_p_cm3: 0.67            # Pivot point for the birth density dependance of the SNII energy fraction in cm^-3.
+  SNII_Energy_fraction_n_Z:         0.8686          # Power-law for the metallicity dependance of the SNII energy fraction.
+  SNII_Energy_fraction_n_n:         0.8686          # Power-law for the birth density dependance of the SNII energy fraction.
+  SNIa_max_mass_Msun:              8.0              # Maximal mass considered for SNIa feedback and enrichment in solar masses.
+  SNIa_timescale_Gyr:              2.0              # Time-scale of the exponential decay of the SNIa rates in Gyr.
+  SNIa_efficiency_p_Msun:          0.002            # Normalisation of the SNIa rates in inverse solar masses.
+  SNIa_Energy_erg:                 1.0e51           # Energy of one SNIa explosion in ergs.
+  AGB_ejecta_velocity_km_p_s:      10.0             # Velocity of the AGB ejectas in km/s.
+  SNII_yield_factor_Hydrogen:       1.0             # (Optional) Correction factor to apply to the Hydrogen yield from the SNII channel.
+  SNII_yield_factor_Helium:         1.0             # (Optional) Correction factor to apply to the Helium yield from the SNII channel.
+  SNII_yield_factor_Carbon:         0.5             # (Optional) Correction factor to apply to the Carbon yield from the SNII channel.
+  SNII_yield_factor_Nitrogen:       1.0             # (Optional) Correction factor to apply to the Nitrogen yield from the SNII channel.
+  SNII_yield_factor_Oxygen:         1.0             # (Optional) Correction factor to apply to the Oxygen yield from the SNII channel.
+  SNII_yield_factor_Neon:           1.0             # (Optional) Correction factor to apply to the Neon yield from the SNII channel.
+  SNII_yield_factor_Magnesium:      2.0             # (Optional) Correction factor to apply to the Magnesium yield from the SNII channel.
+  SNII_yield_factor_Silicon:        1.0             # (Optional) Correction factor to apply to the Silicon yield from the SNII channel.
+  SNII_yield_factor_Iron:           0.5             # (Optional) Correction factor to apply to the Iron yield from the SNII channel.
diff --git a/examples/IsolatedGalaxy/IsolatedGalaxy_feedback/SFH.py b/examples/IsolatedGalaxy/IsolatedGalaxy_feedback/SFH.py
new file mode 100644
index 0000000000000000000000000000000000000000..fa9d9258530396fb7f95237a45af5db9c0da4603
--- /dev/null
+++ b/examples/IsolatedGalaxy/IsolatedGalaxy_feedback/SFH.py
@@ -0,0 +1,100 @@
+"""
+Makes a movie using sphviewer and ffmpeg.
+
+Edit low_frac and up_frac to focus on a certain view of the box.
+The colour map can also be changed via colour_map.
+
+Usage: python3 makeMovie.py CoolingHalo_
+
+Written by James Willis (james.s.willis@durham.ac.uk)
+"""
+
+import glob
+import h5py as h5
+import numpy as np
+import matplotlib.pyplot as plt
+
+from tqdm import tqdm
+
+
+def getSFH(filename):
+
+    # Read the data
+    with h5.File(filename, "r") as f:
+        box_size = f["/Header"].attrs["BoxSize"][0]
+        coordinates = f["/PartType4/Coordinates"][:, :]
+        mass = f["/PartType4/Masses"][:]
+        # flag = f["/PartType4/NewStarFlag"][:]
+        birth_time = f["/PartType4/Birth_time"][:]
+
+    absmaxz = 2  # kpc
+    absmaxxy = 10  # kpc
+
+    part_mask = (
+        ((coordinates[:, 0] - box_size / 2.0) > -absmaxxy)
+        & ((coordinates[:, 0] - box_size / 2.0) < absmaxxy)
+        & ((coordinates[:, 1] - box_size / 2.0) > -absmaxxy)
+        & ((coordinates[:, 1] - box_size / 2.0) < absmaxxy)
+        & ((coordinates[:, 2] - box_size / 2.0) > -absmaxz)
+        & ((coordinates[:, 2] - box_size / 2.0) < absmaxz)
+    )  # & (flag==1)
+
+    birth_time = birth_time[part_mask]
+    mass = mass[part_mask]
+
+    histogram = np.histogram(birth_time, bins=200, weights=mass * 2e4, range=[0, 0.1])
+    values = histogram[0]
+    xvalues = (histogram[1][:-1] + histogram[1][1:]) / 2.0
+    return xvalues, values
+
+
+def getsfrsnapwide():
+
+    time = np.arange(1, 101, 1)
+    SFR_sparticles = np.zeros(100)
+    SFR_gparticles = np.zeros(100)
+    new_sparticles = np.zeros(100)
+    previous_mass = 0
+    previous_numb = 0
+    for i in tqdm(range(1, 100)):
+        # Read the data
+        filename = "output_%04d.hdf5" % i
+        with h5.File(filename, "r") as f:
+            box_size = f["/Header"].attrs["BoxSize"][0]
+            coordinates = f["/PartType0/Coordinates"][:, :]
+            SFR = f["/PartType0/SFR"][:]
+            coordinates_star = f["/PartType4/Coordinates"][:, :]
+            masses_star = f["/PartType4/Masses"][:]
+
+        absmaxz = 2  # kpc
+        absmaxxy = 10  # kpc
+
+        part_mask = (
+            ((coordinates[:, 0] - box_size / 2.0) > -absmaxxy)
+            & ((coordinates[:, 0] - box_size / 2.0) < absmaxxy)
+            & ((coordinates[:, 1] - box_size / 2.0) > -absmaxxy)
+            & ((coordinates[:, 1] - box_size / 2.0) < absmaxxy)
+            & ((coordinates[:, 2] - box_size / 2.0) > -absmaxz)
+            & ((coordinates[:, 2] - box_size / 2.0) < absmaxz)
+            & (SFR > 0)
+        )
+
+        SFR = SFR[part_mask]
+
+        total_SFR = np.sum(SFR)
+        SFR_gparticles[i] = total_SFR * 10
+
+    return time[:-1], SFR_gparticles[1:]
+
+
+if __name__ == "__main__":
+
+    time, SFR1 = getsfrsnapwide()  # , SFR2, SFR_error = getsfrsnapwide()
+    time2, SFR3 = getSFH("output_%04d.hdf5" % 100)
+    plt.plot(time2[1:] * 1e3, SFR3[1:], label="Using birth_time of star particles")
+    plt.plot(time, SFR1, label="Using SFR of gas particles", color="g")
+    plt.xlabel("Time (Myr)")
+    plt.ylabel("SFH ($\\rm M_\odot \\rm yr^{-1}$)")
+    plt.ylim(0, 20)
+    plt.legend()
+    plt.savefig("SFH.png")
diff --git a/examples/IsolatedGalaxy/IsolatedGalaxy_feedback/getEagleCoolingTable.sh b/examples/IsolatedGalaxy/IsolatedGalaxy_feedback/getEagleCoolingTable.sh
new file mode 100755
index 0000000000000000000000000000000000000000..5cfd93ef0f4603e40b7675f3f2c254b2250f699f
--- /dev/null
+++ b/examples/IsolatedGalaxy/IsolatedGalaxy_feedback/getEagleCoolingTable.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+wget http://virgodb.cosma.dur.ac.uk/swift-webstorage/CoolingTables/EAGLE/coolingtables.tar.gz
+tar -xf coolingtables.tar.gz 
diff --git a/examples/IsolatedGalaxy/IsolatedGalaxy_feedback/getIC.sh b/examples/IsolatedGalaxy/IsolatedGalaxy_feedback/getIC.sh
new file mode 100755
index 0000000000000000000000000000000000000000..32195a97b154e849eacd781ddbe98f59ecf48311
--- /dev/null
+++ b/examples/IsolatedGalaxy/IsolatedGalaxy_feedback/getIC.sh
@@ -0,0 +1,3 @@
+#!/bin/bash 
+
+wget http://virgodb.cosma.dur.ac.uk/swift-webstorage/ICs/IsolatedGalaxies/lowres8.hdf5
diff --git a/examples/IsolatedGalaxy/IsolatedGalaxy_feedback/getYieldTable.sh b/examples/IsolatedGalaxy/IsolatedGalaxy_feedback/getYieldTable.sh
new file mode 100755
index 0000000000000000000000000000000000000000..26eef020cab82acee2c80e88089df1790b281eab
--- /dev/null
+++ b/examples/IsolatedGalaxy/IsolatedGalaxy_feedback/getYieldTable.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+wget http://virgodb.cosma.dur.ac.uk/swift-webstorage/YieldTables/EAGLE/yieldtables.tar.gz
+tar -xf yieldtables.tar.gz
diff --git a/examples/IsolatedGalaxy/IsolatedGalaxy_feedback/isolated_galaxy.yml b/examples/IsolatedGalaxy/IsolatedGalaxy_feedback/isolated_galaxy.yml
new file mode 100644
index 0000000000000000000000000000000000000000..24d31443f6320b09b3fb7a1d8146f5c142b3a4ba
--- /dev/null
+++ b/examples/IsolatedGalaxy/IsolatedGalaxy_feedback/isolated_galaxy.yml
@@ -0,0 +1,142 @@
+# Define the system of units to use internally.
+InternalUnitSystem:
+  UnitMass_in_cgs:     1.98848e43    # 10^10 M_sun in grams
+  UnitLength_in_cgs:   3.08567758e21 # 1 kpc in cm
+  UnitVelocity_in_cgs: 1e5           # 1 km/s in cm/s
+  UnitCurrent_in_cgs:  1             # Amperes
+  UnitTemp_in_cgs:     1             # Kelvin
+
+# Parameters for the self-gravity scheme
+Gravity:
+  eta:          0.025               # Constant dimensionless multiplier for time integration.
+  theta:        0.7                 # Opening angle (Multipole acceptance criterion).
+  comoving_softening:     0.01      # Comoving softening length (in internal units).
+  max_physical_softening: 0.01      # Physical softening length (in internal units).
+
+# Parameters governing the time integration (Set dt_min and dt_max to the same value for a fixed time-step run.)
+TimeIntegration:
+  time_begin:        0.    # The starting time of the simulation (in internal units).
+  time_end:          0.1   # The end time of the simulation (in internal units).
+  dt_min:            1e-14  # The minimal time-step size of the simulation (in internal units).
+  dt_max:            1e-2  # The maximal time-step size of the simulation (in internal units).
+
+# Parameters governing the snapshots
+Snapshots:
+  basename:   output      # Common part of the name of output files
+  time_first: 0.          # (Optional) Time of the first output if non-cosmological time-integration (in internal units)
+  delta_time: 0.001        # Time difference between consecutive outputs (in internal units)
+
+# Parameters governing the conserved quantities statistics
+Statistics:
+  delta_time:           1e-2     # Time between statistics output
+  time_first:             0.     # (Optional) Time of the first stats output if non-cosmological time-integration (in internal units)
+
+# Parameters related to the initial conditions
+InitialConditions:
+  file_name:               lowres8.hdf5 # The file to read
+  periodic:                0        # Are we running with periodic ICs?
+  stars_smoothing_length:  0.5
+  
+# Parameters for the hydrodynamics scheme
+SPH:
+  resolution_eta:        1.2348   # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel).
+  CFL_condition:         0.1      # Courant-Friedrich-Levy condition for time integration.
+  h_min_ratio:           0.1      # Minimal smoothing in units of softening.
+  h_max:                 10.
+  minimal_temperature:   100.
+
+# Standard EAGLE cooling options
+EAGLECooling:
+  dir_name:                ./coolingtables/  # Location of the Wiersma+08 cooling tables
+  H_reion_z:               11.5              # Redshift of Hydrogen re-ionization
+  H_reion_eV_p_H:          2.0               # Energy inject by Hydrogen re-ionization in electron-volt per Hydrogen atom
+  He_reion_z_centre:       3.5               # Redshift of the centre of the Helium re-ionization Gaussian
+  He_reion_z_sigma:        0.5               # Spread in redshift of the  Helium re-ionization Gaussian
+  He_reion_eV_p_H:         2.0               # Energy inject by Helium re-ionization in electron-volt per Hydrogen atom
+
+# Use solar abundances
+EAGLEChemistry:
+  init_abundance_metal:     0.0129   
+  init_abundance_Hydrogen:  0.7065   
+  init_abundance_Helium:    0.2806   
+  init_abundance_Carbon:    0.00207  
+  init_abundance_Nitrogen:  0.000836 
+  init_abundance_Oxygen:    0.00549  
+  init_abundance_Neon:      0.00141  
+  init_abundance_Magnesium: 0.000591 
+  init_abundance_Silicon:   0.000683 
+  init_abundance_Iron:      0.0011   
+
+# Hernquist potential parameters
+HernquistPotential:
+  useabspos:       0        # 0 -> positions based on centre, 1 -> absolute positions 
+  position:        [0.,0.,0.]    # Location of centre of isothermal potential with respect to centre of the box (if 0) otherwise absolute (if 1) (internal units)
+  idealizeddisk:   1        # Run with an idealized galaxy disk
+  M200:            137.0   # M200 of the galaxy disk
+  h:               0.704    # reduced Hubble constant (value does not specify the used units!)
+  concentration:   9.0      # concentration of the Halo
+  diskfraction:              0.040   # Disk mass fraction
+  bulgefraction:              0.014   # Bulge mass fraction
+  timestep_mult:   0.01     # Dimensionless pre-factor for the time-step condition, basically determines the fraction of the orbital time we use to do the time integration
+  epsilon:         0.01      # Softening size (internal units)
+ 
+# EAGLE star formation parameters
+EAGLEStarFormation:
+  EOS_density_norm_H_p_cm3:          0.1       # Physical density used for the normalisation of the EOS assumed for the star-forming gas in Hydrogen atoms per cm^3.
+  EOS_temperature_norm_K:            8000      # Temperature om the polytropic EOS assumed for star-forming gas at the density normalisation in Kelvin.
+  EOS_gamma_effective:               1.3333333 # Slope the of the polytropic EOS assumed for the star-forming gas.
+  gas_fraction:                      0.3       # The gas fraction used internally by the model.
+  KS_normalisation:                  1.515e-4  # The normalization of the Kennicutt-Schmidt law in Msun / kpc^2 / yr.
+  KS_exponent:                       1.4       # The exponent of the Kennicutt-Schmidt law.
+  KS_min_over_density:               57.7      # The over-density above which star-formation is allowed.
+  KS_high_density_threshold_H_p_cm3: 1e3       # Hydrogen number density above which the Kennicut-Schmidt law changes slope in Hydrogen atoms per cm^3.
+  KS_high_density_exponent:          2.0       # Slope of the Kennicut-Schmidt law above the high-density threshold.
+  KS_temperature_margin_dex:         0.5       # Logarithm base 10 of the maximal temperature difference above the EOS allowed to form stars.
+  threshold_norm_H_p_cm3:            0.1       # Normalisation of the metal-dependant density threshold for star formation in Hydrogen atoms per cm^3.
+  threshold_Z0:                      0.002     # Reference metallicity (metal mass fraction) for the metal-dependant threshold for star formation.
+  threshold_slope:                   -0.64     # Slope of the metal-dependant star formation threshold
+  threshold_max_density_H_p_cm3:     10.0      # Maximal density of the metal-dependant density threshold for star formation in Hydrogen atoms per cm^3.
+  
+# Parameters for the EAGLE "equation of state"
+EAGLEEntropyFloor:
+  Jeans_density_threshold_H_p_cm3: 0.1       # Physical density above which the EAGLE Jeans limiter entropy floor kicks in expressed in Hydrogen atoms per cm^3.
+  Jeans_over_density_threshold:    10.       # Overdensity above which the EAGLE Jeans limiter entropy floor can kick in.
+  Jeans_temperature_norm_K:        8000      # Temperature of the EAGLE Jeans limiter entropy floor at the density threshold expressed in Kelvin.
+  Jeans_gamma_effective:           1.3333333 # Slope the of the EAGLE Jeans limiter entropy floor
+  Cool_density_threshold_H_p_cm3: 1e-5       # Physical density above which the EAGLE Cool limiter entropy floor kicks in expressed in Hydrogen atoms per cm^3.
+  Cool_over_density_threshold:    10.        # Overdensity above which the EAGLE Cool limiter entropy floor can kick in.
+  Cool_temperature_norm_K:        8000       # Temperature of the EAGLE Cool limiter entropy floor at the density threshold expressed in Kelvin.
+  Cool_gamma_effective:           1.         # Slope the of the EAGLE Cool limiter entropy floor
+
+# EAGLE feedback model
+EAGLEFeedback:
+  use_SNe_feedback:                 1               # Global switch for SNe thermal feedback.
+  use_AGB_enrichment:               1               # Global switch for enrichement from AGB stars.
+  use_SNII_enrichment:              1               # Global switch for enrichement from SNII stars.
+  use_SNIa_enrichment:              1               # Global switch for enrichement from SNIa stars.
+  filename:                         ./yieldtables/  # Path to the directory containing the EAGLE yield tables.
+  IMF_min_mass_Msun:                0.1             # Minimal stellar mass considered for the Chabrier IMF in solar masses.
+  IMF_max_mass_Msun:              100.0             # Maximal stellar mass considered for the Chabrier IMF in solar masses.
+  SNII_min_mass_Msun:               6.0             # Minimal mass considered for SNII feedback (not SNII enrichment!) in solar masses.
+  SNII_max_mass_Msun:             100.0             # Maximal mass considered for SNII feedback (not SNII enrichment!) in solar masses.
+  SNII_wind_delay_Gyr:              0.03            # Time in Gyr between a star's birth and the SNII thermal feedback event.
+  SNII_delta_T_K:                   3.16228e7       # Change in temperature to apply to the gas particle in a SNII thermal feedback event in Kelvin.
+  SNII_Energy_erg:                  1.0e51          # Energy of one SNII explosion in ergs.
+  SNII_Energy_fraction_min:         3.0             # Maximal fraction of energy applied in a SNII feedback event.
+  SNII_Energy_fraction_max:         0.3             # Minimal fraction of energy applied in a SNII feedback event.
+  SNII_Energy_fraction_Z_0:         0.0012663729    # Pivot point for the metallicity dependance of the SNII energy fraction (metal mass fraction).
+  SNII_Energy_fraction_n_0_H_p_cm3: 0.67            # Pivot point for the birth density dependance of the SNII energy fraction in cm^-3.
+  SNII_Energy_fraction_n_Z:         0.8686          # Power-law for the metallicity dependance of the SNII energy fraction.
+  SNII_Energy_fraction_n_n:         0.8686          # Power-law for the birth density dependance of the SNII energy fraction.
+  SNIa_max_mass_Msun:              8.0              # Maximal mass considered for SNIa feedback and enrichment in solar masses.
+  SNIa_timescale_Gyr:              2.0              # Time-scale of the exponential decay of the SNIa rates in Gyr.
+  SNIa_efficiency_p_Msun:          0.002            # Normalisation of the SNIa rates in inverse solar masses.
+  SNII_yield_factor_Hydrogen:       1.0             # (Optional) Correction factor to apply to the Hydrogen yield from the SNII channel.
+  SNII_yield_factor_Helium:         1.0             # (Optional) Correction factor to apply to the Helium yield from the SNII channel.
+  SNII_yield_factor_Carbon:         0.5             # (Optional) Correction factor to apply to the Carbon yield from the SNII channel.
+  SNII_yield_factor_Nitrogen:       1.0             # (Optional) Correction factor to apply to the Nitrogen yield from the SNII channel.
+  SNII_yield_factor_Oxygen:         1.0             # (Optional) Correction factor to apply to the Oxygen yield from the SNII channel.
+  SNII_yield_factor_Neon:           1.0             # (Optional) Correction factor to apply to the Neon yield from the SNII channel.
+  SNII_yield_factor_Magnesium:      2.0             # (Optional) Correction factor to apply to the Magnesium yield from the SNII channel.
+  SNII_yield_factor_Silicon:        1.0             # (Optional) Correction factor to apply to the Silicon yield from the SNII channel.
+  SNII_yield_factor_Iron:           0.5             # (Optional) Correction factor to apply to the Iron yield from the SNII channel.
diff --git a/examples/IsolatedGalaxy/IsolatedGalaxy_feedback/plotSolution.py b/examples/IsolatedGalaxy/IsolatedGalaxy_feedback/plotSolution.py
new file mode 100644
index 0000000000000000000000000000000000000000..89a87923148cb6872ab17b6d7229aef597ef3287
--- /dev/null
+++ b/examples/IsolatedGalaxy/IsolatedGalaxy_feedback/plotSolution.py
@@ -0,0 +1,368 @@
+import matplotlib
+
+matplotlib.use("Agg")
+from pylab import *
+from scipy import stats
+import h5py as h5
+
+# Plot parameters
+params = {
+    "axes.labelsize": 10,
+    "axes.titlesize": 10,
+    "font.size": 9,
+    "legend.fontsize": 9,
+    "xtick.labelsize": 10,
+    "ytick.labelsize": 10,
+    "text.usetex": True,
+    "figure.figsize": (3.15, 3.15),
+    "figure.subplot.left": 0.15,
+    "figure.subplot.right": 0.99,
+    "figure.subplot.bottom": 0.13,
+    "figure.subplot.top": 0.99,
+    "figure.subplot.wspace": 0.15,
+    "figure.subplot.hspace": 0.12,
+    "lines.markersize": 6,
+    "lines.linewidth": 2.0,
+    "text.latex.unicode": True,
+}
+rcParams.update(params)
+rc("font", **{"family": "sans-serif", "sans-serif": ["Times"]})
+
+snap = int(sys.argv[1])
+filename = "output_%.4d.hdf5"%snap
+
+f = h5.File(filename, "r")
+
+# Physical constants
+k_in_cgs = 1.38064852e-16
+mH_in_cgs = 1.6737236e-24
+year_in_cgs = 3600.0 * 24 * 365.0
+Msun_in_cgs = 1.98848e33
+G_in_cgs = 6.67259e-8
+pc_in_cgs = 3.08567758e18
+Msun_p_pc2 = Msun_in_cgs / pc_in_cgs**2
+
+# Gemoetry info
+boxsize = f["/Header"].attrs["BoxSize"]
+centre = boxsize / 2.0
+
+# Read units
+unit_length_in_cgs = f["/Units"].attrs["Unit length in cgs (U_L)"]
+unit_mass_in_cgs = f["/Units"].attrs["Unit mass in cgs (U_M)"]
+unit_time_in_cgs = f["/Units"].attrs["Unit time in cgs (U_t)"]
+
+# Calculate Gravitational constant in internal units
+G = G_in_cgs * ( unit_length_in_cgs**3 / unit_mass_in_cgs / unit_time_in_cgs**2)**(-1)
+
+# Read parameters of the SF model
+KS_law_slope = float(f["/Parameters"].attrs["EAGLEStarFormation:KS_exponent"])
+KS_law_norm = float(f["/Parameters"].attrs["EAGLEStarFormation:KS_normalisation"])
+KS_thresh_Z0 = float(f["/Parameters"].attrs["EAGLEStarFormation:threshold_Z0"])
+KS_thresh_slope = float(f["/Parameters"].attrs["EAGLEStarFormation:threshold_slope"])
+KS_thresh_norm = float(f["/Parameters"].attrs["EAGLEStarFormation:threshold_norm_H_p_cm3"])
+KS_gas_fraction = float(f["/Parameters"].attrs["EAGLEStarFormation:gas_fraction"])
+KS_thresh_max_norm = float(f["/Parameters"].attrs["EAGLEStarFormation:threshold_max_density_H_p_cm3"])
+KS_high_den_thresh = float(f["/Parameters"].attrs["EAGLEStarFormation:KS_high_density_threshold_H_p_cm3"])
+KS_law_slope_high_den = float(f["/Parameters"].attrs["EAGLEStarFormation:KS_high_density_exponent"])
+EOS_gamma_effective = float(f["/Parameters"].attrs["EAGLEStarFormation:EOS_gamma_effective"])                           
+EOS_density_norm = float(f["/Parameters"].attrs["EAGLEStarFormation:EOS_density_norm_H_p_cm3"])                           
+EOS_temp_norm = float(f["/Parameters"].attrs["EAGLEStarFormation:EOS_temperature_norm_K"])                           
+
+# Read reference metallicity
+EAGLE_Z = float(f["/Parameters"].attrs["EAGLEChemistry:init_abundance_metal"])
+
+# Read parameters of the entropy floor
+EAGLEfloor_Jeans_rho_norm = float(f["/Parameters"].attrs["EAGLEEntropyFloor:Jeans_density_threshold_H_p_cm3"])
+EAGLEfloor_Jeans_temperature_norm_K = float(f["/Parameters"].attrs["EAGLEEntropyFloor:Jeans_temperature_norm_K"])
+EAGLEfloor_Jeans_gamma_effective = float(f["/Parameters"].attrs["EAGLEEntropyFloor:Jeans_gamma_effective"])
+EAGLEfloor_cool_rho_norm = float(f["/Parameters"].attrs["EAGLEEntropyFloor:Cool_density_threshold_H_p_cm3"])
+EAGLEfloor_cool_temperature_norm_K = float(f["/Parameters"].attrs["EAGLEEntropyFloor:Cool_temperature_norm_K"])
+EAGLEfloor_cool_gamma_effective = float(f["/Parameters"].attrs["EAGLEEntropyFloor:Cool_gamma_effective"])
+
+# Properties of the KS law
+KS_law_norm_cgs = KS_law_norm * Msun_in_cgs / ( 1e6 * pc_in_cgs**2 * year_in_cgs )
+gamma = 5./3.
+EOS_press_norm = k_in_cgs * EOS_temp_norm * EOS_density_norm
+
+# Star formation threshold
+SF_thresh = KS_thresh_norm * (EAGLE_Z / KS_thresh_Z0)**(KS_thresh_slope)
+
+# Read gas properties
+gas_pos = f["/PartType0/Coordinates"][:, :]
+gas_mass = f["/PartType0/Masses"][:]
+gas_rho = f["/PartType0/Density"][:]
+gas_T = f["/PartType0/Temperature"][:]
+gas_SFR = f["/PartType0/SFR"][:]
+gas_XH = f["/PartType0/ElementAbundance"][:, 0]
+gas_Z = f["/PartType0/Metallicity"][:]
+gas_hsml = f["/PartType0/SmoothingLength"][:]
+gas_sSFR = gas_SFR / gas_mass
+
+# Read the Star properties
+stars_pos = f["/PartType4/Coordinates"][:, :]
+stars_BirthDensity = f["/PartType4/BirthDensity"][:]
+stars_BirthTime = f["/PartType4/BirthTime"][:]
+stars_XH = f["/PartType4/ElementAbundance"][:,0]
+
+# Centre the box
+gas_pos[:, 0] -= centre[0]
+gas_pos[:, 1] -= centre[1]
+gas_pos[:, 2] -= centre[2]
+
+stars_pos[:,0] -= centre[0]
+stars_pos[:,1] -= centre[1]
+stars_pos[:,2] -= centre[2]
+
+# Turn the mass into better units
+gas_mass *= unit_mass_in_cgs / Msun_in_cgs
+
+# Turn the SFR into better units
+gas_SFR = np.maximum(gas_SFR, np.zeros(np.size(gas_SFR)))
+gas_SFR /= unit_time_in_cgs / year_in_cgs
+gas_SFR *= unit_mass_in_cgs / Msun_in_cgs
+
+# Make it a Hydrogen number density
+gas_nH = gas_rho * unit_mass_in_cgs / unit_length_in_cgs ** 3
+gas_nH /= mH_in_cgs
+gas_nH *= gas_XH
+
+stars_BirthDensity *= unit_mass_in_cgs / unit_length_in_cgs ** 3
+stars_BirthDensity /= mH_in_cgs
+stars_BirthDensity *= stars_XH
+
+# Equations of state
+eos_cool_rho = np.logspace(-5, 5, 1000)
+eos_cool_T = EAGLEfloor_cool_temperature_norm_K * (eos_cool_rho / EAGLEfloor_cool_rho_norm) ** ( EAGLEfloor_cool_gamma_effective - 1.0 )
+eos_Jeans_rho = np.logspace(-1, 5, 1000)
+eos_Jeans_T = EAGLEfloor_Jeans_temperature_norm_K * (eos_Jeans_rho / EAGLEfloor_Jeans_rho_norm) ** (EAGLEfloor_Jeans_gamma_effective - 1.0 ) 
+
+########################################################################3
+
+# Plot the phase space diagram
+figure()
+subplot(111, xscale="log", yscale="log")
+plot(eos_cool_rho, eos_cool_T, "k--", lw=0.6)
+plot(eos_Jeans_rho, eos_Jeans_T, "k--", lw=0.6)
+scatter(gas_nH, gas_T, s=0.2)
+xlabel("${\\rm Density}~n_{\\rm H}~[{\\rm cm^{-3}}]$", labelpad=0)
+ylabel("${\\rm Temperature}~T~[{\\rm K}]$", labelpad=2)
+xlim(3e-6, 3e3)
+ylim(500.0, 2e5)
+savefig("rhoT.png", dpi=200)
+
+# Plot the phase space diagram for SF gas
+figure()
+subplot(111, xscale="log", yscale="log")
+plot(eos_cool_rho, eos_cool_T, "k--", lw=0.6)
+plot(eos_Jeans_rho, eos_Jeans_T, "k--", lw=0.6)
+plot([SF_thresh, SF_thresh], [1, 1e10], "k:", lw=0.6)
+text(SF_thresh*0.9, 2e4, "$n_{\\rm H, thresh}=%.3f~{\\rm cm^{-3}}$"%SF_thresh, fontsize=8, rotation=90, ha="right", va="bottom")
+scatter(gas_nH[gas_SFR > 0.0], gas_T[gas_SFR > 0.0], s=0.2)
+xlabel("${\\rm Density}~n_{\\rm H}~[{\\rm cm^{-3}}]$", labelpad=0)
+ylabel("${\\rm Temperature}~T~[{\\rm K}]$", labelpad=2)
+xlim(3e-6, 3e3)
+ylim(500.0, 2e5)
+savefig("rhoT_SF.png", dpi=200)
+
+########################################################################3
+
+# 3D Density vs SFR
+figure()
+subplot(111, xscale="log", yscale="log")
+scatter(gas_nH, gas_SFR, s=0.2)
+plot([1, 100], 2e-5 * np.array([1, 100]) ** 0.266667, "k--", lw=1)
+xlabel("${\\rm Density}~n_{\\rm H}~[{\\rm cm^{-3}}]$", labelpad=0)
+ylabel("${\\rm SFR}~[{\\rm M_\\odot~\\cdot~yr^{-1}}]$", labelpad=-7)
+xlim(1e-4, 3e3)
+ylim(8e-6, 2.5e-4)
+savefig("rho_SFR.png", dpi=200)
+
+########################################################################3
+
+star_mask = (
+    (stars_pos[:, 0] > -15)
+    & (stars_pos[:, 0] < 15)
+    & (stars_pos[:, 1] > -15)
+    & (stars_pos[:, 1] < 15)
+    & (stars_pos[:, 2] < 1.0)
+    & (stars_pos[:, 2] > -1.0)
+)
+
+stars_BirthDensity = stars_BirthDensity[star_mask] 
+#stars_BirthFlag = stars_BirthFlag[star_mask]
+stars_BirthTime = stars_BirthTime[star_mask]
+
+# Histogram of the birth density
+figure()
+subplot(111, xscale="linear", yscale="linear")
+hist(np.log10(stars_BirthDensity),density=True,bins=20,range=[-2,5])
+xlabel("${\\rm Stellar~birth~density}~n_{\\rm H}~[{\\rm cm^{-3}}]$", labelpad=0)
+ylabel("${\\rm Probability}$", labelpad=-7)
+savefig("BirthDensity.png", dpi=200)
+
+# Plot of the specific star formation rate in the galaxy
+rhos = 10**np.linspace(-1,np.log10(KS_high_den_thresh),100)
+rhoshigh = 10**np.linspace(np.log10(KS_high_den_thresh),5,100)
+
+P_effective = EOS_press_norm * ( rhos / EOS_density_norm)**(EOS_gamma_effective)
+P_norm_high = EOS_press_norm * (KS_high_den_thresh  / EOS_density_norm)**(EOS_gamma_effective)
+sSFR = KS_law_norm_cgs * (Msun_p_pc2)**(-KS_law_slope) * (gamma/G_in_cgs * KS_gas_fraction *P_effective)**((KS_law_slope-1.)/2.)
+KS_law_norm_high_den_cgs = KS_law_norm_cgs * (Msun_p_pc2)**(-KS_law_slope) * (gamma/G_in_cgs * KS_gas_fraction * P_norm_high)**((KS_law_slope-1.)/2.)
+sSFR_high_den = KS_law_norm_high_den_cgs * ((rhoshigh/KS_high_den_thresh)**EOS_gamma_effective)**((KS_law_slope_high_den-1)/2.)
+
+# density - sSFR plane
+figure()
+subplot(111)
+hist2d(np.log10(gas_nH), np.log10(gas_sSFR), bins=50,range=[[-1.5,5],[-.5,2.5]])
+plot(np.log10(rhos),np.log10(sSFR)+np.log10(year_in_cgs)+9.,'k--',label='sSFR low density EAGLE')
+plot(np.log10(rhoshigh),np.log10(sSFR_high_den)+np.log10(year_in_cgs)+9.,'k--',label='sSFR high density EAGLE')
+xlabel("${\\rm Density}~n_{\\rm H}~[{\\rm cm^{-3}}]$", labelpad=2)
+ylabel("${\\rm sSFR}~[{\\rm Gyr^{-1}}]$", labelpad=0)
+xticks([-1, 0, 1, 2, 3, 4], ["$10^{-1}$", "$10^0$", "$10^1$", "$10^2$", "$10^3$", "$10^4$"])
+yticks([0, 1, 2], ["$10^0$", "$10^1$", "$10^2$"])
+xlim(-1.4, 4.9)
+ylim(-0.5, 2.2)
+savefig("density-sSFR.png", dpi=200)
+
+########################################################################3
+
+# Select gas in a pillow box around the galaxy
+mask = (
+    (gas_pos[:, 0] > -15)
+    & (gas_pos[:, 0] < 15)
+    & (gas_pos[:, 1] > -15)
+    & (gas_pos[:, 1] < 15)
+    & (gas_pos[:, 2] < 1.0)
+    & (gas_pos[:, 2] > -1.0)
+)
+gas_pos = gas_pos[mask, :]
+gas_SFR = gas_SFR[mask]
+gas_nH = gas_nH[mask]
+gas_rho = gas_rho[mask]
+gas_T = gas_T[mask]
+gas_mass = gas_mass[mask]
+gas_Z = gas_Z[mask]
+gas_hsml = gas_hsml[mask]
+
+
+# Make a crude map of the gas
+figure()
+subplot(111)
+scatter(gas_pos[:, 0], gas_pos[:, 1], s=0.1)
+xlabel("${\\rm Pos}~x~[{\\rm kpc}]$", labelpad=0)
+ylabel("${\\rm Pos}~y~[{\\rm kpc}]$", labelpad=-3)
+xlim(-12, 12)
+ylim(-12, 12)
+savefig("face_on.png", dpi=200)
+
+figure()
+subplot(111)
+scatter(gas_pos[:, 0], gas_pos[:, 2], s=0.1)
+xlabel("${\\rm Pos}~x~[{\\rm kpc}]$", labelpad=0)
+ylabel("${\\rm Pos}~z~[{\\rm kpc}]$", labelpad=-3)
+xlim(-12, 12)
+ylim(-12, 12)
+savefig("edge_on.png", dpi=200)
+
+# Now a SF map
+rcParams.update({"figure.figsize": (4.15, 3.15)})
+figure()
+subplot(111)
+scatter(gas_pos[:, 0], gas_pos[:, 1], s=0.1, c=gas_SFR)
+xlabel("${\\rm Pos}~x~[{\\rm kpc}]$", labelpad=0)
+ylabel("${\\rm Pos}~y~[{\\rm kpc}]$", labelpad=-3)
+colorbar()
+xlim(-12, 12)
+ylim(-12, 12)
+savefig("SF_face_on.png", dpi=200)
+
+
+########################################################################3
+
+# Bin the data in kpc-size patches
+
+x_edges = np.linspace(-15, 15, 31)
+y_edges = np.linspace(-15, 15, 31)
+
+map_mass, _, _, _ = stats.binned_statistic_2d(
+    gas_pos[:, 0], gas_pos[:, 1], gas_mass, statistic="sum", bins=(x_edges, y_edges)
+)
+map_SFR, _, _, _ = stats.binned_statistic_2d(
+    gas_pos[:, 0], gas_pos[:, 1], gas_SFR, statistic="sum", bins=(x_edges, y_edges)
+)
+
+# Mass map
+figure()
+subplot(111)
+pcolormesh(x_edges, y_edges, np.log10(map_mass))
+colorbar()
+xlim(-12, 12)
+ylim(-12, 12)
+xlabel("${\\rm Pos}~x~[{\\rm kpc}]$", labelpad=0)
+ylabel("${\\rm Pos}~y~[{\\rm kpc}]$", labelpad=-3)
+savefig("Map_mass.png", dpi=200)
+
+# SF map
+figure()
+subplot(111)
+pcolormesh(x_edges, y_edges, np.log10(map_SFR), vmax=-0.5, vmin=-4.5)
+colorbar()
+xlim(-12, 12)
+ylim(-12, 12)
+xlabel("${\\rm Pos}~x~[{\\rm kpc}]$", labelpad=0)
+ylabel("${\\rm Pos}~y~[{\\rm kpc}]$", labelpad=-3)
+savefig("Map_SFR.png", dpi=200)
+
+#########################################################################
+
+# Give a minimum SF surface density for the plots
+map_SFR[map_SFR < 1e-6] = 1e-6
+
+# Theoretical threshold (assumes all gas has the same Z)
+KS_n_thresh = KS_thresh_norm * (gas_Z[0] / KS_thresh_Z0) ** KS_thresh_slope
+if np.isfinite(KS_n_thresh) == False:
+    KS_n_thresh = KS_thresh_max_norm
+KS_sigma_thresh = 29.0 * np.sqrt(KS_gas_fraction) * np.sqrt(KS_n_thresh)
+
+# Theoretical KS law
+KS_sigma_mass = np.logspace(-1, 3, 100)
+KS_sigma_SFR = KS_law_norm * KS_sigma_mass ** KS_law_slope
+
+# KS relation
+rcParams.update({"figure.figsize": (3.15, 3.15), "figure.subplot.left": 0.18})
+figure()
+subplot(111, xscale="log", yscale="log")
+plot(KS_sigma_mass, KS_sigma_SFR, "k--", lw=0.6)
+plot([KS_sigma_thresh, KS_sigma_thresh], [1e-8, 1e8], "k--", lw=0.6)
+text(
+    KS_sigma_thresh * 0.95,
+    2.2,
+    "$\\Sigma_{\\rm c} = %.2f~{\\rm M_\\odot\\cdot pc^{-2}}$" % KS_sigma_thresh,
+    va="top",
+    ha="right",
+    rotation=90,
+    fontsize=7,
+)
+text(16, 10 ** (-3.5), "$n_{\\rm H,c} = %.3f~{\\rm cm^{-3}}$" % KS_n_thresh, fontsize=7)
+text(
+    16,
+    2e-6,
+    "${\\rm K\\textendash S~law}$:\n$\\Sigma_{\\rm SFR} = A \\times \\Sigma_g^n$\n$n=%.1f$\n$A=%.3f\\times10^{-4}~{\\rm M_\\odot / yr^{1} / kpc^{2}}$\n$f_{\\rm g} = %.1f$\n$\gamma_{\\rm eos} = %.3f$\n$Z=%1.4f$"
+    % (
+        KS_law_slope,
+        KS_law_norm * 10 ** 4,
+        KS_gas_fraction,
+        EOS_gamma_effective,
+        EAGLE_Z,
+    ),
+    fontsize=7,
+)
+scatter(map_mass.flatten() / 1e6, map_SFR.flatten(), s=0.4)
+xlim(0.3, 900)
+ylim(3e-7, 3)
+xlabel("$\\Sigma_g~[{\\rm M_\\odot\\cdot pc^{-2}}]$", labelpad=0)
+ylabel(
+    "$\\Sigma_{\\rm SFR}~[{\\rm M_\\odot \\cdot yr^{-1} \\cdot kpc^{-2}}]$", labelpad=0
+)
+savefig("KS_law.png", dpi=200)
+close()
diff --git a/examples/IsolatedGalaxy/IsolatedGalaxy_feedback/plot_box_evolution.py b/examples/IsolatedGalaxy/IsolatedGalaxy_feedback/plot_box_evolution.py
new file mode 100644
index 0000000000000000000000000000000000000000..67da3c390be1240323941b835e056dcd6e27feed
--- /dev/null
+++ b/examples/IsolatedGalaxy/IsolatedGalaxy_feedback/plot_box_evolution.py
@@ -0,0 +1,155 @@
+###############################################################################
+ # This file is part of SWIFT.
+ # Copyright (c) 2015 Bert Vandenbroucke (bert.vandenbroucke@ugent.be)
+ #                    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/>.
+ # 
+ ##############################################################################
+
+import matplotlib
+matplotlib.use("Agg")
+from pylab import *
+from scipy import stats
+import h5py
+import numpy as np
+import glob
+import os.path
+
+def find_indices(a,b):
+        result = np.zeros(len(b))
+        for i in range(len(b)):
+                result[i] = ((np.where(a == b[i]))[0])[0]
+
+        return result
+
+
+# Plot parameters
+params = {'axes.labelsize': 10,
+'axes.titlesize': 10,
+'font.size': 12,
+'legend.fontsize': 12,
+'xtick.labelsize': 10,
+'ytick.labelsize': 10,
+'text.usetex': True,
+ 'figure.figsize' : (9.90,6.45),
+'figure.subplot.left'    : 0.1,
+'figure.subplot.right'   : 0.99,
+'figure.subplot.bottom'  : 0.1,
+'figure.subplot.top'     : 0.95,
+'figure.subplot.wspace'  : 0.2,
+'figure.subplot.hspace'  : 0.2,
+'lines.markersize' : 6,
+'lines.linewidth' : 3.,
+'text.latex.unicode': True
+}
+rcParams.update(params)
+rc('font',**{'family':'sans-serif','sans-serif':['Times']})
+
+
+# Number of snapshots and elements
+newest_snap_name = max(glob.glob('output_*.hdf5'), key=os.path.getctime)
+n_snapshots = int(newest_snap_name.replace('output_','').replace('.hdf5','')) + 1
+n_elements = 9
+
+# Read the simulation data
+sim = h5py.File("output_0000.hdf5", "r")
+boxSize = sim["/Header"].attrs["BoxSize"][0]
+time = sim["/Header"].attrs["Time"][0]
+scheme = sim["/HydroScheme"].attrs["Scheme"]
+kernel = sim["/HydroScheme"].attrs["Kernel function"]
+neighbours = sim["/HydroScheme"].attrs["Kernel target N_ngb"]
+eta = sim["/HydroScheme"].attrs["Kernel eta"]
+git = sim["Code"].attrs["Git Revision"]
+stellar_mass = sim["/PartType4/Masses"][0]
+
+# Units
+unit_length_in_cgs = sim["/Units"].attrs["Unit length in cgs (U_L)"]
+unit_mass_in_cgs = sim["/Units"].attrs["Unit mass in cgs (U_M)"]
+unit_time_in_cgs = sim["/Units"].attrs["Unit time in cgs (U_t)"]
+unit_temp_in_cgs = sim["/Units"].attrs["Unit temperature in cgs (U_T)"]
+unit_vel_in_cgs = unit_length_in_cgs / unit_time_in_cgs
+unit_energy_in_cgs = unit_mass_in_cgs * unit_vel_in_cgs * unit_vel_in_cgs
+unit_length_in_si = 0.01 * unit_length_in_cgs
+unit_mass_in_si = 0.001 * unit_mass_in_cgs
+unit_time_in_si = unit_time_in_cgs
+unit_density_in_cgs = unit_mass_in_cgs*unit_length_in_cgs**-3
+unit_pressure_in_cgs = unit_mass_in_cgs/unit_length_in_cgs*unit_time_in_cgs**-2
+unit_int_energy_in_cgs = unit_energy_in_cgs/unit_mass_in_cgs
+unit_entropy_in_cgs = unit_energy_in_cgs/unit_temp_in_cgs
+Gyr_in_cgs = 3.155e16
+Msun_in_cgs = 1.989e33
+
+box_energy = zeros(n_snapshots)
+box_mass = zeros(n_snapshots)
+box_star_mass = zeros(n_snapshots)
+box_metal_mass = zeros(n_snapshots)
+element_mass = zeros((n_snapshots,n_elements))
+t = zeros(n_snapshots)
+
+# Read data from snapshots
+for i in range(n_snapshots):
+	print("reading snapshot "+str(i))
+	# Read the simulation data
+	sim = h5py.File("output_%04d.hdf5"%i, "r")
+	t[i] = sim["/Header"].attrs["Time"][0]
+	#ids = sim["/PartType0/ParticleIDs"][:]
+	
+	masses = sim["/PartType0/Masses"][:]
+	box_mass[i] = np.sum(masses)
+	
+	star_masses = sim["/PartType4/Masses"][:]
+	box_star_mass[i] = np.sum(star_masses)
+	
+	metallicities = sim["/PartType0/Metallicity"][:]
+	box_metal_mass[i] = np.sum(metallicities * masses)
+	
+	internal_energies = sim["/PartType0/InternalEnergy"][:]
+	box_energy[i] = np.sum(masses * internal_energies)
+
+# Plot the interesting quantities
+figure()
+
+# Box mass --------------------------------
+subplot(221)
+plot(t[1:] * unit_time_in_cgs / Gyr_in_cgs, (box_mass[1:] - box_mass[0])* unit_mass_in_cgs / Msun_in_cgs, linewidth=0.5, color='k', marker = "*", ms=0.5, label='swift')
+xlabel("${\\rm{Time}} (Gyr)$", labelpad=0)
+ylabel("Change in total gas particle mass (Msun)", labelpad=2)
+ticklabel_format(style='sci', axis='y', scilimits=(0,0))
+
+# Box metal mass --------------------------------
+subplot(222)
+plot(t[1:] * unit_time_in_cgs / Gyr_in_cgs, (box_metal_mass[1:] - box_metal_mass[0])* unit_mass_in_cgs / Msun_in_cgs, linewidth=0.5, color='k', ms=0.5, label='swift')
+xlabel("${\\rm{Time}} (Gyr)$", labelpad=0)
+ylabel("Change in total metal mass of gas particles (Msun)", labelpad=2)
+ticklabel_format(style='sci', axis='y', scilimits=(0,0))
+
+# Box energy --------------------------------
+subplot(223)
+plot(t[1:] * unit_time_in_cgs / Gyr_in_cgs, (box_energy[1:] - box_energy[0])* unit_energy_in_cgs, linewidth=0.5, color='k', ms=0.5, label='swift')
+xlabel("${\\rm{Time}} (Gyr)$", labelpad=0)
+ylabel("Change in total energy of gas particles (erg)", labelpad=2)
+ticklabel_format(style='sci', axis='y', scilimits=(0,0))
+
+# Box mass --------------------------------
+subplot(224)
+plot(t[1:] * unit_time_in_cgs / Gyr_in_cgs, (box_mass[1:] - box_mass[0])* unit_mass_in_cgs / Msun_in_cgs, linewidth=0.5, color='k', marker = "*", ms=0.5, label='gas')
+plot(t[1:] * unit_time_in_cgs / Gyr_in_cgs, (box_star_mass[1:] - box_star_mass[n_snapshots-1])* unit_mass_in_cgs / Msun_in_cgs, linewidth=0.5, color='r', marker = "*", ms=0.5, label='stars')
+plot(t[1:] * unit_time_in_cgs / Gyr_in_cgs, (box_star_mass[1:] - box_star_mass[n_snapshots-1] + box_mass[1:] - box_mass[0])* unit_mass_in_cgs / Msun_in_cgs, linewidth=0.5, color='g', marker = "*", ms=0.5, label='total')
+xlabel("${\\rm{Time}} (Gyr)$", labelpad=0)
+ylabel("Change in total gas particle mass (Msun)", labelpad=2)
+ticklabel_format(style='sci', axis='y', scilimits=(0,0))
+legend()
+
+savefig("box_evolution.png", dpi=200)
diff --git a/examples/IsolatedGalaxy/IsolatedGalaxy_feedback/run.sh b/examples/IsolatedGalaxy/IsolatedGalaxy_feedback/run.sh
new file mode 100755
index 0000000000000000000000000000000000000000..f0f8e262fc967011d4f7094d068f4dabe23948b1
--- /dev/null
+++ b/examples/IsolatedGalaxy/IsolatedGalaxy_feedback/run.sh
@@ -0,0 +1,27 @@
+#!/bin/bash
+
+if [ ! -e lowres8.hdf5 ] 
+then     
+    echo "Fetching initial conditions for the isolated galaxy example..."
+    ./getIC.sh
+fi
+
+if [ ! -e coolingtables ] 
+then     
+    echo "Fetching EAGLE cooling tables for the isolated galaxy example..."
+    ./getEagleCoolingTable.sh
+fi
+
+if [ ! -e yieldtables ] 
+then     
+    echo "Fetching EAGLE stellar yield tables for the isolated galaxy example..."
+    ./getYieldTable.sh
+fi
+
+../../swift --threads=16 --feedback --external-gravity --self-gravity --stars --star-formation --cooling --hydro isolated_galaxy.yml 2>&1 | tee output.log
+
+# Kennicutt-Schmidt law plot
+python3 plotSolution.py
+
+# Plot that the random star formation matches the expected SFH
+python3 SFH.py
diff --git a/examples/SubgridTests/StellarEvolution/README b/examples/SubgridTests/StellarEvolution/README
new file mode 100644
index 0000000000000000000000000000000000000000..44a4836e523d4037e5f942e01e444599fa009c1a
--- /dev/null
+++ b/examples/SubgridTests/StellarEvolution/README
@@ -0,0 +1,7 @@
+Example for testing EAGLE stellar feedback. This consists of a uniform box of gas with a star in the center. The amount of feedback can then be checked by summing over the gas particles in the whole box and comparing to the expected amount of feedback from a single star over a given time period. 
+
+If only mass enrichment is of interest, the box can be run with ICs generated from a smaller glass (eg glassCube_32.hdf5). In this case, however it is necessary to turn off energy feedback (eg. by setting the return value of compute_SNe in src/stars/EAGLE/stars.h to zero) or using a larger glass (glassCube_64.hdf5). 
+
+Use the python script, plot_box_evolution.py to compare total mass evolution of gas particles in the whole box with what is expected based on EAGLE standalone feedback test.
+
+Use plot_paricle_evolution.py to plot the evolution of particles starting in the viscinity of the star at the beginning of the simulation. 
diff --git a/examples/SubgridTests/StellarEvolution/check_continuous_heating.py b/examples/SubgridTests/StellarEvolution/check_continuous_heating.py
new file mode 100644
index 0000000000000000000000000000000000000000..f3c1b5d7fd682d914f2dbc05259c2dab0baf1e32
--- /dev/null
+++ b/examples/SubgridTests/StellarEvolution/check_continuous_heating.py
@@ -0,0 +1,137 @@
+# Script for plotting energy evolution of uniform box of gas with single star in the 
+# centre when running with stochastic energy injection. It also checks that the change
+# in total energy of the gas particles is within a specified tolerance from what is 
+# expected based on the mass of the star particle (Note that this tolerance could be
+# somewhat high because of Poisson noise and the relatively small number of injection
+# events)
+
+import matplotlib
+matplotlib.use("Agg")
+from pylab import *
+import h5py
+import os.path
+import numpy as np
+import glob
+
+# Number of snapshots and elements
+newest_snap_name = max(glob.glob('stellar_evolution_*.hdf5'), key=os.path.getctime)
+n_snapshots = int(newest_snap_name.replace('stellar_evolution_','').replace('.hdf5','')) + 1
+n_elements = 9
+
+# Plot parameters
+params = {'axes.labelsize': 10,
+'axes.titlesize': 10,
+'font.size': 9,
+'legend.fontsize': 9,
+'xtick.labelsize': 10,
+'ytick.labelsize': 10,
+'text.usetex': True,
+ 'figure.figsize' : (3.15,3.15),
+'figure.subplot.left'    : 0.3,
+'figure.subplot.right'   : 0.99,
+'figure.subplot.bottom'  : 0.18,
+'figure.subplot.top'     : 0.92,
+'figure.subplot.wspace'  : 0.21,
+'figure.subplot.hspace'  : 0.19,
+'lines.markersize' : 6,
+'lines.linewidth' : 2.,
+'text.latex.unicode': True
+}
+
+rcParams.update(params)
+rc('font',**{'family':'sans-serif','sans-serif':['Times']})
+
+# Read the simulation data
+sim = h5py.File("stellar_evolution_0000.hdf5", "r")
+boxSize = sim["/Header"].attrs["BoxSize"][0]
+scheme = sim["/HydroScheme"].attrs["Scheme"][0]
+kernel = sim["/HydroScheme"].attrs["Kernel function"][0]
+neighbours = sim["/HydroScheme"].attrs["Kernel target N_ngb"][0]
+eta = sim["/HydroScheme"].attrs["Kernel eta"][0]
+alpha = sim["/HydroScheme"].attrs["Alpha viscosity"][0]
+H_mass_fraction = sim["/HydroScheme"].attrs["Hydrogen mass fraction"][0]
+H_transition_temp = sim["/HydroScheme"].attrs["Hydrogen ionization transition temperature"][0]
+T_initial = sim["/HydroScheme"].attrs["Initial temperature"][0]
+T_minimal = sim["/HydroScheme"].attrs["Minimal temperature"][0]
+git = sim["Code"].attrs["Git Revision"]
+star_initial_mass = sim["/PartType4/Masses"][0]
+
+# Cosmological parameters
+H_0 = sim["/Cosmology"].attrs["H0 [internal units]"][0]
+gas_gamma = sim["/HydroScheme"].attrs["Adiabatic index"][0]
+
+# Units
+unit_length_in_cgs = sim["/Units"].attrs["Unit length in cgs (U_L)"]
+unit_mass_in_cgs = sim["/Units"].attrs["Unit mass in cgs (U_M)"]
+unit_time_in_cgs = sim["/Units"].attrs["Unit time in cgs (U_t)"]
+unit_vel_in_cgs = unit_length_in_cgs / unit_time_in_cgs
+unit_energy_in_cgs = unit_mass_in_cgs * unit_vel_in_cgs * unit_vel_in_cgs
+unit_length_in_si = 0.01 * unit_length_in_cgs
+unit_mass_in_si = 0.001 * unit_mass_in_cgs
+unit_time_in_si = unit_time_in_cgs
+
+# Calculate solar mass in internal units
+const_solar_mass = 1.98848e33 / unit_mass_in_cgs
+
+# Define Gyr
+Gyr_in_cgs = 1e9 * 365 * 24 * 3600.
+
+# Find out how many particles (gas and star) we have
+n_parts = sim["/Header"].attrs["NumPart_Total"][0]
+n_sparts = sim["/Header"].attrs["NumPart_Total"][4]
+
+# Declare arrays for data
+masses = zeros((n_parts,n_snapshots))
+star_masses = zeros((n_sparts,n_snapshots))
+internal_energy = zeros((n_parts,n_snapshots))
+velocity_parts = zeros((n_parts,3,n_snapshots))
+time = zeros(n_snapshots)
+
+# Read fields we are checking from snapshots
+#for i in [0,n_snapshots-1]:
+for i in range(n_snapshots):
+	sim = h5py.File("stellar_evolution_%04d.hdf5"%i, "r")
+	print('reading snapshot '+str(i))
+	masses[:,i] = sim["/PartType0/Masses"]
+	internal_energy[:,i] = sim["/PartType0/InternalEnergy"]
+	velocity_parts[:,:,i] = sim["/PartType0/Velocities"]
+	time[i] = sim["/Header"].attrs["Time"][0]
+
+# Check that the total amount of enrichment is as expected.
+# Define tolerance. Note, relatively high value used due to
+# Poisson noise associated with stochastic energy injection.
+eps = 0.15
+
+# Stochastic heating
+vel2 = zeros((n_parts,n_snapshots))
+vel2[:,:] = velocity_parts[:,0,:]*velocity_parts[:,0,:] + velocity_parts[:,1,:]*velocity_parts[:,1,:] + velocity_parts[:,2,:]*velocity_parts[:,2,:]
+total_kinetic_energy_cgs = np.sum(np.multiply(vel2,masses)*0.5,axis = 0) * unit_energy_in_cgs
+total_energy_cgs = np.sum(np.multiply(internal_energy,masses),axis = 0) * unit_energy_in_cgs
+total_energy_released_cgs = total_energy_cgs[n_snapshots-1] - total_energy_cgs[0] + total_kinetic_energy_cgs[n_snapshots-1] - total_kinetic_energy_cgs[0]
+
+# Calculate energy released
+energy_per_sn = 1.0e51 / unit_energy_in_cgs
+SNIa_efficiency = 2.e-3
+SNIa_timescale_Gyr = 2.0
+expected_energy_released_cgs = np.zeros(n_snapshots)
+for i in range(n_snapshots):
+	age_Gyr = time[i] * unit_time_in_cgs / Gyr_in_cgs
+	total_sn = SNIa_efficiency * (1.0 - np.exp(-age_Gyr/SNIa_timescale_Gyr)) / const_solar_mass
+	expected_energy_released_cgs[i] = total_sn * energy_per_sn * unit_energy_in_cgs
+
+# Did we get it right?
+if abs(total_energy_released_cgs - expected_energy_released_cgs[n_snapshots-1])/expected_energy_released_cgs[n_snapshots-1] < eps:
+	print("total stochastic energy release consistent with expectation. total stochastic energy release "+str(total_energy_released_cgs)+" expected "+ str(expected_energy_released_cgs[n_snapshots-1]) + " initial total internal energy "+ str(total_energy_cgs[0] + total_kinetic_energy_cgs[0]))
+else:
+	print("total stochastic energy release "+str(total_energy_released_cgs)+" expected "+ str(expected_energy_released_cgs[n_snapshots-1]) + " initial total internal energy "+ str(total_energy_cgs[0] + total_kinetic_energy_cgs[0]) + " energy change fraction of total " + str(total_energy_released_cgs/(total_energy_cgs[0]+total_kinetic_energy_cgs[0])))
+
+# Plot the energy evolution
+figure()
+subplot(111)
+plot(time*unit_time_in_cgs/Gyr_in_cgs, total_energy_cgs + total_kinetic_energy_cgs - total_energy_cgs[0] - total_kinetic_energy_cgs[0],color='k', linewidth=0.5, label="SWIFT")
+plot(time*unit_time_in_cgs/Gyr_in_cgs, expected_energy_released_cgs,color = 'r', linewidth=0.5, label="expected")
+xlabel("Time (Gyr)")
+ylabel("Total energy (erg)")
+legend()
+savefig("continuous_energy_evolution.png", dpi=200)
+
diff --git a/examples/SubgridTests/StellarEvolution/check_stellar_evolution.py b/examples/SubgridTests/StellarEvolution/check_stellar_evolution.py
new file mode 100644
index 0000000000000000000000000000000000000000..02c1e9343de7b58cfddc8dee3bf0215a4b80ccf4
--- /dev/null
+++ b/examples/SubgridTests/StellarEvolution/check_stellar_evolution.py
@@ -0,0 +1,203 @@
+import matplotlib
+matplotlib.use("Agg")
+from pylab import *
+import h5py
+import os.path
+import numpy as np
+import glob
+
+# Number of snapshots and elements
+newest_snap_name = max(glob.glob('stellar_evolution_*.hdf5'), key=os.path.getctime)
+n_snapshots = int(newest_snap_name.replace('stellar_evolution_','').replace('.hdf5','')) + 1
+n_elements = 9
+
+# Plot parameters
+params = {'axes.labelsize': 10,
+'axes.titlesize': 10,
+'font.size': 9,
+'legend.fontsize': 9,
+'xtick.labelsize': 10,
+'ytick.labelsize': 10,
+'text.usetex': True,
+ 'figure.figsize' : (3.15,3.15),
+'figure.subplot.left'    : 0.3,
+'figure.subplot.right'   : 0.99,
+'figure.subplot.bottom'  : 0.18,
+'figure.subplot.top'     : 0.92,
+'figure.subplot.wspace'  : 0.21,
+'figure.subplot.hspace'  : 0.19,
+'lines.markersize' : 6,
+'lines.linewidth' : 2.,
+'text.latex.unicode': True
+}
+
+rcParams.update(params)
+rc('font',**{'family':'sans-serif','sans-serif':['Times']})
+
+# Read the simulation data
+sim = h5py.File("stellar_evolution_0000.hdf5", "r")
+boxSize = sim["/Header"].attrs["BoxSize"][0]
+scheme = sim["/HydroScheme"].attrs["Scheme"][0]
+kernel = sim["/HydroScheme"].attrs["Kernel function"][0]
+neighbours = sim["/HydroScheme"].attrs["Kernel target N_ngb"][0]
+eta = sim["/HydroScheme"].attrs["Kernel eta"][0]
+alpha = sim["/HydroScheme"].attrs["Alpha viscosity"][0]
+H_mass_fraction = sim["/HydroScheme"].attrs["Hydrogen mass fraction"][0]
+H_transition_temp = sim["/HydroScheme"].attrs["Hydrogen ionization transition temperature"][0]
+T_initial = sim["/HydroScheme"].attrs["Initial temperature"][0]
+T_minimal = sim["/HydroScheme"].attrs["Minimal temperature"][0]
+git = sim["Code"].attrs["Git Revision"]
+star_initial_mass = sim["/PartType4/Masses"][0]
+
+# Cosmological parameters
+H_0 = sim["/Cosmology"].attrs["H0 [internal units]"][0]
+gas_gamma = sim["/HydroScheme"].attrs["Adiabatic index"][0]
+
+# Units
+unit_length_in_cgs = sim["/Units"].attrs["Unit length in cgs (U_L)"]
+unit_mass_in_cgs = sim["/Units"].attrs["Unit mass in cgs (U_M)"]
+unit_time_in_cgs = sim["/Units"].attrs["Unit time in cgs (U_t)"]
+unit_vel_in_cgs = unit_length_in_cgs / unit_time_in_cgs
+unit_energy_in_cgs = unit_mass_in_cgs * unit_vel_in_cgs * unit_vel_in_cgs
+unit_length_in_si = 0.01 * unit_length_in_cgs
+unit_mass_in_si = 0.001 * unit_mass_in_cgs
+unit_time_in_si = unit_time_in_cgs
+
+# Find out how many particles (gas and star) we have
+n_parts = sim["/Header"].attrs["NumPart_Total"][0]
+n_sparts = sim["/Header"].attrs["NumPart_Total"][4]
+
+# Declare arrays for data
+masses = zeros((n_parts,n_snapshots))
+star_masses = zeros((n_sparts,n_snapshots))
+mass_from_AGB = zeros((n_parts,n_snapshots))
+metal_mass_frac_from_AGB = zeros((n_parts,n_snapshots))
+mass_from_SNII = zeros((n_parts,n_snapshots))
+metal_mass_frac_from_SNII = zeros((n_parts,n_snapshots))
+mass_from_SNIa = zeros((n_parts,n_snapshots))
+metal_mass_frac_from_SNIa = zeros((n_parts,n_snapshots))
+iron_mass_frac_from_SNIa = zeros((n_parts,n_snapshots))
+metallicity = zeros((n_parts,n_snapshots))
+abundances = zeros((n_parts,n_elements,n_snapshots))
+internal_energy = zeros((n_parts,n_snapshots))
+coord_parts = zeros((n_parts,3))
+velocity_parts = zeros((n_parts,3,n_snapshots))
+coord_sparts = zeros(3)
+time = zeros(n_snapshots)
+
+# Read fields we are checking from snapshots
+for i in range(n_snapshots):
+	sim = h5py.File("stellar_evolution_%04d.hdf5"%i, "r")
+	print('reading snapshot '+str(i))
+	abundances[:,:,i] = sim["/PartType0/ElementAbundance"]
+	metallicity[:,i] = sim["/PartType0/Metallicity"]
+	masses[:,i] = sim["/PartType0/Masses"]
+	star_masses[:,i] = sim["/PartType4/Masses"]
+	mass_from_AGB[:,i] = sim["/PartType0/TotalMassFromAGB"]
+	metal_mass_frac_from_AGB[:,i] = sim["/PartType0/MetalMassFracFromAGB"]
+	mass_from_SNII[:,i] = sim["/PartType0/TotalMassFromSNII"]
+	metal_mass_frac_from_SNII[:,i] = sim["/PartType0/MetalMassFracFromSNII"]
+	mass_from_SNIa[:,i] = sim["/PartType0/TotalMassFromSNIa"]
+	metal_mass_frac_from_SNIa[:,i] = sim["/PartType0/MetalMassFracFromSNIa"]
+	iron_mass_frac_from_SNIa[:,i] = sim["/PartType0/IronMassFracFromSNIa"]
+	internal_energy[:,i] = sim["/PartType0/InternalEnergy"]
+	velocity_parts[:,:,i] = sim["/PartType0/Velocities"]
+	time[i] = sim["/Header"].attrs["Time"][0]
+
+# Define ejecta factor
+ejecta_factor = 1.0e-2
+ejecta_factor_metallicity = 1.0 - 2.0/n_elements
+ejecta_factor_abundances = 1.0/n_elements
+ejected_mass = star_initial_mass
+energy_per_SNe = 1.0e51/unit_energy_in_cgs
+
+# Check that the total amount of enrichment is as expected.
+# Define tolerance
+eps = 0.01
+
+# Total mass
+total_part_mass = np.sum(masses,axis = 0)
+if abs((total_part_mass[n_snapshots-1] - total_part_mass[0])/total_part_mass[0] - ejected_mass/total_part_mass[0])*total_part_mass[0]/ejected_mass < eps:
+	print("total mass released consistent with expectation")
+else:
+	print("mass increase "+str(total_part_mass[n_snapshots-1]/total_part_mass[0])+" expected "+ str(1.0+ejected_mass/total_part_mass[0]))
+
+# Check that mass is conserved (i.e. total star mass decreases by same amount as total gas mass increases)
+total_spart_mass = np.sum(star_masses,axis = 0)
+if abs((total_part_mass[n_snapshots-1] + total_spart_mass[n_snapshots-1]) / (total_part_mass[0] + total_spart_mass[0]) - 1.0) < eps**3:
+	print("total mass conserved")
+else:
+	print("initial part, spart mass " + str(total_part_mass[0]) + " " + str(total_spart_mass[0]) + " final mass " + str(total_part_mass[n_snapshots-1]) + " " + str(total_spart_mass[n_snapshots-1]))
+
+# Total metal mass from AGB
+total_metal_mass_AGB = np.sum(np.multiply(metal_mass_frac_from_AGB,masses),axis = 0)
+expected_metal_mass_AGB = ejecta_factor*ejected_mass
+if abs(total_metal_mass_AGB[n_snapshots-1] - expected_metal_mass_AGB)/expected_metal_mass_AGB < eps:
+	print("total AGB metal mass released consistent with expectation")
+else:
+	print("total AGB metal mass "+str(total_metal_mass_AGB[n_snapshots-1])+" expected "+ str(expected_metal_mass_AGB))
+
+# Total mass from AGB
+total_AGB_mass = np.sum(mass_from_AGB,axis = 0)
+expected_AGB_mass = ejecta_factor*ejected_mass
+if abs(total_AGB_mass[n_snapshots-1] - expected_AGB_mass)/expected_AGB_mass < eps:
+	print("total AGB mass released consistent with expectation")
+else:
+	print("total AGB mass "+str(total_AGB_mass[n_snapshots-1])+" expected "+ str(expected_AGB_mass))
+
+# Total metal mass from SNII
+total_metal_mass_SNII = np.sum(np.multiply(metal_mass_frac_from_SNII,masses),axis = 0)
+expected_metal_mass_SNII = ejecta_factor*ejected_mass
+if abs(total_metal_mass_SNII[n_snapshots-1] - expected_metal_mass_SNII)/expected_metal_mass_SNII < eps:
+	print("total SNII metal mass released consistent with expectation")
+else:
+	print("total SNII metal mass "+str(total_metal_mass_SNII[n_snapshots-1])+" expected "+ str(expected_metal_mass_SNII))
+
+# Total mass from SNII
+total_SNII_mass = np.sum(mass_from_SNII,axis = 0)
+expected_SNII_mass = ejecta_factor*ejected_mass
+if abs(total_SNII_mass[n_snapshots-1] - expected_SNII_mass)/expected_SNII_mass < eps:
+	print("total SNII mass released consistent with expectation")
+else:
+	print("total SNII mass "+str(total_SNII_mass[n_snapshots-1])+" expected "+ str(expected_SNII_mass))
+
+# Total metal mass from SNIa
+total_metal_mass_SNIa = np.sum(np.multiply(metal_mass_frac_from_SNIa,masses),axis = 0)
+expected_metal_mass_SNIa = ejecta_factor*ejected_mass
+if abs(total_metal_mass_SNIa[n_snapshots-1] - expected_metal_mass_SNIa)/expected_metal_mass_SNIa < eps:
+	print("total SNIa metal mass released consistent with expectation")
+else:
+	print("total SNIa metal mass "+str(total_metal_mass_SNIa[n_snapshots-1])+" expected "+ str(expected_metal_mass_SNIa))
+
+# Total iron mass from SNIa
+total_iron_mass_SNIa = np.sum(np.multiply(iron_mass_frac_from_SNIa,masses),axis = 0)
+expected_iron_mass_SNIa = ejecta_factor*ejected_mass
+if abs(total_iron_mass_SNIa[n_snapshots-1] - expected_iron_mass_SNIa)/expected_iron_mass_SNIa < eps:
+	print("total SNIa iron mass released consistent with expectation")
+else:
+	print("total SNIa iron mass "+str(total_iron_mass_SNIa[n_snapshots-1])+" expected "+ str(expected_iron_mass_SNIa))
+
+# Total mass from SNIa
+total_SNIa_mass = np.sum(mass_from_SNIa,axis = 0)
+expected_SNIa_mass = ejecta_factor*ejected_mass
+if abs(total_SNIa_mass[n_snapshots-1] - expected_SNIa_mass)/expected_SNIa_mass < eps:
+	print("total SNIa mass released consistent with expectation")
+else:
+	print("total SNIa mass "+str(total_SNIa_mass[n_snapshots-1])+" expected "+ str(expected_SNIa_mass))
+
+# Total metal mass
+total_metal_mass = np.sum(np.multiply(metallicity,masses),axis = 0)
+expected_metal_mass = ejecta_factor_metallicity*ejected_mass
+if abs(total_metal_mass[n_snapshots-1] - expected_metal_mass)/expected_metal_mass < eps:
+	print("total metal mass released consistent with expectation")
+else:
+	print("total metal mass "+str(total_metal_mass[n_snapshots-1])+" expected "+ str(expected_metal_mass))
+
+# Total mass for each element
+expected_element_mass = ejecta_factor_abundances*ejected_mass
+for i in range(n_elements):
+	total_element_mass = np.sum(np.multiply(abundances[:,i,:],masses),axis = 0)
+	if abs(total_element_mass[n_snapshots-1] - expected_element_mass)/expected_element_mass < eps:
+		print("total element mass released consistent with expectation for element "+str(i))
+	else:
+		print("total element mass "+str(total_element_mass[n_snapshots-1])+" expected "+ str(expected_element_mass) + " for element "+ str(i))
diff --git a/examples/SubgridTests/StellarEvolution/check_stochastic_heating.py b/examples/SubgridTests/StellarEvolution/check_stochastic_heating.py
new file mode 100644
index 0000000000000000000000000000000000000000..da837540041a9295a33b55e16b5e996394576cd7
--- /dev/null
+++ b/examples/SubgridTests/StellarEvolution/check_stochastic_heating.py
@@ -0,0 +1,137 @@
+# Script for plotting energy evolution of uniform box of gas with single star in the 
+# centre when running with stochastic energy injection. It also checks that the change
+# in total energy of the gas particles is within a specified tolerance from what is 
+# expected based on the mass of the star particle (Note that this tolerance could be
+# somewhat high because of Poisson noise and the relatively small number of injection
+# events)
+
+import matplotlib
+matplotlib.use("Agg")
+from pylab import *
+import h5py
+import os.path
+import numpy as np
+import glob
+
+# Number of snapshots and elements
+newest_snap_name = max(glob.glob('stellar_evolution_*.hdf5'), key=os.path.getctime)
+n_snapshots = int(newest_snap_name.replace('stellar_evolution_','').replace('.hdf5','')) + 1
+n_elements = 9
+
+# Plot parameters
+params = {'axes.labelsize': 10,
+'axes.titlesize': 10,
+'font.size': 9,
+'legend.fontsize': 9,
+'xtick.labelsize': 10,
+'ytick.labelsize': 10,
+'text.usetex': True,
+ 'figure.figsize' : (3.15,3.15),
+'figure.subplot.left'    : 0.3,
+'figure.subplot.right'   : 0.99,
+'figure.subplot.bottom'  : 0.18,
+'figure.subplot.top'     : 0.92,
+'figure.subplot.wspace'  : 0.21,
+'figure.subplot.hspace'  : 0.19,
+'lines.markersize' : 6,
+'lines.linewidth' : 2.,
+'text.latex.unicode': True
+}
+
+rcParams.update(params)
+rc('font',**{'family':'sans-serif','sans-serif':['Times']})
+
+# Read the simulation data
+sim = h5py.File("stellar_evolution_0000.hdf5", "r")
+boxSize = sim["/Header"].attrs["BoxSize"][0]
+scheme = sim["/HydroScheme"].attrs["Scheme"][0]
+kernel = sim["/HydroScheme"].attrs["Kernel function"][0]
+neighbours = sim["/HydroScheme"].attrs["Kernel target N_ngb"][0]
+eta = sim["/HydroScheme"].attrs["Kernel eta"][0]
+alpha = sim["/HydroScheme"].attrs["Alpha viscosity"][0]
+H_mass_fraction = sim["/HydroScheme"].attrs["Hydrogen mass fraction"][0]
+H_transition_temp = sim["/HydroScheme"].attrs["Hydrogen ionization transition temperature"][0]
+T_initial = sim["/HydroScheme"].attrs["Initial temperature"][0]
+T_minimal = sim["/HydroScheme"].attrs["Minimal temperature"][0]
+git = sim["Code"].attrs["Git Revision"]
+star_initial_mass = sim["/PartType4/Masses"][0]
+
+# Cosmological parameters
+H_0 = sim["/Cosmology"].attrs["H0 [internal units]"][0]
+gas_gamma = sim["/HydroScheme"].attrs["Adiabatic index"][0]
+
+# Units
+unit_length_in_cgs = sim["/Units"].attrs["Unit length in cgs (U_L)"]
+unit_mass_in_cgs = sim["/Units"].attrs["Unit mass in cgs (U_M)"]
+unit_time_in_cgs = sim["/Units"].attrs["Unit time in cgs (U_t)"]
+unit_vel_in_cgs = unit_length_in_cgs / unit_time_in_cgs
+unit_energy_in_cgs = unit_mass_in_cgs * unit_vel_in_cgs * unit_vel_in_cgs
+unit_length_in_si = 0.01 * unit_length_in_cgs
+unit_mass_in_si = 0.001 * unit_mass_in_cgs
+unit_time_in_si = unit_time_in_cgs
+
+# Calculate solar mass in internal units
+const_solar_mass = 1.98848e33 / unit_mass_in_cgs
+
+# Define Gyr
+Gyr_in_cgs = 1e9 * 365 * 24 * 3600.
+
+# Find out how many particles (gas and star) we have
+n_parts = sim["/Header"].attrs["NumPart_Total"][0]
+n_sparts = sim["/Header"].attrs["NumPart_Total"][4]
+
+# Declare arrays for data
+masses = zeros((n_parts,n_snapshots))
+star_masses = zeros((n_sparts,n_snapshots))
+internal_energy = zeros((n_parts,n_snapshots))
+velocity_parts = zeros((n_parts,3,n_snapshots))
+time = zeros(n_snapshots)
+
+# Read fields we are checking from snapshots
+#for i in [0,n_snapshots-1]:
+for i in range(n_snapshots):
+	sim = h5py.File("stellar_evolution_%04d.hdf5"%i, "r")
+	print('reading snapshot '+str(i))
+	masses[:,i] = sim["/PartType0/Masses"]
+	internal_energy[:,i] = sim["/PartType0/InternalEnergy"]
+	velocity_parts[:,:,i] = sim["/PartType0/Velocities"]
+	time[i] = sim["/Header"].attrs["Time"][0]
+
+# Check that the total amount of enrichment is as expected.
+# Define tolerance. Note, relatively high value used due to
+# Poisson noise associated with stochastic energy injection.
+eps = 0.15
+
+# Stochastic heating
+vel2 = zeros((n_parts,n_snapshots))
+vel2[:,:] = velocity_parts[:,0,:]*velocity_parts[:,0,:] + velocity_parts[:,1,:]*velocity_parts[:,1,:] + velocity_parts[:,2,:]*velocity_parts[:,2,:]
+total_kinetic_energy_cgs = np.sum(np.multiply(vel2,masses)*0.5,axis = 0) * unit_energy_in_cgs
+total_energy_cgs = np.sum(np.multiply(internal_energy,masses),axis = 0) * unit_energy_in_cgs
+total_energy_released_cgs = total_energy_cgs[n_snapshots-1] - total_energy_cgs[0] + total_kinetic_energy_cgs[n_snapshots-1] - total_kinetic_energy_cgs[0]
+
+# Calculate energy released
+num_SNII_per_msun = 1.73621e-02
+energy_per_sn = 1.0e51 / unit_energy_in_cgs
+expected_energy_released_cgs = np.zeros(n_snapshots)
+for i in range(n_snapshots):
+	if time[i]*unit_time_in_cgs/Gyr_in_cgs < 0.03:
+		expected_energy_released_cgs[i] = 0
+	else:
+		expected_energy_released_cgs[i] = num_SNII_per_msun * star_initial_mass / const_solar_mass * energy_per_sn * unit_energy_in_cgs
+
+# Did we get it right?
+if abs(total_energy_released_cgs - expected_energy_released_cgs[n_snapshots-1])/expected_energy_released_cgs[n_snapshots-1] < eps:
+	print("total stochastic energy release consistent with expectation. total stochastic energy release "+str(total_energy_released_cgs)+" expected "+ str(expected_energy_released_cgs[n_snapshots-1]) + " initial total internal energy "+ str(total_energy_cgs[0] + total_kinetic_energy_cgs[0]))
+else:
+	print("total stochastic energy release "+str(total_energy_released_cgs)+" expected "+ str(expected_energy_released_cgs[n_snapshots-1]) + " initial total internal energy "+ str(total_energy_cgs[0] + total_kinetic_energy_cgs[0]) + " energy change fraction of total " + str(total_energy_released_cgs/(total_energy_cgs[0]+total_kinetic_energy_cgs[0])))
+
+# Plot the energy evolution
+figure()
+subplot(111)
+plot(time*unit_time_in_cgs/Gyr_in_cgs, total_energy_cgs + total_kinetic_energy_cgs - total_energy_cgs[0] - total_kinetic_energy_cgs[0],color='k', linewidth=0.5, label="SWIFT")
+plot(time*unit_time_in_cgs/Gyr_in_cgs, expected_energy_released_cgs,color = 'r', linewidth=0.5, label="expected")
+xlabel("Time (Gyr)")
+ylabel("Total energy (erg)")
+legend()
+savefig("stochastic_energy_evolution.png", dpi=200)
+
diff --git a/examples/SubgridTests/StellarEvolution/getGlass.sh b/examples/SubgridTests/StellarEvolution/getGlass.sh
new file mode 100755
index 0000000000000000000000000000000000000000..ffd92e88deae6e91237059adac2a6c2067caee46
--- /dev/null
+++ b/examples/SubgridTests/StellarEvolution/getGlass.sh
@@ -0,0 +1,2 @@
+#!/bin/bash
+wget http://virgodb.cosma.dur.ac.uk/swift-webstorage/ICs/glassCube_32.hdf5
diff --git a/examples/SubgridTests/StellarEvolution/getSolutions.sh b/examples/SubgridTests/StellarEvolution/getSolutions.sh
new file mode 100755
index 0000000000000000000000000000000000000000..1fe0f1507a7efa1da843970ddcede681e846e4ec
--- /dev/null
+++ b/examples/SubgridTests/StellarEvolution/getSolutions.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+wget http://virgodb.cosma.dur.ac.uk/swift-webstorage/ReferenceSolutions/StellarEvolutionSolution.tar.gz
+tar -xvzf StellarEvolutionSolution.tar.gz
diff --git a/examples/SubgridTests/StellarEvolution/getYieldTable.sh b/examples/SubgridTests/StellarEvolution/getYieldTable.sh
new file mode 100755
index 0000000000000000000000000000000000000000..26eef020cab82acee2c80e88089df1790b281eab
--- /dev/null
+++ b/examples/SubgridTests/StellarEvolution/getYieldTable.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+wget http://virgodb.cosma.dur.ac.uk/swift-webstorage/YieldTables/EAGLE/yieldtables.tar.gz
+tar -xf yieldtables.tar.gz
diff --git a/examples/SubgridTests/StellarEvolution/makeIC.py b/examples/SubgridTests/StellarEvolution/makeIC.py
new file mode 100644
index 0000000000000000000000000000000000000000..880e47844da90d42af1f287abe7a375ad4e4639f
--- /dev/null
+++ b/examples/SubgridTests/StellarEvolution/makeIC.py
@@ -0,0 +1,142 @@
+###############################################################################
+ # This file is part of SWIFT.
+ # Copyright (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/>.
+ # 
+ ##############################################################################
+
+import h5py
+from numpy import *
+
+# Some constants
+solar_mass_cgs = 1.988480e33 
+kpc_in_cm = 3.085678e21
+mp_cgs = 1.67e-24
+boltzmann_k_cgs = 1.38e-16
+
+# Parameters
+gamma = 5./3.      				# Gas adiabatic index
+rho_cgs = mp_cgs        			# Background density
+u0_cgs = 1.2e10					# Desired initial internal energy (1.2e12 ~ 10^4K)
+P_cgs = rho_cgs*u0_cgs*(gamma - 1.)          	# Background pressure
+fileName = "stellar_evolution.hdf5" 
+
+# Units
+unit_l_cgs = 3.085678e24
+unit_m_cgs = 1.988480e43
+unit_t_cgs = 3.085678e19
+unit_A_cgs = 1.
+unit_T_cgs = 1.
+unit_v_cgs = unit_l_cgs/unit_t_cgs
+
+boxsize_cgs = 1.0e1*kpc_in_cm
+vol_cgs = boxsize_cgs**3
+
+#---------------------------------------------------
+glass = h5py.File("glassCube_32.hdf5", "r")
+
+# Read particle positions and h from the glass
+pos = glass["/PartType0/Coordinates"][:,:]
+eps = 1e-6
+pos = (pos - pos.min()) / (pos.max() - pos.min() + eps) * boxsize_cgs / unit_l_cgs
+h = glass["/PartType0/SmoothingLength"][:] * boxsize_cgs / unit_l_cgs
+
+numPart = size(h)
+
+# Generate extra arrays
+v = zeros((numPart, 3))
+ids = linspace(1, numPart, numPart)
+m_cgs = zeros(numPart)
+u_cgs = zeros(numPart)
+m = zeros(numPart)
+u = zeros(numPart)
+
+m_cgs[:] = rho_cgs * vol_cgs / numPart    
+u_cgs[:] = P_cgs / (rho_cgs * (gamma - 1))
+
+# Stars
+star_pos = zeros((1, 3))
+star_pos[:,:] = 0.5 * boxsize_cgs / unit_l_cgs
+
+star_v = zeros((1, 3))
+star_v[:,:] = 0.
+
+# increase mass to keep it at center
+star_m_cgs = 5e0 * array([rho_cgs * vol_cgs / numPart])
+star_ids = array([numPart + 1])
+star_h = array([h.max()])
+
+#--------------------------------------------------
+
+# Check quantities are correct for debugging
+print("part mass/msun " + str(m_cgs[0]/solar_mass_cgs) + " stellar mass/msun " + str(star_m_cgs/solar_mass_cgs))
+print("boxsize kpc " + str(boxsize_cgs/kpc_in_cm))
+print("density cm^-3 " + str(rho_cgs/mp_cgs))
+print("initial temperature K " + str(u_cgs[0] / boltzmann_k_cgs*((gamma - 1)*rho_cgs)))
+
+# Convert to internal units
+star_m = star_m_cgs/unit_m_cgs
+m[:] = m_cgs/unit_m_cgs
+u[:] = u_cgs*unit_v_cgs**-2
+boxsize = boxsize_cgs/unit_l_cgs
+
+
+#--------------------------------------------------
+
+#File
+file = h5py.File(fileName, 'w')
+
+# Header
+grp = file.create_group("/Header")
+grp.attrs["BoxSize"] = [boxsize]*3
+grp.attrs["NumPart_Total"] =  [numPart, 0, 0, 0, 1, 0]
+grp.attrs["NumPart_Total_HighWord"] = [0, 0, 0, 0, 0, 0]
+grp.attrs["NumPart_ThisFile"] = [numPart, 0, 0, 0, 1, 0]
+grp.attrs["Time"] = 0.0
+grp.attrs["NumFilesPerSnapshot"] = 1
+grp.attrs["MassTable"] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
+grp.attrs["Flag_Entropy_ICs"] = 0
+grp.attrs["Dimension"] = 3
+
+#Runtime parameters
+grp = file.create_group("/RuntimePars")
+grp.attrs["PeriodicBoundariesOn"] = 0
+
+#Units
+grp = file.create_group("/Units")
+grp.attrs["Unit length in cgs (U_L)"] = unit_l_cgs
+grp.attrs["Unit mass in cgs (U_M)"] = unit_m_cgs
+grp.attrs["Unit time in cgs (U_t)"] = unit_t_cgs
+grp.attrs["Unit current in cgs (U_I)"] = unit_A_cgs
+grp.attrs["Unit temperature in cgs (U_T)"] = unit_T_cgs
+
+#Particle group
+grp = file.create_group("/PartType0")
+grp.create_dataset('Coordinates', data=pos, dtype='d')
+grp.create_dataset('Velocities', data=v, dtype='f')
+grp.create_dataset('Masses', data=m, dtype='f')
+grp.create_dataset('SmoothingLength', data=h, dtype='f')
+grp.create_dataset('InternalEnergy', data=u, dtype='f')
+grp.create_dataset('ParticleIDs', data=ids, dtype='L')
+
+# stellar group
+grp = file.create_group("/PartType4")
+grp.create_dataset("Coordinates", data=star_pos, dtype="d")
+grp.create_dataset('Velocities', data=star_v, dtype='f')
+grp.create_dataset('Masses', data=star_m, dtype='f')
+grp.create_dataset('SmoothingLength', data=star_h, dtype='f')
+grp.create_dataset('ParticleIDs', data=star_ids, dtype='L')
+
+file.close()
diff --git a/examples/SubgridTests/StellarEvolution/plot_box_evolution.py b/examples/SubgridTests/StellarEvolution/plot_box_evolution.py
new file mode 100644
index 0000000000000000000000000000000000000000..db4d075b03da90ba992487125c6fec5886930b70
--- /dev/null
+++ b/examples/SubgridTests/StellarEvolution/plot_box_evolution.py
@@ -0,0 +1,197 @@
+###############################################################################
+ # This file is part of SWIFT.
+ # Copyright (c) 2018 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/>.
+ # 
+ ##############################################################################
+
+# Script used to plot time evolution of gas particle properties. Intended to 
+# compare result of feedback due to one star placed in centre of uniform box
+# of gas with output from EAGLE feedback test. Can also use as input output
+# from SWIFT feedback test (tests/testFeedback) with the appropriate change
+# to filepath.
+
+import matplotlib
+matplotlib.use("Agg")
+from pylab import *
+from scipy import stats
+import h5py
+import numpy as np
+import glob
+import os.path
+
+# Plot parameters
+params = {'axes.labelsize': 10,
+'axes.titlesize': 10,
+'font.size': 12,
+'legend.fontsize': 12,
+'xtick.labelsize': 10,
+'ytick.labelsize': 10,
+'text.usetex': True,
+ 'figure.figsize' : (9.90,6.45),
+'figure.subplot.left'    : 0.05,
+'figure.subplot.right'   : 0.995,
+'figure.subplot.bottom'  : 0.06,
+'figure.subplot.top'     : 0.92,
+'figure.subplot.wspace'  : 0.25,
+'figure.subplot.hspace'  : 0.2,
+'lines.markersize' : 6,
+'lines.linewidth' : 3.,
+'text.latex.unicode': True
+}
+rcParams.update(params)
+rc('font',**{'family':'sans-serif','sans-serif':['Times']})
+
+
+# Number of snapshots and elements
+newest_snap_name = max(glob.glob('stellar_evolution_*.hdf5'))#, key=os.path.getctime)
+n_snapshots = int(newest_snap_name.replace('stellar_evolution_','').replace('.hdf5','')) + 1
+n_elements = 9
+
+# Read the simulation data
+sim = h5py.File("stellar_evolution_0000.hdf5", "r")
+boxSize = sim["/Header"].attrs["BoxSize"][0]
+time = sim["/Header"].attrs["Time"][0]
+scheme = sim["/HydroScheme"].attrs["Scheme"]
+kernel = sim["/HydroScheme"].attrs["Kernel function"]
+neighbours = sim["/HydroScheme"].attrs["Kernel target N_ngb"]
+eta = sim["/HydroScheme"].attrs["Kernel eta"]
+git = sim["Code"].attrs["Git Revision"]
+stellar_mass = sim["/PartType4/Masses"][0]
+
+# Units
+unit_length_in_cgs = sim["/Units"].attrs["Unit length in cgs (U_L)"]
+unit_mass_in_cgs = sim["/Units"].attrs["Unit mass in cgs (U_M)"]
+unit_time_in_cgs = sim["/Units"].attrs["Unit time in cgs (U_t)"]
+unit_temp_in_cgs = sim["/Units"].attrs["Unit temperature in cgs (U_T)"]
+unit_vel_in_cgs = unit_length_in_cgs / unit_time_in_cgs
+unit_energy_in_cgs = unit_mass_in_cgs * unit_vel_in_cgs * unit_vel_in_cgs
+unit_length_in_si = 0.01 * unit_length_in_cgs
+unit_mass_in_si = 0.001 * unit_mass_in_cgs
+unit_time_in_si = unit_time_in_cgs
+unit_density_in_cgs = unit_mass_in_cgs*unit_length_in_cgs**-3
+unit_pressure_in_cgs = unit_mass_in_cgs/unit_length_in_cgs*unit_time_in_cgs**-2
+unit_int_energy_in_cgs = unit_energy_in_cgs/unit_mass_in_cgs
+unit_entropy_in_cgs = unit_energy_in_cgs/unit_temp_in_cgs
+Gyr_in_cgs = 1e9 * 365. * 24 * 3600.
+Msun_in_cgs = 1.98848e33
+
+# Declare arrays to store SWIFT data
+swift_box_gas_mass = zeros(n_snapshots)
+swift_box_star_mass = zeros(n_snapshots)
+swift_box_gas_metal_mass = zeros(n_snapshots)
+swift_element_mass = zeros((n_snapshots,n_elements))
+t = zeros(n_snapshots)
+
+# Read data from snapshots
+for i in range(n_snapshots):
+	#print("reading snapshot "+str(i))
+	sim = h5py.File("stellar_evolution_%04d.hdf5"%i, "r")
+	t[i] = sim["/Header"].attrs["Time"][0]
+	
+	masses = sim["/PartType0/Masses"][:]
+	swift_box_gas_mass[i] = np.sum(masses)
+
+        Z_star = sim["/PartType4/Metallicity"][0]
+	star_masses = sim["/PartType4/Masses"][:]
+	swift_box_star_mass[i] = np.sum(star_masses)
+
+	metallicities = sim["/PartType0/Metallicity"][:]
+	swift_box_gas_metal_mass[i] = np.sum(metallicities * masses)
+
+	element_abundances = sim["/PartType0/ElementAbundance"][:][:]
+	for j in range(n_elements):
+		swift_element_mass[i,j] = np.sum(element_abundances[:,j] * masses)
+
+        sim.close()
+
+# Read expected yields from EAGLE. Choose which file to use based on metallicity used when
+# running SWIFT (can be specified in yml file)
+filename = "./StellarEvolutionSolution/Z_%.4f/StellarEvolutionTotal.txt"%Z_star
+
+# Read EAGLE test output
+with open(filename) as f:
+	eagle_categories = f.readline()
+	eagle_data = f.readlines()
+
+eagle_data = [x.strip() for x in eagle_data]
+
+# Declare arrays to store EAGLE test output
+eagle_time_Gyr = zeros(len(eagle_data))
+eagle_total_mass = zeros(len(eagle_data))
+eagle_total_metal_mass = zeros(len(eagle_data))
+eagle_total_element_mass = zeros((len(eagle_data),n_elements))
+
+# Populate arrays with data from EAGLE test output
+i = 0
+for line in eagle_data:
+	enrich_to_date = line.split(' ')
+	eagle_time_Gyr[i] = float(enrich_to_date[0])
+	eagle_total_mass[i] = float(enrich_to_date[1]) * stellar_mass / Msun_in_cgs * unit_mass_in_cgs
+	eagle_total_metal_mass[i] = float(enrich_to_date[2]) * stellar_mass / Msun_in_cgs * unit_mass_in_cgs 
+	for j in range(n_elements):
+		eagle_total_element_mass[i,j] = float(enrich_to_date[3+j]) * stellar_mass / Msun_in_cgs * unit_mass_in_cgs 
+	i += 1
+
+                
+# Plot the interesting quantities
+figure()
+
+suptitle("Star metallicity Z = %.4f"%Z_star)
+
+# Box gas mass --------------------------------
+subplot(221)
+plot(t[1:] * unit_time_in_cgs / Gyr_in_cgs, (swift_box_gas_mass[1:] - swift_box_gas_mass[0])* unit_mass_in_cgs / Msun_in_cgs, linewidth=0.5, color='k', marker = "*", ms=0.5, label='swift')
+plot(eagle_time_Gyr[1:],eagle_total_mass[:-1],linewidth=0.5,color='r',label='eagle test total', ls='--')
+xlabel("${\\rm{Time}} (Gyr)$", labelpad=0)
+ylabel("Change in total gas particle mass (Msun)", labelpad=2)
+ticklabel_format(style='sci', axis='y', scilimits=(0,0))
+legend()
+
+# Box star mass --------------------------------
+subplot(222)
+plot(t * unit_time_in_cgs / Gyr_in_cgs, (swift_box_star_mass)* unit_mass_in_cgs / Msun_in_cgs, linewidth=0.5, color='k', marker = "*", ms=0.5, label='swift')
+plot(eagle_time_Gyr[1:], swift_box_star_mass[0] * unit_mass_in_cgs / Msun_in_cgs - eagle_total_mass[:-1],linewidth=0.5,color='r',label='eagle test total')
+xlabel("${\\rm{Time}} (Gyr)$", labelpad=0)
+ylabel("Change in total star particle mass (Msun)", labelpad=2)
+ticklabel_format(style='sci', axis='y', scilimits=(0,0))
+legend()
+
+# Box gas element  mass --------------------------------
+colours = ['k','r','g','b','c','y','m','skyblue','plum']
+element_names = ['H','He','C','N','O','Ne','Mg','Si','Fe']
+subplot(223)
+for j in range(n_elements):
+	plot(t[1:] * unit_time_in_cgs / Gyr_in_cgs, (swift_element_mass[1:,j] - swift_element_mass[0,j]) * unit_mass_in_cgs / Msun_in_cgs, linewidth=0.5, color=colours[j], ms=0.5, label=element_names[j])
+	plot(eagle_time_Gyr[1:],eagle_total_element_mass[:-1,j],linewidth=1,color=colours[j],linestyle='--')
+xlabel("${\\rm{Time}} (Gyr)$", labelpad=0)
+ylabel("Change in element mass of gas particles (Msun)", labelpad=2)
+xscale("log")
+yscale("log")
+legend(bbox_to_anchor=(1.005, 1.), ncol=1, fontsize=8, handlelength=1)
+
+# Box gas metal mass --------------------------------
+subplot(224)
+plot(t[1:] * unit_time_in_cgs / Gyr_in_cgs, (swift_box_gas_metal_mass[1:] - swift_box_gas_metal_mass[0])* unit_mass_in_cgs / Msun_in_cgs, linewidth=0.5, color='k', marker = "*", ms=0.5, label='swift')
+plot(eagle_time_Gyr[1:],eagle_total_metal_mass[:-1],linewidth=0.5,color='r',label='eagle test')
+xlabel("${\\rm{Time}} (Gyr)$", labelpad=0)
+ylabel("Change in total metal mass of gas particles (Msun)", labelpad=2)
+ticklabel_format(style='sci', axis='y', scilimits=(0,0))
+
+savefig("box_evolution_Z_%.4f.png"%(Z_star), dpi=200)
+
+
+
+
diff --git a/examples/SubgridTests/StellarEvolution/plot_particle_evolution.py b/examples/SubgridTests/StellarEvolution/plot_particle_evolution.py
new file mode 100644
index 0000000000000000000000000000000000000000..8b935e537b14a9d1d9cc4eec7c5cd0794c6fc489
--- /dev/null
+++ b/examples/SubgridTests/StellarEvolution/plot_particle_evolution.py
@@ -0,0 +1,190 @@
+###############################################################################
+ # This file is part of SWIFT.
+ # Copyright (c) 2015 Bert Vandenbroucke (bert.vandenbroucke@ugent.be)
+ #                    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/>.
+ # 
+ ##############################################################################
+
+# Assuming output snapshots contain evolution of box of gas with star at its 
+# centre, this script will plot the evolution of the radial velocities, internal 
+# energies, mass and metallicities of the nearest n particles to the star over 
+# the duration of the simulation. 
+
+import matplotlib
+matplotlib.use("Agg")
+from pylab import *
+from scipy import stats
+import h5py
+import numpy as np
+import glob
+import os.path
+
+# Function to find index in array a for each element in array b
+def find_indices(a,b):
+        result = np.zeros(len(b))
+        for i in range(len(b)):
+                result[i] = ((np.where(a == b[i]))[0])[0]
+        return result
+
+# Plot parameters
+params = {'axes.labelsize': 10,
+'axes.titlesize': 10,
+'font.size': 12,
+'legend.fontsize': 12,
+'xtick.labelsize': 10,
+'ytick.labelsize': 10,
+'text.usetex': True,
+ 'figure.figsize' : (9.90,6.45),
+'figure.subplot.left'    : 0.1,
+'figure.subplot.right'   : 0.99,
+'figure.subplot.bottom'  : 0.1,
+'figure.subplot.top'     : 0.95,
+'figure.subplot.wspace'  : 0.2,
+'figure.subplot.hspace'  : 0.2,
+'lines.markersize' : 6,
+'lines.linewidth' : 3.,
+'text.latex.unicode': True
+}
+rcParams.update(params)
+rc('font',**{'family':'sans-serif','sans-serif':['Times']})
+
+
+# Number of snapshots and elements
+newest_snap_name = max(glob.glob('stellar_evolution_*.hdf5'), key=os.path.getctime)
+n_snapshots = int(newest_snap_name.replace('stellar_evolution_','').replace('.hdf5','')) + 1
+n_particles_to_plot = 500
+
+# Read the simulation data
+sim = h5py.File("stellar_evolution_0000.hdf5", "r")
+boxSize = sim["/Header"].attrs["BoxSize"][0]
+time = sim["/Header"].attrs["Time"][0]
+scheme = sim["/HydroScheme"].attrs["Scheme"]
+kernel = sim["/HydroScheme"].attrs["Kernel function"]
+neighbours = sim["/HydroScheme"].attrs["Kernel target N_ngb"]
+eta = sim["/HydroScheme"].attrs["Kernel eta"]
+git = sim["Code"].attrs["Git Revision"]
+
+# Units
+unit_length_in_cgs = sim["/Units"].attrs["Unit length in cgs (U_L)"]
+unit_mass_in_cgs = sim["/Units"].attrs["Unit mass in cgs (U_M)"]
+unit_time_in_cgs = sim["/Units"].attrs["Unit time in cgs (U_t)"]
+unit_temp_in_cgs = sim["/Units"].attrs["Unit temperature in cgs (U_T)"]
+unit_vel_in_cgs = unit_length_in_cgs / unit_time_in_cgs
+unit_energy_in_cgs = unit_mass_in_cgs * unit_vel_in_cgs * unit_vel_in_cgs
+unit_length_in_si = 0.01 * unit_length_in_cgs
+unit_mass_in_si = 0.001 * unit_mass_in_cgs
+unit_time_in_si = unit_time_in_cgs
+unit_density_in_cgs = unit_mass_in_cgs*unit_length_in_cgs**-3
+unit_pressure_in_cgs = unit_mass_in_cgs/unit_length_in_cgs*unit_time_in_cgs**-2
+unit_int_energy_in_cgs = unit_energy_in_cgs/unit_mass_in_cgs
+unit_entropy_in_cgs = unit_energy_in_cgs/unit_temp_in_cgs
+Myr_in_cgs = 3.154e13
+Msun_in_cgs = 1.989e33
+
+# Read data of zeroth snapshot
+pos = sim["/PartType0/Coordinates"][:,:]
+x = pos[:,0] - boxSize / 2
+y = pos[:,1] - boxSize / 2
+z = pos[:,2] - boxSize / 2
+vel = sim["/PartType0/Velocities"][:,:]
+r = sqrt(x**2 + y**2 + z**2)
+v_r = (x * vel[:,0] + y * vel[:,1] + z * vel[:,2]) / r
+u = sim["/PartType0/InternalEnergy"][:]
+S = sim["/PartType0/Entropy"][:]
+P = sim["/PartType0/Pressure"][:]
+rho = sim["/PartType0/Density"][:]
+mass = sim["/PartType0/Masses"][:]
+IDs = sim["/PartType0/ParticleIDs"][:]
+
+# Find which particles are closest to centre of box
+index = argsort(r)
+part_IDs_to_plot = zeros(n_particles_to_plot)
+part_IDs_to_plot = np.sort(IDs[index[0:n_particles_to_plot]])
+
+# Declare arrrays to plot
+masses_to_plot = zeros((n_particles_to_plot, n_snapshots))
+v_r_to_plot = zeros((n_particles_to_plot, n_snapshots))
+metallicities_to_plot = zeros((n_particles_to_plot, n_snapshots))
+internal_energies_to_plot = zeros((n_particles_to_plot, n_snapshots))
+t = zeros(n_snapshots)
+
+# Read data from rest of snapshots
+for i in range(n_snapshots):
+	print("reading snapshot "+str(i))
+	# Read the simulation data
+	sim = h5py.File("stellar_evolution_%04d.hdf5"%i, "r")
+	t[i] = sim["/Header"].attrs["Time"][0]
+	
+	pos = sim["/PartType0/Coordinates"][:,:]
+	x = pos[:,0] - boxSize / 2
+	y = pos[:,1] - boxSize / 2
+	z = pos[:,2] - boxSize / 2
+	vel = sim["/PartType0/Velocities"][:,:]
+	r = sqrt(x**2 + y**2 + z**2)
+	v_r = (x * vel[:,0] + y * vel[:,1] + z * vel[:,2]) / r
+	u = sim["/PartType0/InternalEnergy"][:]
+	S = sim["/PartType0/Entropy"][:]
+	P = sim["/PartType0/Pressure"][:]
+	rho = sim["/PartType0/Density"][:]
+	mass = sim["/PartType0/Masses"][:]
+	metallicity = sim["/PartType0/Metallicity"][:]
+	internal_energy = sim["/PartType0/InternalEnergy"][:]
+	IDs = sim["/PartType0/ParticleIDs"][:]
+
+	# Find which particles we want to plot and store their data
+	indices = (find_indices(IDs,part_IDs_to_plot)).astype(int)
+	masses_to_plot[:,i] = mass[indices[:]]
+	v_r_to_plot[:,i] = v_r[indices[:]]
+	metallicities_to_plot[:,i] = metallicity[indices[:]]
+	internal_energies_to_plot[:,i] = internal_energy[indices[:]]
+	
+
+# Plot the interesting quantities
+figure()
+
+# Radial velocity --------------------------------
+subplot(221)
+for j in range(n_particles_to_plot):
+	plot(t * unit_time_in_cgs / Myr_in_cgs, v_r_to_plot[j,:] * unit_vel_in_cgs, linewidth=0.5, color='k', ms=0.5, alpha=0.1)
+xlabel("Time (Myr)", labelpad=0)
+ylabel("Radial velocity $(\\rm{cm} \cdot \\rm{s}^{-1})$", labelpad=0)
+ticklabel_format(style='sci', axis='y', scilimits=(0,0))
+
+# Internal energy --------------------------------
+subplot(222)
+for j in range(n_particles_to_plot):
+	plot(t * unit_time_in_cgs / Myr_in_cgs, internal_energies_to_plot[j,:] * unit_energy_in_cgs / unit_mass_in_cgs, linewidth=0.5, color='k', ms=0.5, alpha=0.1)
+xlabel("Time (Myr)", labelpad=0)
+ylabel("Internal energy $(\\rm{erg} \cdot \\rm{g}^{-1})$", labelpad=2)
+ticklabel_format(style='sci', axis='y', scilimits=(0,0))
+
+# Masses --------------------------------
+subplot(223)
+for j in range(n_particles_to_plot):
+	plot(t * unit_time_in_cgs / Myr_in_cgs, masses_to_plot[j,:] * unit_mass_in_cgs / Msun_in_cgs, linewidth=0.5, color='k', ms=0.5, alpha=0.1)
+xlabel("Time (Myr)", labelpad=0)
+ylabel("Mass (Msun)", labelpad=2)
+ticklabel_format(style='sci', axis='y', scilimits=(0,0))
+
+# Metallicities --------------------------------
+subplot(224)
+for j in range(n_particles_to_plot):
+	plot(t * unit_time_in_cgs / Myr_in_cgs, metallicities_to_plot[j,:] , linewidth=0.5, color='k', ms=0.5, alpha=0.1)
+xlabel("Time (Myr)", labelpad=0)
+ylabel("Metallicity", labelpad=2)
+ticklabel_format(style='sci', axis='y', scilimits=(0,0))
+
+savefig("particle_evolution.png", dpi=200)
diff --git a/examples/SubgridTests/StellarEvolution/run.sh b/examples/SubgridTests/StellarEvolution/run.sh
new file mode 100755
index 0000000000000000000000000000000000000000..91032ced8970feecaf8f398ca0b65228e53fc312
--- /dev/null
+++ b/examples/SubgridTests/StellarEvolution/run.sh
@@ -0,0 +1,47 @@
+#!/bin/bash
+
+# Generate the initial conditions if they are not present.
+if [ ! -e glassCube_32.hdf5 ]
+then
+    echo "Fetching initial glass file for the Supernovae feedback example..."
+    ./getGlass.sh
+fi
+if [ ! -e stellar_evolution.hdf5 ]
+then
+    echo "Generating initial conditions for the 3D stellar evolution example..."
+    python makeIC.py
+fi
+
+# Get the Yield tables
+if [ ! -e yieldtables ]
+then
+    echo "Fetching Yield tables..."
+    ./getYieldTable.sh
+fi
+
+# Get the solutions
+if [ ! -e StellarEvolutionSolution ]
+then
+    echo "Fetching solutions ..."
+    ./getSolutions.sh
+fi
+
+../../swift  --feedback --stars --hydro --external-gravity --threads=4 stellar_evolution.yml -P EAGLEChemistry:init_abundance_metal:0.08 2>&1 | tee output.log
+
+python plot_box_evolution.py
+
+../../swift  --feedback --stars --hydro --external-gravity --threads=4 stellar_evolution.yml -P EAGLEChemistry:init_abundance_metal:0.04 2>&1 | tee output.log
+
+python plot_box_evolution.py
+
+../../swift  --feedback --stars --hydro --external-gravity --threads=4 stellar_evolution.yml -P EAGLEChemistry:init_abundance_metal:0.01 2>&1 | tee output.log
+
+python plot_box_evolution.py
+
+../../swift  --feedback --stars --hydro --external-gravity --threads=4 stellar_evolution.yml -P EAGLEChemistry:init_abundance_metal:0.001 2>&1 | tee output.log
+
+python plot_box_evolution.py
+
+../../swift  --feedback --stars --hydro --external-gravity --threads=4 stellar_evolution.yml -P EAGLEChemistry:init_abundance_metal:0.0001 2>&1 | tee output.log
+
+python plot_box_evolution.py
diff --git a/examples/SubgridTests/StellarEvolution/stellar_evolution.yml b/examples/SubgridTests/StellarEvolution/stellar_evolution.yml
new file mode 100644
index 0000000000000000000000000000000000000000..9baa1b57be2b14564c50aec2796d15fb3364aa17
--- /dev/null
+++ b/examples/SubgridTests/StellarEvolution/stellar_evolution.yml
@@ -0,0 +1,112 @@
+# Define the system of units to use internally. 
+InternalUnitSystem:
+  UnitMass_in_cgs:     1.98848e43    # 10^10 M_sun in grams
+  UnitLength_in_cgs:   3.08567758e24 # Mpc in centimeters
+  UnitVelocity_in_cgs: 1e5           # km/s in centimeters per second
+  UnitCurrent_in_cgs:  1.            # Amperes
+  UnitTemp_in_cgs:     1.            # Kelvin
+
+# Cosmological parameters
+Cosmology:
+  h:              0.6777        # Reduced Hubble constant
+  a_begin:        0.5           # 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
+
+# Parameters governing the time integration
+TimeIntegration:
+  time_begin: 0      # The starting time of the simulation (in internal units).
+  time_end:   1.3e-2 # The end time of the simulation (in internal units).
+  dt_min:     1e-10  # The minimal time-step size of the simulation (in internal units).
+  dt_max:     8e-6   # The maximal time-step size of the simulation (in internal units).
+
+# Parameters governing the snapshots
+Snapshots:
+  basename:            stellar_evolution # Common part of the name of output files
+  time_first:          0.       # Time of the first output (in internal units)
+  delta_time:          3.e-5    # Time difference between consecutive outputs without cosmology (internal units)
+
+# Parameters governing the conserved quantities statistics
+Statistics:
+  time_first:          0.
+  delta_time:          1.e-5  # non cosmology time between statistics output
+  scale_factor_first:  0.5
+
+# Parameters for the hydrodynamics scheme
+SPH:
+  resolution_eta:        1.2348   # Target smoothing length in units of the mean inter-particle separation 
+  CFL_condition:         0.1      # Courant-Friedrich-Levy condition for time integration.
+  minimal_temperature:   10.      # Kelvin
+
+# Properties of the stars
+Stars:
+  birth_time:  0.   # Give the star in the ICs a decent birth time
+  
+# Parameters related to the initial conditions
+InitialConditions:
+  file_name:  ./stellar_evolution.hdf5       # The file to read
+  periodic:   1
+  
+Scheduler:
+  max_top_level_cells: 4
+
+# Parameters for the EAGLE "equation of state"
+EAGLEEntropyFloor:
+  Jeans_density_threshold_H_p_cm3: 0.1       # Physical density above which the EAGLE Jeans limiter entropy floor kicks in expressed in Hydrogen atoms per cm^3.
+  Jeans_over_density_threshold:    10.       # Overdensity above which the EAGLE Jeans limiter entropy floor can kick in.
+  Jeans_temperature_norm_K:        8000      # Temperature of the EAGLE Jeans limiter entropy floor at the density threshold expressed in Kelvin.
+  Jeans_gamma_effective:           1.3333333 # Slope the of the EAGLE Jeans limiter entropy floor
+  Cool_density_threshold_H_p_cm3: 1e-5       # Physical density above which the EAGLE Cool limiter entropy floor kicks in expressed in Hydrogen atoms per cm^3.
+  Cool_over_density_threshold:    10.        # Overdensity above which the EAGLE Cool limiter entropy floor can kick in.
+  Cool_temperature_norm_K:        8000       # Temperature of the EAGLE Cool limiter entropy floor at the density threshold expressed in Kelvin.
+  Cool_gamma_effective:           1.         # Slope the of the EAGLE Cool limiter entropy floor
+
+# Metallicites read in for the gas and star
+EAGLEChemistry:              
+  init_abundance_metal:      0.01
+  init_abundance_Hydrogen:   0.752
+  init_abundance_Helium:     0.248
+  init_abundance_Carbon:     0.0
+  init_abundance_Nitrogen:   0.0
+  init_abundance_Oxygen:     0.0
+  init_abundance_Neon:       0.0
+  init_abundance_Magnesium:  0.0
+  init_abundance_Silicon:    0.0
+  init_abundance_Iron:       0.0
+
+# Properties of the EAGLE feedback and enrichment model.
+EAGLEFeedback:
+  use_SNe_feedback:                 0               # Global switch for SNe thermal feedback.
+  use_AGB_enrichment:               1               # Global switch for enrichement from AGB stars.
+  use_SNII_enrichment:              1               # Global switch for enrichement from SNII stars.
+  use_SNIa_enrichment:              1               # Global switch for enrichement from SNIa stars.
+  filename:                         ./yieldtables/  # Path to the directory containing the EAGLE yield tables.
+  IMF_min_mass_Msun:                0.1             # Minimal stellar mass considered for the Chabrier IMF in solar masses.
+  IMF_max_mass_Msun:              100.0             # Maximal stellar mass considered for the Chabrier IMF in solar masses.
+  SNII_min_mass_Msun:               6.0             # Minimal mass considered for SNII feedback (not SNII enrichment!) in solar masses.
+  SNII_max_mass_Msun:             100.0             # Maximal mass considered for SNII feedback (not SNII enrichment!) in solar masses.
+  SNII_wind_delay_Gyr:              0.03            # Time in Gyr between a star's birth and the SNII thermal feedback event.
+  SNII_delta_T_K:                   3.16228e7       # Change in temperature to apply to the gas particle in a SNII thermal feedback event in Kelvin.
+  SNII_Energy_erg:                  1.0e51          # Energy of one SNII explosion in ergs.
+  SNII_Energy_fraction_min:         3.0             # Maximal fraction of energy applied in a SNII feedback event.
+  SNII_Energy_fraction_max:         0.3             # Minimal fraction of energy applied in a SNII feedback event.
+  SNII_Energy_fraction_Z_0:         0.0012663729    # Pivot point for the metallicity dependance of the SNII energy fraction (metal mass fraction).
+  SNII_Energy_fraction_n_0_H_p_cm3: 0.67            # Pivot point for the birth density dependance of the SNII energy fraction in cm^-3.
+  SNII_Energy_fraction_n_Z:         0.8686          # Power-law for the metallicity dependance of the SNII energy fraction.
+  SNII_Energy_fraction_n_n:         0.8686          # Power-law for the birth density dependance of the SNII energy fraction.
+  SNIa_max_mass_Msun:              8.0              # Maximal mass considered for SNIa feedback and enrichment in solar masses.
+  SNIa_timescale_Gyr:              2.0              # Time-scale of the exponential decay of the SNIa rates in Gyr.
+  SNIa_efficiency_p_Msun:          0.002            # Normalisation of the SNIa rates in inverse solar masses.
+  SNIa_Energy_erg:                 1.0e51           # Energy of one SNIa explosion in ergs.
+  AGB_ejecta_velocity_km_p_s:      10.0             # Velocity of the AGB ejectas in km/s.
+  SNII_yield_factor_Hydrogen:       1.0             # (Optional) Correction factor to apply to the Hydrogen yield from the SNII channel.
+  SNII_yield_factor_Helium:         1.0             # (Optional) Correction factor to apply to the Helium yield from the SNII channel.
+  SNII_yield_factor_Carbon:         0.5             # (Optional) Correction factor to apply to the Carbon yield from the SNII channel.
+  SNII_yield_factor_Nitrogen:       1.0             # (Optional) Correction factor to apply to the Nitrogen yield from the SNII channel.
+  SNII_yield_factor_Oxygen:         1.0             # (Optional) Correction factor to apply to the Oxygen yield from the SNII channel.
+  SNII_yield_factor_Neon:           1.0             # (Optional) Correction factor to apply to the Neon yield from the SNII channel.
+  SNII_yield_factor_Magnesium:      2.0             # (Optional) Correction factor to apply to the Magnesium yield from the SNII channel.
+  SNII_yield_factor_Silicon:        1.0             # (Optional) Correction factor to apply to the Silicon yield from the SNII channel.
+  SNII_yield_factor_Iron:           0.5             # (Optional) Correction factor to apply to the Iron yield from the SNII channel.
diff --git a/examples/main.c b/examples/main.c
index 5a6d577aaca3eb7d4f071c391b76ebab03abb87d..13d101549c2a68c52a1e616931a67a348177ce77 100644
--- a/examples/main.c
+++ b/examples/main.c
@@ -96,6 +96,7 @@ int main(int argc, char *argv[]) {
   struct gravity_props gravity_properties;
   struct hydro_props hydro_properties;
   struct stars_props stars_properties;
+  struct feedback_props feedback_properties;
   struct entropy_floor_properties entropy_floor;
   struct part *parts = NULL;
   struct phys_const prog_const;
@@ -739,10 +740,20 @@ int main(int argc, char *argv[]) {
     /* Initialise the stars properties */
     if (with_stars)
       stars_props_init(&stars_properties, &prog_const, &us, params,
-                       &hydro_properties);
+                       &hydro_properties, &cosmo);
     else
       bzero(&stars_properties, sizeof(struct stars_props));
 
+    /* Initialise the feedback properties */
+    if (with_feedback) {
+#ifdef FEEDBACK_NONE
+      error("ERROR: Running with feedback but compiled without it.");
+#endif
+      feedback_props_init(&feedback_properties, &prog_const, &us, params,
+                          &hydro_properties, &cosmo);
+    } else
+      bzero(&feedback_properties, sizeof(struct feedback_props));
+
     /* Initialise the gravity properties */
     if (with_self_gravity)
       gravity_props_init(&gravity_properties, params, &cosmo, with_cosmology,
@@ -993,8 +1004,8 @@ int main(int argc, char *argv[]) {
     engine_init(&e, &s, params, N_total[0], N_total[1], N_total[2],
                 engine_policies, talking, &reparttype, &us, &prog_const, &cosmo,
                 &hydro_properties, &entropy_floor, &gravity_properties,
-                &stars_properties, &mesh, &potential, &cooling_func, &starform,
-                &chemistry);
+                &stars_properties, &feedback_properties, &mesh, &potential,
+                &cooling_func, &starform, &chemistry);
     engine_config(0, &e, params, nr_nodes, myrank, nr_threads, with_aff,
                   talking, restart_file);
 
@@ -1199,19 +1210,19 @@ int main(int argc, char *argv[]) {
 
     /* Print some information to the screen */
     printf(
-        "  %6d %14e %12.7f %12.7f %14e %4d %4d %12lld %12lld %12lld %21.3f "
-        "%6d\n",
+        "  %6d %14e %12.7f %12.7f %14e %4d %4d %12lld %12lld %12lld %12lld"
+        " %21.3f %6d\n",
         e.step, e.time, e.cosmology->a, e.cosmology->z, e.time_step,
         e.min_active_bin, e.max_active_bin, e.updates, e.g_updates, e.s_updates,
-        e.wallclock_time, e.step_props);
+        e.b_updates, e.wallclock_time, e.step_props);
     fflush(stdout);
 
     fprintf(e.file_timesteps,
-            "  %6d %14e %12.7f %12.7f %14e %4d %4d %12lld %12lld %12lld %21.3f "
-            "%6d\n",
+            "  %6d %14e %12.7f %12.7f %14e %4d %4d %12lld %12lld %12lld %12lld"
+            " %21.3f %6d\n",
             e.step, e.time, e.cosmology->a, e.cosmology->z, e.time_step,
             e.min_active_bin, e.max_active_bin, e.updates, e.g_updates,
-            e.s_updates, e.wallclock_time, e.step_props);
+            e.s_updates, e.b_updates, e.wallclock_time, e.step_props);
     fflush(e.file_timesteps);
 
     /* Print information to the SFH logger */
diff --git a/examples/parameter_example.yml b/examples/parameter_example.yml
index 22bbf3db4f4f49f1cce6c1aa817b8228f829437f..d077a216890b04ce05e73110b34802f09a032dd5 100644
--- a/examples/parameter_example.yml
+++ b/examples/parameter_example.yml
@@ -335,3 +335,39 @@ EAGLEStarFormation:
   threshold_slope:                   -0.64     # Slope of the metal-dependant star formation threshold
   threshold_max_density_H_p_cm3:     10.0      # Maximal density of the metal-dependant density threshold for star formation in Hydrogen atoms per cm^3.  
   
+# Parameters related to feedback models  -----------------------------------------------
+
+# EAGLE feedback model
+EAGLEFeedback:
+  use_SNe_feedback:                 1               # Global switch for SNe thermal feedback.
+  use_AGB_enrichment:               1               # Global switch for enrichement from AGB stars.
+  use_SNII_enrichment:              1               # Global switch for enrichement from SNII stars.
+  use_SNIa_enrichment:              1               # Global switch for enrichement from SNIa stars.
+  filename:                         ./yieldtables/  # Path to the directory containing the EAGLE yield tables.
+  IMF_min_mass_Msun:                0.1             # Minimal stellar mass considered for the Chabrier IMF in solar masses.
+  IMF_max_mass_Msun:              100.0             # Maximal stellar mass considered for the Chabrier IMF in solar masses.
+  SNII_min_mass_Msun:               6.0             # Minimal mass considered for SNII feedback (not SNII enrichment!) in solar masses.
+  SNII_max_mass_Msun:             100.0             # Maximal mass considered for SNII feedback (not SNII enrichment!) in solar masses.
+  SNII_wind_delay_Gyr:              0.03            # Time in Gyr between a star's birth and the SNII thermal feedback event.
+  SNII_delta_T_K:                   3.16228e7       # Change in temperature to apply to the gas particle in a SNII thermal feedback event in Kelvin.
+  SNII_Energy_erg:                  1.0e51          # Energy of one SNII explosion in ergs.
+  SNII_Energy_fraction_min:         3.0             # Maximal fraction of energy applied in a SNII feedback event.
+  SNII_Energy_fraction_max:         0.3             # Minimal fraction of energy applied in a SNII feedback event.
+  SNII_Energy_fraction_Z_0:         0.0012663729    # Pivot point for the metallicity dependance of the SNII energy fraction (metal mass fraction).
+  SNII_Energy_fraction_n_0_H_p_cm3: 0.67            # Pivot point for the birth density dependance of the SNII energy fraction in cm^-3.
+  SNII_Energy_fraction_n_Z:         0.8686          # Power-law for the metallicity dependance of the SNII energy fraction.
+  SNII_Energy_fraction_n_n:         0.8686          # Power-law for the birth density dependance of the SNII energy fraction.
+  SNIa_max_mass_Msun:              8.0              # Maximal mass considered for SNIa feedback and enrichment in solar masses.
+  SNIa_timescale_Gyr:              2.0              # Time-scale of the exponential decay of the SNIa rates in Gyr.
+  SNIa_efficiency_p_Msun:          0.002            # Normalisation of the SNIa rates in inverse solar masses.
+  SNIa_Energy_erg:                 1.0e51           # Energy of one SNIa explosion in ergs.
+  AGB_ejecta_velocity_km_p_s:      10.0             # Velocity of the AGB ejectas in km/s.
+  SNII_yield_factor_Hydrogen:       1.0             # (Optional) Correction factor to apply to the Hydrogen yield from the SNII channel.
+  SNII_yield_factor_Helium:         1.0             # (Optional) Correction factor to apply to the Helium yield from the SNII channel.
+  SNII_yield_factor_Carbon:         0.5             # (Optional) Correction factor to apply to the Carbon yield from the SNII channel.
+  SNII_yield_factor_Nitrogen:       1.0             # (Optional) Correction factor to apply to the Nitrogen yield from the SNII channel.
+  SNII_yield_factor_Oxygen:         1.0             # (Optional) Correction factor to apply to the Oxygen yield from the SNII channel.
+  SNII_yield_factor_Neon:           1.0             # (Optional) Correction factor to apply to the Neon yield from the SNII channel.
+  SNII_yield_factor_Magnesium:      2.0             # (Optional) Correction factor to apply to the Magnesium yield from the SNII channel.
+  SNII_yield_factor_Silicon:        1.0             # (Optional) Correction factor to apply to the Silicon yield from the SNII channel.
+  SNII_yield_factor_Iron:           0.5             # (Optional) Correction factor to apply to the Iron yield from the SNII channel.
diff --git a/src/Makefile.am b/src/Makefile.am
index 16ba357fe963d34eee99262a409d7fb981126276..3f7a61bc097802e3e28744234e0c96116918187c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -52,7 +52,8 @@ include_HEADERS = space.h runner.h queue.h task.h lock.h cell.h part.h const.h \
     logger_io.h tracers_io.h tracers.h tracers_struct.h star_formation_io.h \
     star_formation_struct.h star_formation.h star_formation_iact.h \
     star_formation_logger.h star_formation_logger_struct.h \
-    velociraptor_struct.h velociraptor_io.h random.h memuse.h black_holes.h black_holes_io.h
+    velociraptor_struct.h velociraptor_io.h random.h memuse.h black_holes.h black_holes_io.h \
+    feedback.h feedback_struct.h feedback_properties.h
 
 # source files for EAGLE cooling
 EAGLE_COOLING_SOURCES =
@@ -60,6 +61,12 @@ if HAVEEAGLECOOLING
 EAGLE_COOLING_SOURCES += cooling/EAGLE/cooling.c cooling/EAGLE/cooling_tables.c
 endif
 
+# source files for EAGLE feedback
+EAGLE_FEEDBACK_SOURCES =
+if HAVEEAGLEFEEDBACK
+EAGLE_FEEDBACK_SOURCES += feedback/EAGLE/feedback.c
+endif
+
 # Common source files
 AM_SOURCES = space.c runner.c queue.c task.c cell.c engine.c engine_maketasks.c \
     engine_marktasks.c engine_drift.c serial_io.c timers.c debug.c scheduler.c \
@@ -72,7 +79,7 @@ AM_SOURCES = space.c runner.c queue.c task.c cell.c engine.c engine_maketasks.c
     collectgroup.c hydro_space.c equation_of_state.c \
     chemistry.c cosmology.c restart.c mesh_gravity.c velociraptor_interface.c \
     outputlist.c velociraptor_dummy.c logger_io.c memuse.c \
-    $(EAGLE_COOLING_SOURCES)
+    $(EAGLE_COOLING_SOURCES) $(EAGLE_FEEDBACK_SOURCES)
 
 # Include files for distribution, not installation.
 nobase_noinst_HEADERS = align.h approx_math.h atomic.h barrier.h cycle.h error.h inline.h kernel_hydro.h kernel_gravity.h \
@@ -183,6 +190,11 @@ nobase_noinst_HEADERS = align.h approx_math.h atomic.h barrier.h cycle.h error.h
                  tracers/none/tracers_io.h \
 		 tracers/EAGLE/tracers.h tracers/EAGLE/tracers_struct.h \
                  tracers/EAGLE/tracers_io.h \
+	         feedback/none/feedback.h feedback/none/feedback_struct.h feedback/none/feedback_iact.h \
+                 feedback/none/feedback_properties.h \
+	         feedback/EAGLE/feedback.h feedback/EAGLE/feedback_struct.h feedback/EAGLE/feedback_iact.h \
+                 feedback/EAGLE/feedback_properties.h feedback/EAGLE/imf.h feedback/EAGLE/interpolate.h \
+                 feedback/EAGLE/yield_tables.h \
                  black_holes/Default/black_holes.h black_holes/Default/black_holes_io.h \
 		 black_holes/Default/black_holes_part.h 
 
diff --git a/src/cell.c b/src/cell.c
index 9e05d555c7fc500e31e12fca8c568a2e3a47d600..c1ee647717c4793508c726ca6a0ac5834388e8de 100644
--- a/src/cell.c
+++ b/src/cell.c
@@ -54,6 +54,7 @@
 #include "drift.h"
 #include "engine.h"
 #include "error.h"
+#include "feedback.h"
 #include "gravity.h"
 #include "hydro.h"
 #include "hydro_properties.h"
@@ -4193,7 +4194,11 @@ void cell_drift_part(struct cell *c, const struct engine *e, int force) {
       if (fabs(xp->v_full[0] * dt_drift) > e->s->dim[0] ||
           fabs(xp->v_full[1] * dt_drift) > e->s->dim[1] ||
           fabs(xp->v_full[2] * dt_drift) > e->s->dim[2]) {
-        error("Particle drifts by more than a box length!");
+        error(
+            "Particle drifts by more than a box length! id %llu xp->v_full "
+            "%.5e %.5e %.5e p->v %.5e %.5e %.5e",
+            p->id, xp->v_full[0], xp->v_full[1], xp->v_full[2], p->v[0],
+            p->v[1], p->v[2]);
       }
 #endif
 
@@ -4209,12 +4214,8 @@ void cell_drift_part(struct cell *c, const struct engine *e, int force) {
           hydro_remove_part(p, xp);
 
           /* Remove the particle entirely */
-          struct gpart *gp = p->gpart;
           cell_remove_part(e, c, p, xp);
 
-          /* and it's gravity friend */
-          if (gp != NULL) cell_remove_gpart(e, c, gp);
-
           continue;
         }
       }
@@ -4351,7 +4352,10 @@ void cell_drift_gpart(struct cell *c, const struct engine *e, int force) {
       if (fabs(gp->v_full[0] * dt_drift) > e->s->dim[0] ||
           fabs(gp->v_full[1] * dt_drift) > e->s->dim[1] ||
           fabs(gp->v_full[2] * dt_drift) > e->s->dim[2]) {
-        error("Particle drifts by more than a box length!");
+        error(
+            "Particle drifts by more than a box length! gp->v_full %.5e %.5e "
+            "%.5e",
+            gp->v_full[0], gp->v_full[1], gp->v_full[2]);
       }
 #endif
 
@@ -4364,7 +4368,7 @@ void cell_drift_gpart(struct cell *c, const struct engine *e, int force) {
             (gp->x[2] > dim[2]) || (gp->x[2] < 0.)) {  // z
 
           /* Remove the particle entirely */
-          if (gp->type == swift_type_dark_matter) cell_remove_gpart(e, c, gp);
+          cell_remove_gpart(e, c, gp);
 
           continue;
         }
@@ -4533,6 +4537,7 @@ void cell_drift_spart(struct cell *c, const struct engine *e, int force) {
       /* Get ready for a density calculation */
       if (spart_is_active(sp, e)) {
         stars_init_spart(sp);
+        feedback_init_spart(sp);
       }
     }
 
@@ -5086,9 +5091,6 @@ void cell_remove_gpart(const struct engine *e, struct cell *c,
   if (c->nodeID != e->nodeID)
     error("Can't remove a particle in a foreign cell.");
 
-  if (gp->type != swift_type_dark_matter)
-    error("Trying to remove a non-dark matter gpart.");
-
   /* Mark the particle as inhibited */
   gp->time_bin = time_bin_inhibited;
 }
diff --git a/src/chemistry/EAGLE/chemistry.h b/src/chemistry/EAGLE/chemistry.h
index 7cb61d11fc5578da4cf545448c7fdc2e6b0b12ed..8c0061eef618fa7c01c48ae0ace763a20d85e762 100644
--- a/src/chemistry/EAGLE/chemistry.h
+++ b/src/chemistry/EAGLE/chemistry.h
@@ -164,7 +164,7 @@ __attribute__((always_inline)) INLINE static void chemistry_first_init_part(
     const struct chemistry_global_data* data, struct part* restrict p,
     struct xpart* restrict xp) {
 
-  // Add initialization of all other fields in chemistry_part_data struct.
+  /* Initialize mass fractions for total metals and each metal individually */
   if (data->initial_metal_mass_fraction_total != -1) {
     p->chemistry_data.metal_mass_fraction_total =
         data->initial_metal_mass_fraction_total;
@@ -176,6 +176,27 @@ __attribute__((always_inline)) INLINE static void chemistry_first_init_part(
   chemistry_init_part(p, data);
 }
 
+/**
+ * @brief Sets the chemistry properties of the sparticles to a valid start
+ * state.
+ *
+ * @param data The global chemistry information.
+ * @param sp Pointer to the sparticle data.
+ */
+__attribute__((always_inline)) INLINE static void chemistry_first_init_spart(
+    const struct chemistry_global_data* data, struct spart* restrict sp) {
+
+  /* Initialize mass fractions for total metals and each metal individually */
+  if (data->initial_metal_mass_fraction_total != -1) {
+    sp->chemistry_data.metal_mass_fraction_total =
+        data->initial_metal_mass_fraction_total;
+
+    for (int elem = 0; elem < chemistry_element_count; ++elem)
+      sp->chemistry_data.metal_mass_fraction[elem] =
+          data->initial_metal_mass_fraction[elem];
+  }
+}
+
 /**
  * @brief Initialises the chemistry properties.
  *
diff --git a/src/chemistry/none/chemistry.h b/src/chemistry/none/chemistry.h
index dce06ffda339e8a6c4925c7b7c430485a208adb7..543a5e77eea245da9ec18de210c781d5be07d7fb 100644
--- a/src/chemistry/none/chemistry.h
+++ b/src/chemistry/none/chemistry.h
@@ -133,4 +133,17 @@ __attribute__((always_inline)) INLINE static void chemistry_first_init_part(
 __attribute__((always_inline)) INLINE static void chemistry_init_part(
     struct part* restrict p, const struct chemistry_global_data* data) {}
 
+/**
+ * @brief Sets the chemistry properties of the sparticles to a valid start
+ * state.
+ *
+ * @param phys_const The physical constants in internal units.
+ * @param us The internal system of units.
+ * @param cosmo The current cosmological model.
+ * @param data The global chemistry information.
+ * @param sp Pointer to the sparticle data.
+ * @param xp Pointer to the extended particle data.
+ */
+__attribute__((always_inline)) INLINE static void chemistry_first_init_spart(
+    const struct chemistry_global_data* data, struct spart* restrict sp) {}
 #endif /* SWIFT_CHEMISTRY_NONE_H */
diff --git a/src/cooling.c b/src/cooling.c
index e203ddb34d7b7f45010da9c47383966a5cf25f39..b2a711bcda0a8208c8de92fddb341f4288034c4d 100644
--- a/src/cooling.c
+++ b/src/cooling.c
@@ -36,6 +36,7 @@
  * @param parameter_file The parsed parameter file.
  * @param us The current internal system of units.
  * @param phys_const The physical constants in internal units.
+ * @param hydro_props The properties of the hydro scheme.
  * @param cooling The cooling properties to initialize
  */
 void cooling_init(struct swift_params* parameter_file,
diff --git a/src/cooling/EAGLE/cooling.c b/src/cooling/EAGLE/cooling.c
index 3933d536720e81f3737be53d16432b20b8913c6a..af7a4c90eee1e581f24e6b303ee3c99c721b530b 100644
--- a/src/cooling/EAGLE/cooling.c
+++ b/src/cooling/EAGLE/cooling.c
@@ -361,8 +361,8 @@ INLINE static double bisection_iter(
     if (i >= bisection_max_iterations) {
       error(
           "particle %llu exceeded max iterations searching for bounds when "
-          "cooling",
-          ID);
+          "cooling, u_ini_cgs %.5e n_H_cgs %.5e",
+          ID, u_ini_cgs, n_H_cgs);
     }
   } else {
 
@@ -397,8 +397,8 @@ INLINE static double bisection_iter(
     if (i >= bisection_max_iterations) {
       error(
           "particle %llu exceeded max iterations searching for bounds when "
-          "heating",
-          ID);
+          "heating, u_ini_cgs %.5e n_H_cgs %.5e",
+          ID, u_ini_cgs, n_H_cgs);
     }
   }
 
@@ -423,6 +423,10 @@ INLINE static double bisection_iter(
                            n_H_index, d_n_H, He_index, d_He, cooling,
                            /*dLambdaNet_du=*/NULL);
 
+    // Debugging
+    if (u_next_cgs <= 0)
+      error("u_next_cgs %.5e u_upper %.5e u_lower %.5e Lambda %.5e", u_next_cgs,
+            u_upper_cgs, u_lower_cgs, LambdaNet_cgs);
     /* Where do we go next? */
     if (u_next_cgs - u_ini_cgs - LambdaNet_cgs * ratefact_cgs * dt_cgs > 0.0) {
       u_upper_cgs = u_next_cgs;
diff --git a/src/cosmology.c b/src/cosmology.c
index 5dfe1d7f01fc6d596942188b90fbb4598b7a6810..45f87c3bb4b5878216be164ee6f7ff83aaaed8c7 100644
--- a/src/cosmology.c
+++ b/src/cosmology.c
@@ -777,6 +777,35 @@ double cosmology_get_delta_time(const struct cosmology *c,
   return t2 - t1;
 }
 
+/**
+ * @brief Compute the cosmic time (in internal units) between two scale factors
+ *
+ * @param c The current #cosmology.
+ * @param a_start the starting scale factor
+ * @param a_end the ending scale factor
+ */
+double cosmology_get_delta_time_from_scale_factors(const struct cosmology *c,
+                                                   const double a_start,
+                                                   const double a_end) {
+
+#ifdef SWIFT_DEBUG_CHECKS
+  if (a_end < a_start) error("a_end must be >= a_start");
+#endif
+
+  const double log_a_start = log(a_start);
+  const double log_a_end = log(a_end);
+
+  /* Time between a_begin and a_start */
+  const double t1 = interp_table(c->time_interp_table, log_a_start,
+                                 c->log_a_begin, c->log_a_end);
+
+  /* Time between a_begin and a_end */
+  const double t2 = interp_table(c->time_interp_table, log_a_end,
+                                 c->log_a_begin, c->log_a_end);
+
+  return t2 - t1;
+}
+
 /**
  * @brief Compute scale factor from time since big bang (in internal units).
  *
diff --git a/src/cosmology.h b/src/cosmology.h
index f2abdb6c62e7509c593b5edfbdb9dd8fe0c99e72..8a0963d92edf658498b09299ad2e28790805232c 100644
--- a/src/cosmology.h
+++ b/src/cosmology.h
@@ -200,6 +200,10 @@ double cosmology_get_corr_kick_factor(const struct cosmology *cosmo,
 double cosmology_get_delta_time(const struct cosmology *c,
                                 integertime_t ti_start, integertime_t ti_end);
 
+double cosmology_get_delta_time_from_scale_factors(const struct cosmology *c,
+                                                   const double a_start,
+                                                   const double a_end);
+
 double cosmology_get_scale_factor(const struct cosmology *cosmo, double t);
 
 double cosmology_get_time_since_big_bang(const struct cosmology *c, double a);
diff --git a/src/engine.c b/src/engine.c
index 53520c859ab762e2dc25874eb816f50c73e018da..8effa2f9e536bbb36e3ccc7a41f4c9161ffa1c2a 100644
--- a/src/engine.c
+++ b/src/engine.c
@@ -4855,6 +4855,7 @@ void engine_unpin(void) {
  * @param entropy_floor The #entropy_floor_properties for this run.
  * @param gravity The #gravity_props used for this run.
  * @param stars The #stars_props used for this run.
+ * @param feedback The #feedback_props used for this run.
  * @param mesh The #pm_mesh used for the long-range periodic forces.
  * @param potential The properties of the external potential.
  * @param cooling_func The properties of the cooling function.
@@ -4869,7 +4870,7 @@ void engine_init(struct engine *e, struct space *s, struct swift_params *params,
                  struct cosmology *cosmo, struct hydro_props *hydro,
                  const struct entropy_floor_properties *entropy_floor,
                  struct gravity_props *gravity, const struct stars_props *stars,
-                 struct pm_mesh *mesh,
+                 const struct feedback_props *feedback, struct pm_mesh *mesh,
                  const struct external_potential *potential,
                  struct cooling_function_data *cooling_func,
                  const struct star_formation *starform,
@@ -4940,6 +4941,7 @@ void engine_init(struct engine *e, struct space *s, struct swift_params *params,
   e->external_potential = potential;
   e->cooling_func = cooling_func;
   e->star_formation = starform;
+  e->feedback_props = feedback;
   e->chemistry = chemistry;
   e->parameter_file = params;
 #ifdef WITH_MPI
diff --git a/src/engine.h b/src/engine.h
index 37d5848856aa3066349985d11b476190faa796b3..fe40a4212c5e6b48844d18a6a1d54c25fc73602e 100644
--- a/src/engine.h
+++ b/src/engine.h
@@ -414,6 +414,9 @@ struct engine {
   /* Properties of the starformation law */
   const struct star_formation *star_formation;
 
+  /* Properties of the sellar feedback model */
+  const struct feedback_props *feedback_props;
+
   /* Properties of the chemistry model */
   const struct chemistry_global_data *chemistry;
 
@@ -470,7 +473,7 @@ void engine_init(struct engine *e, struct space *s, struct swift_params *params,
                  struct cosmology *cosmo, struct hydro_props *hydro,
                  const struct entropy_floor_properties *entropy_floor,
                  struct gravity_props *gravity, const struct stars_props *stars,
-                 struct pm_mesh *mesh,
+                 const struct feedback_props *feedback, struct pm_mesh *mesh,
                  const struct external_potential *potential,
                  struct cooling_function_data *cooling_func,
                  const struct star_formation *starform,
diff --git a/src/feedback.h b/src/feedback.h
new file mode 100644
index 0000000000000000000000000000000000000000..ee2934c76456dd58b6909c63acfaa34104ac0300
--- /dev/null
+++ b/src/feedback.h
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Coypright (c) 2018 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_FEEDBACK_H
+#define SWIFT_FEEDBACK_H
+
+/* Config parameters. */
+#include "../config.h"
+
+/* Select the correct feedback model */
+#if defined(FEEDBACK_NONE)
+#include "./feedback/none/feedback.h"
+#include "./feedback/none/feedback_iact.h"
+#elif defined(FEEDBACK_EAGLE)
+#include "./feedback/EAGLE/feedback.h"
+#include "./feedback/EAGLE/feedback_iact.h"
+#else
+#error "Invalid choice of feedback model"
+#endif
+
+#endif
diff --git a/src/feedback/EAGLE/feedback.c b/src/feedback/EAGLE/feedback.c
new file mode 100644
index 0000000000000000000000000000000000000000..26ac30025e01dcc6f1214f60732fb814e87985b8
--- /dev/null
+++ b/src/feedback/EAGLE/feedback.c
@@ -0,0 +1,968 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Copyright (c) 2018 Matthieu Schaller (schaller@strw.leidenuniv.nl)
+ *
+ * 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/>.
+ *
+ ******************************************************************************/
+
+/* This file's header */
+#include "feedback.h"
+
+/* Local includes. */
+#include "hydro_properties.h"
+#include "imf.h"
+#include "inline.h"
+#include "interpolate.h"
+#include "yield_tables.h"
+
+/**
+ * @brief Return the change in temperature (in internal units) to apply to a
+ * gas particle affected by SNe feedback.
+ *
+ * @param sp The #spart.
+ * @param props The properties of the feedback model.
+ */
+double eagle_feedback_temperature_change(const struct spart* sp,
+                                         const struct feedback_props* props) {
+
+  /* In the EAGLE REF model, the change of temperature is constant */
+  return props->SNe_deltaT_desired;
+}
+
+/**
+ * @brief Computes the number of supernovae of type II exploding for a given
+ * star particle.
+ *
+ * @param sp The #spart.
+ * @param props The properties of the stellar model.
+ */
+double eagle_feedback_number_of_SNII(const struct spart* sp,
+                                     const struct feedback_props* props) {
+
+  /* Note: For a Chabrier 2003 IMF and SNII going off between 6 and 100
+   * M_sun, the first term is 0.017362 M_sun^-1 */
+  return props->num_SNII_per_msun * sp->mass_init * props->mass_to_solar_mass;
+}
+
+/**
+ * @brief Computes the number of supernovae of type Ia exploding for a given
+ * star particle between time t and t+dt
+ *
+ * We follow Foerster et al. 2006, MNRAS, 368
+ *
+ * @param sp The #spart.
+ * @param t0 The initial time (in Gyr).
+ * @param t1 The final time (in Gyr).
+ * @param props The properties of the stellar model.
+ */
+double eagle_feedback_number_of_SNIa(const struct spart* sp, const double t0,
+                                     const double t1,
+                                     const struct feedback_props* props) {
+
+  /* The calculation is written as the integral between t0 and t1 of
+   * eq. 3 of Schaye 2015 paper. */
+  const double tau = props->SNIa_timescale_Gyr_inv;
+  const double nu = props->SNIa_efficiency;
+  const double num_SNe_per_Msun = nu * (exp(-t0 * tau) - exp(-t1 * tau));
+
+  return num_SNe_per_Msun * sp->mass_init * props->mass_to_solar_mass;
+}
+
+/**
+ * @brief Computes the fraction of the available super-novae energy to
+ * inject for a given event.
+ *
+ * Note that the fraction can be > 1.
+ *
+ * We use equation 7 of Schaye et al. 2015.
+ *
+ * @param sp The #spart.
+ * @param props The properties of the feedback model.
+ */
+double eagle_feedback_energy_fraction(const struct spart* sp,
+                                      const struct feedback_props* props) {
+
+  /* Model parameters */
+  const double f_E_max = props->f_E_max;
+  const double f_E_min = props->f_E_min;
+  const double Z_0 = props->Z_0;
+  const double n_0 = props->n_0_cgs;
+  const double n_Z = props->n_Z;
+  const double n_n = props->n_n;
+
+  /* Star properties */
+
+  /* Smoothed metallicity (metal mass fraction) at birth time of the star */
+  const double Z_smooth = sp->chemistry_data.smoothed_metal_mass_fraction_total;
+
+  /* Physical density of the gas at the star's birth time */
+  const double rho_birth = sp->birth_density;
+  double n_birth = rho_birth * props->rho_to_n_cgs;
+
+  /* Calculate f_E */
+  const double Z_term = pow(max(Z_smooth, 1e-6) / Z_0, n_Z);
+  const double n_term = pow(max(n_birth, 1e-6) / n_0, -n_n);
+  const double denonimator = 1. + Z_term * n_term;
+
+  return f_E_min + (f_E_max - f_E_min) / denonimator;
+}
+
+/**
+ * @brief Compute the properties of the SNe feedback energy injection.
+ *
+ * Only does something if the particle reached the SNe age during this time
+ * step.
+ *
+ * @param sp The star particle.
+ * @param star_age Age of star at the beginning of the step in internal units.
+ * @param dt Length of time-step in internal units.
+ * @param ngb_gas_mass Total un-weighted mass in the star's kernel.
+ * @param feedback_props The properties of the feedback model.
+ */
+INLINE static void compute_SNe_feedback(
+    struct spart* sp, const double star_age, const double dt,
+    const float ngb_gas_mass, const struct feedback_props* feedback_props) {
+
+  /* Time after birth considered for SNII feedback (internal units) */
+  const float SNII_wind_delay = feedback_props->SNII_wind_delay;
+
+  /* Are we doing feedback this step? */
+  if (star_age <= SNII_wind_delay && (star_age + dt) > SNII_wind_delay) {
+
+    /* Properties of the model (all in internal units) */
+    const double delta_T =
+        eagle_feedback_temperature_change(sp, feedback_props);
+    const double N_SNe = eagle_feedback_number_of_SNII(sp, feedback_props);
+    const double E_SNe = feedback_props->E_SNII;
+    const double f_E = eagle_feedback_energy_fraction(sp, feedback_props);
+
+    /* Conversion factor from T to internal energy */
+    const double conv_factor = feedback_props->temp_to_u_factor;
+
+    /* Calculate the default heating probability */
+    double prob = f_E * E_SNe * N_SNe / (conv_factor * delta_T * ngb_gas_mass);
+
+    /* Calculate the change in internal energy of the gas particles that get
+     * heated */
+    double delta_u;
+    if (prob <= 1.) {
+
+      /* Normal case */
+      delta_u = delta_T * conv_factor;
+
+    } else {
+
+      /* Special case: we need to adjust the energy irrespective of the
+         desired deltaT to ensure we inject all the available energy. */
+
+      prob = 1.;
+      delta_u = f_E * E_SNe * N_SNe / ngb_gas_mass;
+    }
+
+    /* Store all of this in the star for delivery onto the gas */
+    sp->feedback_data.to_distribute.SNII_heating_probability = prob;
+    sp->feedback_data.to_distribute.SNII_delta_u = delta_u;
+  }
+}
+
+/**
+ * @brief Find the bins and offset along the metallicity dimension of the
+ * AGB yields table.
+ *
+ * @param iz_low (return) Lower index along the metallicity dimension.
+ * @param iz_high (return) High index along the metallicity dimension.
+ * @param dz (return) Offset between the metallicity bin and Z.
+ * @param log10_Z log10 of the star metallicity (metal mass fraction).
+ * @param props The properties of the feedback model.
+ */
+INLINE static void determine_bin_yield_AGB(int* iz_low, int* iz_high, float* dz,
+                                           const float log10_Z,
+                                           const struct feedback_props* props) {
+
+  const double* AGB_Z = props->yield_AGB.metallicity;
+  const int N_bins = eagle_feedback_AGB_N_metals;
+
+  if (log10_Z > log10_min_metallicity) {
+
+    /* Find metallicity bin which contains the star's metallicity */
+    int j;
+    for (j = 0; j < (N_bins - 1) && log10_Z > AGB_Z[j + 1]; j++)
+      ;
+
+    /* Store the indices */
+    *iz_low = j;
+    *iz_high = *iz_low + 1;
+
+    *iz_high = min(*iz_high, N_bins - 1);
+
+    /* Compute offset */
+    if ((log10_Z >= AGB_Z[0]) && (log10_Z <= AGB_Z[N_bins - 1])) {
+
+      *dz = log10_Z - AGB_Z[*iz_low];
+    } else {
+      *dz = 0.f;
+    }
+
+    /* Normalize offset */
+    const float delta_Z = AGB_Z[*iz_high] - AGB_Z[*iz_low];
+
+    if (delta_Z > 0.f)
+      *dz /= delta_Z;
+    else
+      *dz = 0.f;
+
+  } else {
+    *iz_low = 0;
+    *iz_high = 0;
+    *dz = 0.f;
+  }
+}
+
+/**
+ * @brief Find the bins and offset along the metallicity dimension of the
+ * SNII yields table.
+ *
+ * @param iz_low (return) Lower index along the metallicity dimension.
+ * @param iz_high (return) High index along the metallicity dimension.
+ * @param dz (return) Offset between the metallicity bin and Z.
+ * @param log10_Z log10 of the star metallicity (metal mass fraction).
+ * @param props The properties of the feedback model.
+ */
+INLINE static void determine_bin_yield_SNII(
+    int* iz_low, int* iz_high, float* dz, const float log10_Z,
+    const struct feedback_props* props) {
+
+  const double* SNII_Z = props->yield_SNII.metallicity;
+  const int N_bins = eagle_feedback_SNII_N_metals;
+
+  if (log10_Z > log10_min_metallicity) {
+
+    /* Find metallicity bin which contains the star's metallicity */
+    int j;
+    for (j = 0; j < (N_bins - 1) && log10_Z > SNII_Z[j + 1]; j++)
+      ;
+
+    /* Store the indices */
+    *iz_low = j;
+    *iz_high = *iz_low + 1;
+
+    *iz_high = min(*iz_high, N_bins - 1);
+
+    /* Compute offset */
+    if ((log10_Z >= SNII_Z[0]) && (log10_Z <= SNII_Z[N_bins - 1])) {
+
+      *dz = log10_Z - SNII_Z[*iz_low];
+    } else {
+      *dz = 0.f;
+    }
+
+    /* Normalize offset */
+    const float delta_Z = SNII_Z[*iz_high] - SNII_Z[*iz_low];
+
+    if (delta_Z > 0.f)
+      *dz = *dz / delta_Z;
+    else
+      *dz = 0.f;
+
+  } else {
+    *iz_low = 0;
+    *iz_high = 0;
+    *dz = 0.f;
+  }
+}
+
+/**
+ * @brief compute enrichment and feedback due to SNIa. To do this compute the
+ * number of SNIa that occur during the timestep, multiply by constants read
+ * from tables.
+ *
+ * @param log10_min_mass log10 mass at the end of step
+ * @param log10_max_mass log10 mass at the beginning of step
+ * @param props properties of the feedback model
+ * @param sp #spart we are computing feedback from
+ * @param star_age_Gyr age of star in Gyr
+ * @param dt_Gyr timestep dt in Gyr
+ */
+INLINE static void evolve_SNIa(const float log10_min_mass,
+                               const float log10_max_mass,
+                               const struct feedback_props* props,
+                               struct spart* sp, float star_age_Gyr,
+                               float dt_Gyr) {
+
+  /* Check if we're outside the mass range for SNIa */
+  if (log10_min_mass >= props->log10_SNIa_max_mass_msun) return;
+
+  /* If the max mass is outside the mass range update it to be the maximum
+   * and use updated values for the star's age and timestep in this function */
+  if (log10_max_mass > props->log10_SNIa_max_mass_msun) {
+
+    const float Z = sp->chemistry_data.metal_mass_fraction_total;
+    const float max_mass = exp10f(props->log10_SNIa_max_mass_msun);
+    const float lifetime_Gyr = lifetime_in_Gyr(max_mass, Z, props);
+
+    dt_Gyr = star_age_Gyr + dt_Gyr - lifetime_Gyr;
+    star_age_Gyr = lifetime_Gyr;
+  }
+
+  /* Compute the number of SNIa */
+  const float num_SNIa = eagle_feedback_number_of_SNIa(
+      sp, star_age_Gyr, star_age_Gyr + dt_Gyr, props);
+
+  /* compute mass of each metal */
+  for (int i = 0; i < chemistry_element_count; i++) {
+    sp->feedback_data.to_distribute.metal_mass[i] +=
+        num_SNIa * props->yield_SNIa_IMF_resampled[i] *
+        props->solar_mass_to_mass;
+  }
+
+  /* Update the metallicity of the material released */
+  sp->feedback_data.to_distribute.metal_mass_from_SNIa +=
+      num_SNIa * props->yield_SNIa_total_metals_IMF_resampled *
+      props->solar_mass_to_mass;
+
+  /* Update the metal mass produced */
+  sp->feedback_data.to_distribute.total_metal_mass +=
+      num_SNIa * props->yield_SNIa_total_metals_IMF_resampled *
+      props->solar_mass_to_mass;
+
+  /* Compute the mass produced by SNIa
+   * Note: SNIa do not inject H or He so the mass injected is the same
+   * as the metal mass injected. */
+  sp->feedback_data.to_distribute.mass_from_SNIa +=
+      num_SNIa * props->yield_SNIa_total_metals_IMF_resampled *
+      props->solar_mass_to_mass;
+
+  /* Compute the iron mass produced */
+  sp->feedback_data.to_distribute.Fe_mass_from_SNIa +=
+      num_SNIa * props->yield_SNIa_IMF_resampled[chemistry_element_Fe] *
+      props->solar_mass_to_mass;
+
+  /* Compute the energy to be injected */
+  sp->feedback_data.to_distribute.energy += num_SNIa * props->E_SNIa;
+}
+
+/**
+ * @brief compute enrichment and feedback due to SNII. To do this, integrate the
+ * IMF weighted by the yields read from tables for each of the quantities of
+ * interest.
+ *
+ * Note for Matthieu: This function is poorly written and needs improving.
+ *
+ * @param log10_min_mass log10 mass at the end of step
+ * @param log10_max_mass log10 mass at the beginning of step
+ * @param stellar_yields array to store calculated yields for passing to
+ * integrate_imf
+ * @param props properties of the feedback model.
+ * @param sp spart we are computing feedback from
+ */
+INLINE static void evolve_SNII(float log10_min_mass, float log10_max_mass,
+                               float* stellar_yields,
+                               const struct feedback_props* props,
+                               struct spart* sp) {
+
+  int low_imf_mass_bin_index, high_imf_mass_bin_index, mass_bin_index;
+
+  /* If mass at beginning of step is less than tabulated lower bound for IMF,
+   * limit it.*/
+  if (log10_min_mass < props->log10_SNII_min_mass_msun)
+    log10_min_mass = props->log10_SNII_min_mass_msun;
+
+  /* If mass at end of step is greater than tabulated upper bound for IMF, limit
+   * it.*/
+  if (log10_max_mass > props->log10_SNII_max_mass_msun)
+    log10_max_mass = props->log10_SNII_max_mass_msun;
+
+  /* Don't do anything if the stellar mass hasn't decreased by the end of the
+   * step */
+  if (log10_min_mass >= log10_max_mass) return;
+
+  /* determine which IMF mass bins contribute to the integral */
+  determine_imf_bins(log10_min_mass, log10_max_mass, &low_imf_mass_bin_index,
+                     &high_imf_mass_bin_index, props);
+
+  /* determine which metallicity bin and offset this star belongs to */
+  int iz_low = 0, iz_high = 0, low_index_3d, high_index_3d, low_index_2d,
+      high_index_2d;
+  float dz = 0.;
+  determine_bin_yield_SNII(&iz_low, &iz_high, &dz,
+                           log10(sp->chemistry_data.metal_mass_fraction_total),
+                           props);
+
+  /* compute metals produced */
+  float metal_mass_released[chemistry_element_count], metal_mass_released_total;
+  for (int elem = 0; elem < chemistry_element_count; elem++) {
+    for (mass_bin_index = low_imf_mass_bin_index;
+         mass_bin_index < high_imf_mass_bin_index + 1; mass_bin_index++) {
+      low_index_3d = row_major_index_3d(
+          iz_low, elem, mass_bin_index, eagle_feedback_SNII_N_metals,
+          chemistry_element_count, eagle_feedback_N_imf_bins);
+      high_index_3d = row_major_index_3d(
+          iz_high, elem, mass_bin_index, eagle_feedback_SNII_N_metals,
+          chemistry_element_count, eagle_feedback_N_imf_bins);
+      low_index_2d = row_major_index_2d(iz_low, mass_bin_index,
+                                        eagle_feedback_SNII_N_metals,
+                                        eagle_feedback_N_imf_bins);
+      high_index_2d = row_major_index_2d(iz_high, mass_bin_index,
+                                         eagle_feedback_SNII_N_metals,
+                                         eagle_feedback_N_imf_bins);
+      stellar_yields[mass_bin_index] =
+          (1 - dz) *
+              (props->yield_SNII.yield_IMF_resampled[low_index_3d] +
+               sp->chemistry_data.metal_mass_fraction[elem] *
+                   props->yield_SNII.ejecta_IMF_resampled[low_index_2d]) +
+          dz * (props->yield_SNII.yield_IMF_resampled[high_index_3d] +
+                sp->chemistry_data.metal_mass_fraction[elem] *
+                    props->yield_SNII.ejecta_IMF_resampled[high_index_2d]);
+    }
+
+    metal_mass_released[elem] = integrate_imf(
+        log10_min_mass, log10_max_mass, eagle_imf_integration_yield_weight,
+        stellar_yields, props);
+  }
+
+  /* Compute mass produced */
+  for (mass_bin_index = low_imf_mass_bin_index;
+       mass_bin_index < high_imf_mass_bin_index + 1; mass_bin_index++) {
+    low_index_2d =
+        row_major_index_2d(iz_low, mass_bin_index, eagle_feedback_SNII_N_metals,
+                           eagle_feedback_N_imf_bins);
+    high_index_2d = row_major_index_2d(iz_high, mass_bin_index,
+                                       eagle_feedback_SNII_N_metals,
+                                       eagle_feedback_N_imf_bins);
+    stellar_yields[mass_bin_index] =
+        (1 - dz) * (props->yield_SNII.total_metals_IMF_resampled[low_index_2d] +
+                    sp->chemistry_data.metal_mass_fraction_total *
+                        props->yield_SNII.ejecta_IMF_resampled[low_index_2d]) +
+        dz * (props->yield_SNII.total_metals_IMF_resampled[high_index_2d] +
+              sp->chemistry_data.metal_mass_fraction_total *
+                  props->yield_SNII.ejecta_IMF_resampled[high_index_2d]);
+  }
+
+  metal_mass_released_total =
+      integrate_imf(log10_min_mass, log10_max_mass,
+                    eagle_imf_integration_yield_weight, stellar_yields, props);
+
+  /* yield normalization */
+  float mass_ejected, mass_released;
+
+  /* zero all negative values */
+  for (int i = 0; i < chemistry_element_count; i++)
+    metal_mass_released[i] = max(metal_mass_released[i], 0.f);
+
+  metal_mass_released_total = max(metal_mass_released_total, 0.f);
+
+  /* compute the total metal mass ejected from the star*/
+  for (mass_bin_index = low_imf_mass_bin_index;
+       mass_bin_index < high_imf_mass_bin_index + 1; mass_bin_index++) {
+    low_index_2d =
+        row_major_index_2d(iz_low, mass_bin_index, eagle_feedback_SNII_N_metals,
+                           eagle_feedback_N_imf_bins);
+    high_index_2d = row_major_index_2d(iz_high, mass_bin_index,
+                                       eagle_feedback_SNII_N_metals,
+                                       eagle_feedback_N_imf_bins);
+    stellar_yields[mass_bin_index] =
+        (1 - dz) * props->yield_SNII.ejecta_IMF_resampled[low_index_2d] +
+        dz * props->yield_SNII.ejecta_IMF_resampled[high_index_2d];
+  }
+
+  mass_ejected =
+      integrate_imf(log10_min_mass, log10_max_mass,
+                    eagle_imf_integration_yield_weight, stellar_yields, props);
+
+  /* compute the total mass released */
+  mass_released = metal_mass_released_total +
+                  metal_mass_released[chemistry_element_H] +
+                  metal_mass_released[chemistry_element_He];
+
+  /* normalize the yields */
+  if (mass_released > 0) {
+    /* Set normalisation factor. Note additional multiplication by the star
+     * initial mass as tables are per initial mass */
+    const float norm_factor = sp->mass_init * mass_ejected / mass_released;
+
+    for (int i = 0; i < chemistry_element_count; i++) {
+      sp->feedback_data.to_distribute.metal_mass[i] +=
+          metal_mass_released[i] * norm_factor;
+    }
+    for (int i = 0; i < chemistry_element_count; i++) {
+      sp->feedback_data.to_distribute.mass_from_SNII +=
+          sp->feedback_data.to_distribute.metal_mass[i];
+    }
+    sp->feedback_data.to_distribute.total_metal_mass +=
+        metal_mass_released_total * norm_factor;
+    sp->feedback_data.to_distribute.metal_mass_from_SNII +=
+        metal_mass_released_total * norm_factor;
+  } else {
+    error("wrong normalization!!!! mass_released = %e\n", mass_released);
+  }
+}
+
+/**
+ * @brief compute enrichment and feedback due to AGB. To do this, integrate the
+ * IMF weighted by the yields read from tables for each of the quantities of
+ * interest.
+ *
+ * Note for Matthieu: This function is poorly written and needs improving.
+ *
+ * @param log10_min_mass log10 mass at the end of step
+ * @param log10_max_mass log10 mass at the beginning of step
+ * @param stellar_yields array to store calculated yields for passing to
+ * integrate_imf
+ * @param props Properties of the feedback model.
+ * @param sp spart we are computing feedback for.
+ */
+INLINE static void evolve_AGB(const float log10_min_mass, float log10_max_mass,
+                              float* stellar_yields,
+                              const struct feedback_props* props,
+                              struct spart* sp) {
+
+  int low_imf_mass_bin_index, high_imf_mass_bin_index, mass_bin_index;
+
+  /* If mass at end of step is greater than tabulated lower bound for IMF, limit
+   * it.*/
+  if (log10_max_mass > props->log10_SNII_min_mass_msun)
+    log10_max_mass = props->log10_SNII_min_mass_msun;
+
+  /* Don't do anything if the stellar mass hasn't decreased by the end of the
+   * step */
+  if (log10_min_mass >= log10_max_mass) return;
+
+  /* determine which IMF mass bins contribute to the integral */
+  determine_imf_bins(log10_min_mass, log10_max_mass, &low_imf_mass_bin_index,
+                     &high_imf_mass_bin_index, props);
+
+  /* determine which metallicity bin and offset this star belongs to */
+  int iz_low = 0, iz_high = 0, low_index_3d, high_index_3d, low_index_2d,
+      high_index_2d;
+  float dz = 0.f;
+  determine_bin_yield_AGB(&iz_low, &iz_high, &dz,
+                          log10(sp->chemistry_data.metal_mass_fraction_total),
+                          props);
+
+  /* compute metals produced */
+  float metal_mass_released[chemistry_element_count], metal_mass_released_total;
+  for (int elem = 0; elem < chemistry_element_count; elem++) {
+    for (mass_bin_index = low_imf_mass_bin_index;
+         mass_bin_index < high_imf_mass_bin_index + 1; mass_bin_index++) {
+      low_index_3d = row_major_index_3d(
+          iz_low, elem, mass_bin_index, eagle_feedback_AGB_N_metals,
+          chemistry_element_count, eagle_feedback_N_imf_bins);
+      high_index_3d = row_major_index_3d(
+          iz_high, elem, mass_bin_index, eagle_feedback_AGB_N_metals,
+          chemistry_element_count, eagle_feedback_N_imf_bins);
+      low_index_2d = row_major_index_2d(iz_low, mass_bin_index,
+                                        eagle_feedback_AGB_N_metals,
+                                        eagle_feedback_N_imf_bins);
+      high_index_2d = row_major_index_2d(iz_high, mass_bin_index,
+                                         eagle_feedback_AGB_N_metals,
+                                         eagle_feedback_N_imf_bins);
+      stellar_yields[mass_bin_index] =
+          (1 - dz) * (props->yield_AGB.yield_IMF_resampled[low_index_3d] +
+                      sp->chemistry_data.metal_mass_fraction[elem] *
+                          props->yield_AGB.ejecta_IMF_resampled[low_index_2d]) +
+          dz * (props->yield_AGB.yield_IMF_resampled[high_index_3d] +
+                sp->chemistry_data.metal_mass_fraction[elem] *
+                    props->yield_AGB.ejecta_IMF_resampled[high_index_2d]);
+    }
+
+    metal_mass_released[elem] = integrate_imf(
+        log10_min_mass, log10_max_mass, eagle_imf_integration_yield_weight,
+        stellar_yields, props);
+  }
+
+  /* Compute mass produced */
+  for (mass_bin_index = low_imf_mass_bin_index;
+       mass_bin_index < high_imf_mass_bin_index + 1; mass_bin_index++) {
+    low_index_2d =
+        row_major_index_2d(iz_low, mass_bin_index, eagle_feedback_AGB_N_metals,
+                           eagle_feedback_N_imf_bins);
+    high_index_2d =
+        row_major_index_2d(iz_high, mass_bin_index, eagle_feedback_AGB_N_metals,
+                           eagle_feedback_N_imf_bins);
+    stellar_yields[mass_bin_index] =
+        (1 - dz) * (props->yield_AGB.total_metals_IMF_resampled[low_index_2d] +
+                    sp->chemistry_data.metal_mass_fraction_total *
+                        props->yield_AGB.ejecta_IMF_resampled[low_index_2d]) +
+        dz * (props->yield_AGB.total_metals_IMF_resampled[high_index_2d] +
+              sp->chemistry_data.metal_mass_fraction_total *
+                  props->yield_AGB.ejecta_IMF_resampled[high_index_2d]);
+  }
+
+  metal_mass_released_total =
+      integrate_imf(log10_min_mass, log10_max_mass,
+                    eagle_imf_integration_yield_weight, stellar_yields, props);
+
+  /* yield normalization */
+  float mass_ejected, mass_released;
+
+  /* zero all negative values */
+  for (int i = 0; i < chemistry_element_count; i++)
+    metal_mass_released[i] = max(metal_mass_released[i], 0.f);
+
+  metal_mass_released_total = max(metal_mass_released_total, 0.f);
+
+  /* compute the total metal mass ejected from the star */
+  for (mass_bin_index = low_imf_mass_bin_index;
+       mass_bin_index < high_imf_mass_bin_index + 1; mass_bin_index++) {
+    low_index_2d =
+        row_major_index_2d(iz_low, mass_bin_index, eagle_feedback_AGB_N_metals,
+                           eagle_feedback_N_imf_bins);
+    high_index_2d =
+        row_major_index_2d(iz_high, mass_bin_index, eagle_feedback_AGB_N_metals,
+                           eagle_feedback_N_imf_bins);
+    stellar_yields[mass_bin_index] =
+        (1 - dz) * props->yield_AGB.ejecta_IMF_resampled[low_index_2d] +
+        dz * props->yield_AGB.ejecta_IMF_resampled[high_index_2d];
+  }
+
+  mass_ejected =
+      integrate_imf(log10_min_mass, log10_max_mass,
+                    eagle_imf_integration_yield_weight, stellar_yields, props);
+
+  /* compute the total mass released */
+  mass_released = metal_mass_released_total +
+                  metal_mass_released[chemistry_element_H] +
+                  metal_mass_released[chemistry_element_He];
+
+  /* normalize the yields */
+  if (mass_released > 0) {
+
+    /* Set normalisation factor. Note additional multiplication by the stellar
+     * initial mass as tables are per initial mass */
+    const float norm_factor = sp->mass_init * mass_ejected / mass_released;
+
+    for (int i = 0; i < chemistry_element_count; i++) {
+      sp->feedback_data.to_distribute.metal_mass[i] +=
+          metal_mass_released[i] * norm_factor;
+      sp->feedback_data.to_distribute.mass_from_AGB +=
+          metal_mass_released[i] * norm_factor;
+    }
+    sp->feedback_data.to_distribute.total_metal_mass +=
+        metal_mass_released_total * norm_factor;
+    sp->feedback_data.to_distribute.metal_mass_from_AGB +=
+        metal_mass_released_total * norm_factor;
+  } else {
+    error("wrong normalization!!!! mass_released = %e\n", mass_released);
+  }
+}
+
+/**
+ * @brief calculates stellar mass in spart that died over the timestep, calls
+ * functions to calculate feedback due to SNIa, SNII and AGB
+ *
+ * @param feedback_props feedback_props data structure
+ * @param cosmo The cosmological model.
+ * @param sp spart that we're evolving
+ * @param us unit_system data structure
+ * @param age age of spart at beginning of step
+ * @param dt length of current timestep
+ */
+void compute_stellar_evolution(const struct feedback_props* feedback_props,
+                               const struct cosmology* cosmo, struct spart* sp,
+                               const struct unit_system* us, const float age,
+                               const float dt) {
+
+  /* Allocate temporary array for calculating imf weights */
+  float stellar_yields[eagle_feedback_N_imf_bins];
+
+  /* Convert dt and stellar age from internal units to Gyr. */
+  const double Gyr_in_cgs = 1e9 * 365. * 24. * 3600.;
+  const double time_to_cgs = units_cgs_conversion_factor(us, UNIT_CONV_TIME);
+  const float conversion_factor = time_to_cgs / Gyr_in_cgs;
+  const float dt_Gyr = dt * conversion_factor;
+  const float star_age_Gyr = age * conversion_factor;
+
+  /* Get the metallicity */
+  const float Z = sp->chemistry_data.metal_mass_fraction_total;
+
+  /* Properties collected in the stellar density loop. */
+  const float ngb_gas_mass = sp->feedback_data.to_collect.ngb_mass;
+  const float enrichment_weight_inv =
+      sp->feedback_data.to_collect.enrichment_weight_inv;
+
+  /* Now we start filling the data structure for information to apply to the
+   * particles. Do _NOT_ read from the to_collect substructure any more. */
+
+  /* Zero all the output fields */
+  feedback_reset_feedback(sp, feedback_props);
+
+  /* Update the weights used for distribution */
+  const float enrichment_weight =
+      (enrichment_weight_inv != 0.f) ? 1.f / enrichment_weight_inv : 0.f;
+  sp->feedback_data.to_distribute.enrichment_weight = enrichment_weight;
+
+  /* Compute properties of the stochastic SNe feedback model. */
+  if (feedback_props->with_SNe_feedback) {
+    compute_SNe_feedback(sp, age, dt, ngb_gas_mass, feedback_props);
+  }
+
+  /* Calculate mass of stars that has died from the star's birth up to the
+   * beginning and end of timestep */
+  const float max_dying_mass_Msun =
+      dying_mass_msun(star_age_Gyr, Z, feedback_props);
+  const float min_dying_mass_Msun =
+      dying_mass_msun(star_age_Gyr + dt_Gyr, Z, feedback_props);
+
+#ifdef SWIFT_DEBUG_CHECK
+  /* Sanity check. Worth investigating if necessary as functions for evaluating
+   * mass of stars dying might be strictly decreasing.  */
+  if (min_dying_mass_Msun > max_dying_mass_Msun)
+    error("min dying mass is greater than max dying mass");
+#endif
+
+  /* Integration interval is zero - this can happen if minimum and maximum
+   * dying masses are above imf_max_mass_Msun. Return without doing any
+   * enrichment. */
+  if (min_dying_mass_Msun == max_dying_mass_Msun) return;
+
+  /* Life is better in log */
+  const float log10_max_dying_mass_Msun = log10f(max_dying_mass_Msun);
+  const float log10_min_dying_mass_Msun = log10f(min_dying_mass_Msun);
+
+  /* Compute elements, energy and momentum to distribute from the
+   *  three channels SNIa, SNII, AGB */
+  if (feedback_props->with_SNIa_enrichment) {
+    evolve_SNIa(log10_min_dying_mass_Msun, log10_max_dying_mass_Msun,
+                feedback_props, sp, star_age_Gyr, dt_Gyr);
+  }
+  if (feedback_props->with_SNII_enrichment) {
+    evolve_SNII(log10_min_dying_mass_Msun, log10_max_dying_mass_Msun,
+                stellar_yields, feedback_props, sp);
+  }
+  if (feedback_props->with_AGB_enrichment) {
+    evolve_AGB(log10_min_dying_mass_Msun, log10_max_dying_mass_Msun,
+               stellar_yields, feedback_props, sp);
+  }
+
+#ifdef SWIFT_DEBUG_CHECKS
+  if (sp->feedback_data.to_distribute.mass != 0.f)
+    error("Injected mass will be lost");
+#endif
+
+  /* Compute the total mass to distribute (H + He  metals) */
+  sp->feedback_data.to_distribute.mass =
+      sp->feedback_data.to_distribute.total_metal_mass +
+      sp->feedback_data.to_distribute.metal_mass[chemistry_element_H] +
+      sp->feedback_data.to_distribute.metal_mass[chemistry_element_He];
+
+  /* Compute energy change due to kinetic energy of ejectas */
+  sp->feedback_data.to_distribute.energy +=
+      sp->feedback_data.to_distribute.mass *
+      feedback_props->AGB_ejecta_specific_kinetic_energy;
+
+  /* Compute energy change due to kinetic energy of the star */
+  sp->feedback_data.to_distribute.energy +=
+      sp->feedback_data.to_distribute.mass * 0.5f *
+      (sp->v[0] * sp->v[0] + sp->v[1] * sp->v[1] + sp->v[2] * sp->v[2]) *
+      cosmo->a2_inv;
+}
+
+/**
+ * @brief Initialize the global properties of the feedback scheme.
+ *
+ * By default, takes the values provided by the hydro.
+ *
+ * @param fp The #feedback_props.
+ * @param phys_const The physical constants in the internal unit system.
+ * @param us The internal unit system.
+ * @param params The parsed parameters.
+ * @param hydro_props The already read-in properties of the hydro scheme.
+ * @param cosmo The cosmological model.
+ */
+void feedback_props_init(struct feedback_props* fp,
+                         const struct phys_const* phys_const,
+                         const struct unit_system* us,
+                         struct swift_params* params,
+                         const struct hydro_props* hydro_props,
+                         const struct cosmology* cosmo) {
+
+  /* Main operation modes ------------------------------------------------- */
+
+  fp->with_SNe_feedback =
+      parser_get_param_int(params, "EAGLEFeedback:use_SNe_feedback");
+
+  fp->with_AGB_enrichment =
+      parser_get_param_int(params, "EAGLEFeedback:use_AGB_enrichment");
+
+  fp->with_SNII_enrichment =
+      parser_get_param_int(params, "EAGLEFeedback:use_SNII_enrichment");
+
+  fp->with_SNIa_enrichment =
+      parser_get_param_int(params, "EAGLEFeedback:use_SNIa_enrichment");
+
+  /* Properties of the IMF model ------------------------------------------ */
+
+  /* Minimal and maximal mass considered */
+  fp->imf_max_mass_msun =
+      parser_get_param_double(params, "EAGLEFeedback:IMF_max_mass_Msun");
+  fp->imf_min_mass_msun =
+      parser_get_param_double(params, "EAGLEFeedback:IMF_min_mass_Msun");
+
+  fp->log10_imf_max_mass_msun = log10(fp->imf_max_mass_msun);
+  fp->log10_imf_min_mass_msun = log10(fp->imf_min_mass_msun);
+
+  /* Properties of the SNII energy feedback model ------------------------- */
+
+  /* Set the delay time before SNII occur */
+  const float Gyr_in_cgs = 1e9 * 365 * 24 * 3600;
+  fp->SNII_wind_delay =
+      parser_get_param_float(params, "EAGLEFeedback:SNII_wind_delay_Gyr") *
+      Gyr_in_cgs / units_cgs_conversion_factor(us, UNIT_CONV_TIME);
+
+  /* Read the temperature change to use in stochastic heating */
+  fp->SNe_deltaT_desired =
+      parser_get_param_float(params, "EAGLEFeedback:SNII_delta_T_K");
+  fp->SNe_deltaT_desired /=
+      units_cgs_conversion_factor(us, UNIT_CONV_TEMPERATURE);
+
+  /* Energy released by supernova type II */
+  fp->E_SNII_cgs =
+      parser_get_param_double(params, "EAGLEFeedback:SNII_Energy_erg");
+  fp->E_SNII =
+      fp->E_SNII_cgs / units_cgs_conversion_factor(us, UNIT_CONV_ENERGY);
+
+  /* Stellar mass limits for SNII feedback */
+  const double SNII_min_mass_msun =
+      parser_get_param_double(params, "EAGLEFeedback:SNII_min_mass_Msun");
+  const double SNII_max_mass_msun =
+      parser_get_param_double(params, "EAGLEFeedback:SNII_max_mass_Msun");
+
+  fp->log10_SNII_min_mass_msun = log10(SNII_min_mass_msun);
+  fp->log10_SNII_max_mass_msun = log10(SNII_max_mass_msun);
+
+  /* Properties of the energy fraction model */
+  fp->f_E_min =
+      parser_get_param_double(params, "EAGLEFeedback:SNII_Energy_fraction_min");
+  fp->f_E_max =
+      parser_get_param_double(params, "EAGLEFeedback:SNII_Energy_fraction_max");
+  fp->Z_0 =
+      parser_get_param_double(params, "EAGLEFeedback:SNII_Energy_fraction_Z_0");
+  fp->n_0_cgs = parser_get_param_double(
+      params, "EAGLEFeedback:SNII_Energy_fraction_n_0_H_p_cm3");
+  fp->n_n =
+      parser_get_param_double(params, "EAGLEFeedback:SNII_Energy_fraction_n_n");
+  fp->n_Z =
+      parser_get_param_double(params, "EAGLEFeedback:SNII_Energy_fraction_n_Z");
+
+  /* Properties of the SNII enrichment model -------------------------------- */
+
+  /* Set factors for each element adjusting SNII yield */
+  for (int elem = 0; elem < chemistry_element_count; ++elem) {
+    char buffer[50];
+    sprintf(buffer, "EAGLEFeedback:SNII_yield_factor_%s",
+            chemistry_get_element_name((enum chemistry_element)elem));
+
+    fp->SNII_yield_factor[elem] =
+        parser_get_opt_param_float(params, buffer, 1.f);
+  }
+
+  /* Properties of the SNIa enrichment model -------------------------------- */
+
+  const double SNIa_max_mass_msun =
+      parser_get_param_double(params, "EAGLEFeedback:SNIa_max_mass_Msun");
+  fp->log10_SNIa_max_mass_msun = log10(SNIa_max_mass_msun);
+
+  /* Read SNIa timescale model parameters */
+  fp->SNIa_efficiency =
+      parser_get_param_float(params, "EAGLEFeedback:SNIa_efficiency_p_Msun");
+  fp->SNIa_timescale_Gyr =
+      parser_get_param_float(params, "EAGLEFeedback:SNIa_timescale_Gyr");
+  fp->SNIa_timescale_Gyr_inv = 1.f / fp->SNIa_timescale_Gyr;
+
+  /* Energy released by supernova type Ia */
+  fp->E_SNIa_cgs =
+      parser_get_param_double(params, "EAGLEFeedback:SNIa_Energy_erg");
+  fp->E_SNIa =
+      fp->E_SNIa_cgs / units_cgs_conversion_factor(us, UNIT_CONV_ENERGY);
+
+  /* Properties of the SNIa enrichment model -------------------------------- */
+
+  /* Read AGB ejecta velocity */
+  const float ejecta_velocity_km_p_s = parser_get_param_float(
+      params, "EAGLEFeedback:AGB_ejecta_velocity_km_p_s");
+
+  /* Convert to internal units */
+  const float ejecta_velocity_cgs = ejecta_velocity_km_p_s * 1e5;
+  const float ejecta_velocity =
+      ejecta_velocity_cgs / units_cgs_conversion_factor(us, UNIT_CONV_SPEED);
+
+  /* Convert to specific thermal energy */
+  fp->AGB_ejecta_specific_kinetic_energy =
+      0.5f * ejecta_velocity * ejecta_velocity;
+
+  /* Gather common conversion factors --------------------------------------- */
+
+  /* Calculate internal mass to solar mass conversion factor */
+  const double Msun_cgs = phys_const->const_solar_mass *
+                          units_cgs_conversion_factor(us, UNIT_CONV_MASS);
+  const double unit_mass_cgs = units_cgs_conversion_factor(us, UNIT_CONV_MASS);
+  fp->mass_to_solar_mass = unit_mass_cgs / Msun_cgs;
+  fp->solar_mass_to_mass = 1. / fp->mass_to_solar_mass;
+
+  /* Calculate temperature to internal energy conversion factor (all internal
+   * units) */
+  const double k_B = phys_const->const_boltzmann_k;
+  const double m_p = phys_const->const_proton_mass;
+  const double mu = hydro_props->mu_ionised;
+  fp->temp_to_u_factor = k_B / (mu * hydro_gamma_minus_one * m_p);
+
+  /* Calculate conversion factor from rho to n_H
+   * Note this assumes primoridal abundance */
+  const double X_H = hydro_props->hydrogen_mass_fraction;
+  fp->rho_to_n_cgs =
+      (X_H / m_p) * units_cgs_conversion_factor(us, UNIT_CONV_NUMBER_DENSITY);
+
+  /* Initialise the IMF ------------------------------------------------- */
+
+  init_imf(fp);
+
+  /* Calculate number of type II SN per unit solar mass based on our choice
+   * of IMF and integration limits for type II SNe.
+   * Note: No weighting by yields here. */
+  fp->num_SNII_per_msun =
+      integrate_imf(fp->log10_SNII_min_mass_msun, fp->log10_SNII_max_mass_msun,
+                    eagle_imf_integration_no_weight,
+                    /*(stellar_yields=)*/ NULL, fp);
+
+  /* Initialise the yields ---------------------------------------------- */
+
+  /* Read yield table filepath  */
+  parser_get_param_string(params, "EAGLEFeedback:filename",
+                          fp->yield_table_path);
+
+  /* Allocate yield tables  */
+  allocate_yield_tables(fp);
+
+  /* Read the tables  */
+  read_yield_tables(fp);
+
+  /* Set yield_mass_bins array */
+  const float imf_log10_mass_bin_size =
+      (fp->log10_imf_max_mass_msun - fp->log10_imf_min_mass_msun) /
+      (eagle_feedback_N_imf_bins - 1);
+
+  for (int i = 0; i < eagle_feedback_N_imf_bins; i++)
+    fp->yield_mass_bins[i] =
+        imf_log10_mass_bin_size * i + fp->log10_imf_min_mass_msun;
+
+  /* Resample yields from mass bins used in tables to mass bins used in IMF  */
+  compute_yields(fp);
+
+  /* Resample ejecta contribution to enrichment from mass bins used in tables to
+   * mass bins used in IMF  */
+  compute_ejecta(fp);
+
+  message("initialized stellar feedback");
+}
diff --git a/src/feedback/EAGLE/feedback.h b/src/feedback/EAGLE/feedback.h
new file mode 100644
index 0000000000000000000000000000000000000000..5fa32fc2fa8053dbeaa1c1f96b5abb8526942b68
--- /dev/null
+++ b/src/feedback/EAGLE/feedback.h
@@ -0,0 +1,154 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Copyright (c) 2018 Matthieu Schaller (schaller@strw.leidenuniv.nl)
+ *
+ * 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_FEEDBACK_EAGLE_H
+#define SWIFT_FEEDBACK_EAGLE_H
+
+#include "cosmology.h"
+#include "error.h"
+#include "feedback_properties.h"
+#include "hydro_properties.h"
+#include "part.h"
+#include "units.h"
+
+#include <strings.h>
+
+void compute_stellar_evolution(const struct feedback_props* feedback_props,
+                               const struct cosmology* cosmo, struct spart* sp,
+                               const struct unit_system* us, const float age,
+                               const float dt);
+
+/**
+ * @brief Should we do feedback for this star?
+ *
+ * @param sp The star to consider.
+ */
+__attribute__((always_inline)) INLINE static int feedback_do_feedback(
+    const struct spart* sp) {
+
+  return (sp->birth_time != -1.);
+}
+
+/**
+ * @brief Prepares a s-particle for its feedback interactions
+ *
+ * @param sp The particle to act upon
+ */
+__attribute__((always_inline)) INLINE static void feedback_init_spart(
+    struct spart* sp) {
+
+  sp->feedback_data.to_collect.enrichment_weight_inv = 0.f;
+  sp->feedback_data.to_collect.ngb_mass = 0.f;
+}
+
+/**
+ * @brief Prepares a star's feedback field before computing what
+ * needs to be distributed.
+ */
+__attribute__((always_inline)) INLINE static void feedback_reset_feedback(
+    struct spart* sp, const struct feedback_props* feedback_props) {
+
+  /* Zero the distribution weights */
+  sp->feedback_data.to_distribute.enrichment_weight = 0.f;
+
+  /* Zero the amount of mass that is distributed */
+  sp->feedback_data.to_distribute.mass = 0.f;
+
+  /* Zero the metal enrichment quantities */
+  for (int i = 0; i < chemistry_element_count; i++) {
+    sp->feedback_data.to_distribute.metal_mass[i] = 0.f;
+  }
+  sp->feedback_data.to_distribute.total_metal_mass = 0.f;
+  sp->feedback_data.to_distribute.mass_from_AGB = 0.f;
+  sp->feedback_data.to_distribute.metal_mass_from_AGB = 0.f;
+  sp->feedback_data.to_distribute.mass_from_SNII = 0.f;
+  sp->feedback_data.to_distribute.metal_mass_from_SNII = 0.f;
+  sp->feedback_data.to_distribute.mass_from_SNIa = 0.f;
+  sp->feedback_data.to_distribute.metal_mass_from_SNIa = 0.f;
+  sp->feedback_data.to_distribute.Fe_mass_from_SNIa = 0.f;
+
+  /* Zero the energy to inject */
+  sp->feedback_data.to_distribute.energy = 0.f;
+
+  /* Zero the SNII feedback probability */
+  sp->feedback_data.to_distribute.SNII_heating_probability = 0.f;
+
+  /* Zero the SNII feedback energy */
+  sp->feedback_data.to_distribute.SNII_delta_u = 0.f;
+}
+
+/**
+ * @brief Initialises the s-particles feedback props for the first time
+ *
+ * This function is called only once just after the ICs have been
+ * read in to do some conversions.
+ *
+ * @param sp The particle to act upon.
+ * @param feedback_props The properties of the feedback model.
+ */
+__attribute__((always_inline)) INLINE static void feedback_first_init_spart(
+    struct spart* sp, const struct feedback_props* feedback_props) {
+
+  feedback_init_spart(sp);
+}
+
+/**
+ * @brief Initialises the s-particles feedback props for the first time
+ *
+ * This function is called only once just after the ICs have been
+ * read in to do some conversions.
+ *
+ * @param sp The particle to act upon.
+ * @param feedback_props The properties of the feedback model.
+ */
+__attribute__((always_inline)) INLINE static void feedback_prepare_spart(
+    struct spart* sp, const struct feedback_props* feedback_props) {}
+
+/**
+ * @brief Evolve the stellar properties of a #spart.
+ *
+ * This function allows for example to compute the SN rate before sending
+ * this information to a different MPI rank.
+ *
+ * @param sp The particle to act upon
+ * @param feedback_props The #feedback_props structure.
+ * @param cosmo The current cosmological model.
+ * @param us The unit system.
+ * @param star_age_beg_step The age of the star at the star of the time-step in
+ * internal units.
+ * @param dt The time-step size of this star in internal units.
+ */
+__attribute__((always_inline)) INLINE static void feedback_evolve_spart(
+    struct spart* restrict sp, const struct feedback_props* feedback_props,
+    const struct cosmology* cosmo, const struct unit_system* us,
+    const double star_age_beg_step, const double dt) {
+
+#ifdef SWIFT_DEBUG_CHECKS
+  if (sp->birth_time == -1.) error("Evolving a star particle that shoul not!");
+#endif
+
+  /* Compute amount of enrichment and feedback that needs to be done in this
+   * step */
+  compute_stellar_evolution(feedback_props, cosmo, sp, us, star_age_beg_step,
+                            dt);
+
+  /* Decrease star mass by amount of mass distributed to gas neighbours */
+  sp->mass -= sp->feedback_data.to_distribute.mass;
+}
+
+#endif /* SWIFT_FEEDBACK_EAGLE_H */
diff --git a/src/feedback/EAGLE/feedback_iact.h b/src/feedback/EAGLE/feedback_iact.h
new file mode 100644
index 0000000000000000000000000000000000000000..66f8bc47fabc45fb57c6cc4c508e50c0f1e27a06
--- /dev/null
+++ b/src/feedback/EAGLE/feedback_iact.h
@@ -0,0 +1,276 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Coypright (c) 2018 Matthieu Schaller (schaller@strw.leidenuniv.nl)
+ *
+ * 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_EAGLE_FEEDBACK_IACT_H
+#define SWIFT_EAGLE_FEEDBACK_IACT_H
+
+/* Local includes */
+#include "random.h"
+
+/**
+ * @brief Density interaction between two particles (non-symmetric).
+ *
+ * @param r2 Comoving square distance between the two particles.
+ * @param dx Comoving vector separating both particles (pi - pj).
+ * @param hi Comoving smoothing-length of particle i.
+ * @param hj Comoving smoothing-length of particle j.
+ * @param si First sparticle.
+ * @param pj Second particle (not updated).
+ * @param xpj Extra particle data (not updated).
+ * @param cosmo The cosmological model.
+ * @param ti_current Current integer time value
+ */
+__attribute__((always_inline)) INLINE static void
+runner_iact_nonsym_feedback_density(const float r2, const float *dx,
+                                    const float hi, const float hj,
+                                    struct spart *restrict si,
+                                    const struct part *restrict pj,
+                                    const struct xpart *restrict xpj,
+                                    const struct cosmology *restrict cosmo,
+                                    const integertime_t ti_current) {
+
+  /* Get the gas mass. */
+  const float mj = hydro_get_mass(pj);
+
+  /* Get r and 1/r. */
+  const float r_inv = 1.0f / sqrtf(r2);
+  const float r = r2 * r_inv;
+
+  /* Compute the kernel function */
+  const float hi_inv = 1.0f / hi;
+  const float ui = r * hi_inv;
+  float wi;
+  kernel_eval(ui, &wi);
+
+  /* Add mass of pj to neighbour mass of si  */
+  si->feedback_data.to_collect.ngb_mass += mj;
+
+  /* Add contribution of pj to normalisation of density weighted fraction
+   * which determines how much mass to distribute to neighbouring
+   * gas particles */
+
+  const float rho = hydro_get_comoving_density(pj);
+  if (rho != 0.f)
+    si->feedback_data.to_collect.enrichment_weight_inv += wi / rho;
+}
+
+/**
+ * @brief Feedback interaction between two particles (non-symmetric).
+ * Used for updating properties of gas particles neighbouring a star particle
+ *
+ * @param r2 Comoving square distance between the two particles.
+ * @param dx Comoving vector separating both particles (si - pj).
+ * @param hi Comoving smoothing-length of particle i.
+ * @param hj Comoving smoothing-length of particle j.
+ * @param si First (star) particle (not updated).
+ * @param pj Second (gas) particle.
+ * @param xpj Extra particle data
+ * @param cosmo The cosmological model.
+ * @param ti_current Current integer time used value for seeding random number
+ * generator
+ */
+__attribute__((always_inline)) INLINE static void
+runner_iact_nonsym_feedback_apply(const float r2, const float *dx,
+                                  const float hi, const float hj,
+                                  const struct spart *restrict si,
+                                  struct part *restrict pj,
+                                  struct xpart *restrict xpj,
+                                  const struct cosmology *restrict cosmo,
+                                  const integertime_t ti_current) {
+
+  /* Get r and 1/r. */
+  const float r_inv = 1.0f / sqrtf(r2);
+  const float r = r2 * r_inv;
+
+  /* Compute the kernel function */
+  const float hi_inv = 1.0f / hi;
+  const float ui = r * hi_inv;
+  float wi;
+  kernel_eval(ui, &wi);
+
+  /* Gas particle density */
+  const float rho_j = hydro_get_comoving_density(pj);
+
+  /* Compute weighting for distributing feedback quantities */
+  float Omega_frac;
+  if (rho_j != 0.f) {
+    Omega_frac = si->feedback_data.to_distribute.enrichment_weight * wi / rho_j;
+  } else {
+    Omega_frac = 0.f;
+  }
+
+  /* Update particle mass */
+  const double current_mass = hydro_get_mass(pj);
+  const double delta_mass = si->feedback_data.to_distribute.mass * Omega_frac;
+  const double new_mass = current_mass + delta_mass;
+
+  hydro_set_mass(pj, new_mass);
+
+  /* Inverse of the new mass */
+  const double new_mass_inv = 1. / new_mass;
+
+  /* Update total metallicity */
+  const double current_metal_mass_total =
+      pj->chemistry_data.metal_mass_fraction_total * current_mass;
+  const double delta_metal_mass_total =
+      si->feedback_data.to_distribute.total_metal_mass * Omega_frac;
+  const double new_metal_mass_total =
+      current_metal_mass_total + delta_metal_mass_total;
+
+  pj->chemistry_data.metal_mass_fraction_total =
+      new_metal_mass_total * new_mass_inv;
+
+  /* Update mass fraction of each tracked element  */
+  for (int elem = 0; elem < chemistry_element_count; elem++) {
+    const double current_metal_mass =
+        pj->chemistry_data.metal_mass_fraction[elem] * current_mass;
+    const double delta_metal_mass =
+        si->feedback_data.to_distribute.metal_mass[elem] * Omega_frac;
+    const double new_metal_mass = current_metal_mass + delta_metal_mass;
+
+    pj->chemistry_data.metal_mass_fraction[elem] =
+        new_metal_mass * new_mass_inv;
+  }
+
+  /* Update iron mass fraction from SNIa  */
+  const double current_iron_from_SNIa_mass =
+      pj->chemistry_data.iron_mass_fraction_from_SNIa * current_mass;
+  const double delta_iron_from_SNIa_mass =
+      si->feedback_data.to_distribute.Fe_mass_from_SNIa * Omega_frac;
+  const double new_iron_from_SNIa_mass =
+      current_iron_from_SNIa_mass + delta_iron_from_SNIa_mass;
+
+  pj->chemistry_data.iron_mass_fraction_from_SNIa =
+      new_iron_from_SNIa_mass * new_mass_inv;
+
+  /* Update mass fraction from SNIa  */
+  const double current_mass_from_SNIa =
+      pj->chemistry_data.mass_from_SNIa * current_mass;
+  const double delta_mass_from_SNIa =
+      si->feedback_data.to_distribute.mass_from_SNIa * Omega_frac;
+  const double new_mass_from_SNIa =
+      current_mass_from_SNIa + delta_mass_from_SNIa;
+
+  pj->chemistry_data.mass_from_SNIa = new_mass_from_SNIa * new_mass_inv;
+
+  /* Update metal mass fraction from SNIa */
+  const double current_metal_mass_from_SNIa =
+      pj->chemistry_data.metal_mass_fraction_from_SNIa * current_mass;
+  const double delta_metal_mass_from_SNIa =
+      si->feedback_data.to_distribute.metal_mass_from_SNIa * Omega_frac;
+  const double new_metal_mass_from_SNIa =
+      current_metal_mass_from_SNIa + delta_metal_mass_from_SNIa;
+
+  pj->chemistry_data.metal_mass_fraction_from_SNIa =
+      new_metal_mass_from_SNIa * new_mass_inv;
+
+  /* Update mass fraction from SNII  */
+  const double current_mass_from_SNII =
+      pj->chemistry_data.mass_from_SNII * current_mass;
+  const double delta_mass_from_SNII =
+      si->feedback_data.to_distribute.mass_from_SNII * Omega_frac;
+  const double new_mass_from_SNII =
+      current_mass_from_SNII + delta_mass_from_SNII;
+
+  pj->chemistry_data.mass_from_SNII = new_mass_from_SNII * new_mass_inv;
+
+  /* Update metal mass fraction from SNII */
+  const double current_metal_mass_from_SNII =
+      pj->chemistry_data.metal_mass_fraction_from_SNII * current_mass;
+  const double delta_metal_mass_from_SNII =
+      si->feedback_data.to_distribute.metal_mass_from_SNII * Omega_frac;
+  const double new_metal_mass_from_SNII =
+      current_metal_mass_from_SNII + delta_metal_mass_from_SNII;
+
+  pj->chemistry_data.metal_mass_fraction_from_SNII =
+      new_metal_mass_from_SNII * new_mass_inv;
+
+  /* Update mass fraction from AGB  */
+  const double current_mass_from_AGB =
+      pj->chemistry_data.mass_from_AGB * current_mass;
+  const double delta_mass_from_AGB =
+      si->feedback_data.to_distribute.mass_from_AGB * Omega_frac;
+  const double new_mass_from_AGB = current_mass_from_AGB + delta_mass_from_AGB;
+
+  pj->chemistry_data.mass_from_AGB = new_mass_from_AGB * new_mass_inv;
+
+  /* Update metal mass fraction from AGB */
+  const double current_metal_mass_from_AGB =
+      pj->chemistry_data.metal_mass_fraction_from_AGB * current_mass;
+  const double delta_metal_mass_from_AGB =
+      si->feedback_data.to_distribute.metal_mass_from_AGB * Omega_frac;
+  const double new_metal_mass_from_AGB =
+      current_metal_mass_from_AGB + delta_metal_mass_from_AGB;
+
+  pj->chemistry_data.metal_mass_fraction_from_AGB =
+      new_metal_mass_from_AGB * new_mass_inv;
+
+  /* Update velocity following injection of momentum */
+  const double delta_m = si->feedback_data.to_distribute.mass * Omega_frac;
+  xpj->v_full[0] += delta_m * si->v[0] * new_mass_inv;
+  xpj->v_full[1] += delta_m * si->v[1] * new_mass_inv;
+  xpj->v_full[2] += delta_m * si->v[2] * new_mass_inv;
+
+  /* /\* Compute how much energy to inject *\/ */
+  /* const double v2 = xpj->v_full[0] * xpj->v_full[0] + */
+  /*                   xpj->v_full[1] * xpj->v_full[1] + */
+  /*                   xpj->v_full[2] * xpj->v_full[2]; */
+  /* const double kinetic_energy_gas = 0.5 * cosmo->a2_inv * new_mass * v2; */
+  /* const double total_energy = */
+  /*     si->feedback_data.to_distribute.energy * Omega_frac; */
+  /* const double thermal_energy = total_energy - kinetic_energy_gas; */
+  /* const double delta_u_enrich = thermal_energy / new_mass; */
+
+  /* /\* Energy feedback (ejecta energy + SNIa)*\/ */
+  /* const double u_init_enrich = */
+  /*     hydro_get_physical_internal_energy(pj, xpj, cosmo); */
+
+  /* const double u_new_enrich = u_init_enrich + max(delta_u_enrich, 0.); */
+  /* hydro_set_physical_internal_energy(pj, xpj, cosmo, u_new_enrich); */
+  /* hydro_set_drifted_physical_internal_energy(pj, cosmo, u_new_enrich); */
+
+  /* Get the SNII feedback properties */
+  const float prob = si->feedback_data.to_distribute.SNII_heating_probability;
+
+  /* Are we doing some SNII (big boys) feedback? */
+  if (prob > 0.f) {
+
+    /* Draw a random number (Note mixing both IDs) */
+    const float rand = random_unit_interval(si->id + pj->id, ti_current,
+                                            random_number_stellar_feedback);
+    /* Are we lucky? */
+    if (rand < prob) {
+
+      /* Compute new energy of this particle */
+      const double u_init = hydro_get_physical_internal_energy(pj, xpj, cosmo);
+      const float delta_u = si->feedback_data.to_distribute.SNII_delta_u;
+      const double u_new = u_init + delta_u;
+
+      /* Inject energy into the particle */
+      hydro_set_physical_internal_energy(pj, xpj, cosmo, u_new);
+      hydro_set_drifted_physical_internal_energy(pj, cosmo, u_new);
+
+      /* message( */
+      /*     "We did some heating! id %llu star id %llu probability %.5e " */
+      /*     "random_num %.5e du %.5e du/ini %.5e", */
+      /*     pj->id, si->id, prob, rand, delta_u, delta_u / u_init); */
+    }
+  }
+}
+
+#endif /* SWIFT_EAGLE_FEEDBACK_IACT_H */
diff --git a/src/feedback/EAGLE/feedback_properties.h b/src/feedback/EAGLE/feedback_properties.h
new file mode 100644
index 0000000000000000000000000000000000000000..69aee1124c88ccb21a37d22dea5b720a3af8d0aa
--- /dev/null
+++ b/src/feedback/EAGLE/feedback_properties.h
@@ -0,0 +1,241 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Coypright (c) 2018 Matthieu Schaller (schaller@strw.leidenuniv.nl)
+ *
+ * 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_EAGLE_FEEDBACK_PROPERTIES_H
+#define SWIFT_EAGLE_FEEDBACK_PROPERTIES_H
+
+#include "chemistry.h"
+#include "hydro_properties.h"
+
+/**
+ * @brief Stores AGB and SNII yield tables
+ */
+struct yield_table {
+
+  /* Yield table mass bins */
+  double *mass;
+
+  /* Yield table metallicity bins */
+  double *metallicity;
+
+  /* Array to store yield table resampled by IMF mass bins */
+  double *yield_IMF_resampled;
+
+  /* Array to store yield table being read in */
+  double *yield;
+
+  /* Array to store table of ejecta resampled by IMF mass bins */
+  double *ejecta_IMF_resampled;
+
+  /* Array to store table of ejecta being read in */
+  double *ejecta;
+
+  /* Array to store table of total mass released resampled by IMF mass bins */
+  double *total_metals_IMF_resampled;
+
+  /* Array to store table of total mass released being read in */
+  double *total_metals;
+};
+
+/**
+ * @brief Stores tables to determine stellar lifetimes. Used for calculation of
+ * IMF
+ */
+struct lifetime_table {
+
+  /* table of masses */
+  double *mass;
+
+  /* table of metallicities */
+  double *metallicity;
+
+  /* table of lifetimes depending on mass an metallicity */
+  double **dyingtime;
+};
+
+/**
+ * @brief Properties of the EAGLE feedback model.
+ */
+struct feedback_props {
+
+  /* ------------ Main operation modes ------------- */
+
+  /*! Are we doing SNe feedback? */
+  int with_SNe_feedback;
+
+  /*! Are we doing AGB enrichment? */
+  int with_AGB_enrichment;
+
+  /*! Are we doing SNII enrichment? */
+  int with_SNII_enrichment;
+
+  /*! Are we doing SNIa enrichment? */
+  int with_SNIa_enrichment;
+
+  /* ------------ Yield tables    ----------------- */
+
+  /* Yield tables for AGB and SNII  */
+  struct yield_table yield_AGB;
+  struct yield_table yield_SNII;
+
+  /* Arrays of yield tables for SNIa */
+  double *yield_SNIa_IMF_resampled;
+  double yield_SNIa_total_metals_IMF_resampled;
+  double *yields_SNIa;
+
+  /* Arrays for names of elements being tracked for each enrichment channel */
+  char **SNIa_element_names;
+  char **SNII_element_names;
+  char **AGB_element_names;
+
+  /* Array of mass bins for yield calculations */
+  double *yield_mass_bins;
+
+  /* Location of yield tables */
+  char yield_table_path[200];
+
+  /* ------------- Lifetime tracks   --------------- */
+
+  /* Table of lifetime values */
+  struct lifetime_table lifetimes;
+
+  /* ------------- SNII parameters    --------------- */
+
+  /* Array of adjustment factors for SNII  */
+  float SNII_yield_factor[chemistry_element_count];
+
+  /* ------------- SNIa parameters    --------------- */
+
+  /*! Efficiency of the SNIa model */
+  float SNIa_efficiency;
+
+  /*! Time-scale of the SNIa decay function in Giga-years */
+  float SNIa_timescale_Gyr;
+
+  /*! Inverse of time-scale of the SNIa decay function in Giga-years */
+  float SNIa_timescale_Gyr_inv;
+
+  /*! Log 10 of the maximal mass used for SNIa feedback (in solar masses) */
+  float log10_SNIa_max_mass_msun;
+
+  /*! Energy released by one supernova type II in cgs units */
+  double E_SNIa_cgs;
+
+  /*! Energy released by one supernova type II in internal units */
+  float E_SNIa;
+
+  /* ------------- AGB parameters    ---------------- */
+
+  /*! Specific kinetic energy injected from AGB ejectas (in internal units). */
+  float AGB_ejecta_specific_kinetic_energy;
+
+  /* ------------- Conversion factors --------------- */
+
+  /*! Conversion factor from internal mass unit to solar mass */
+  double mass_to_solar_mass;
+
+  /*! Conversion factor from internal mass unit to solar mass */
+  double solar_mass_to_mass;
+
+  /*! Conversion factor from density in internal units to Hydrogen number
+   * density in cgs */
+  double rho_to_n_cgs;
+
+  /*! Conversion factor from temperature to internal energy */
+  float temp_to_u_factor;
+
+  /* ------------- Parameters for IMF --------------- */
+
+  /*! Array to store calculated IMF */
+  float *imf;
+
+  /*! Arrays to store IMF mass bins */
+  float *imf_mass_bin;
+
+  /*! Arrays to store IMF mass bins (log10)*/
+  float *imf_mass_bin_log10;
+
+  /*! Minimal stellar mass considered by the IMF (in solar masses) */
+  float imf_min_mass_msun;
+
+  /*! Maximal stellar mass considered by the IMF (in solar masses) */
+  float imf_max_mass_msun;
+
+  /*! Log 10 of the minimal stellar mass considered by the IMF (in solar masses)
+   */
+  float log10_imf_min_mass_msun;
+
+  /*! Log 10 of the maximal stellar mass considered by the IMF (in solar masses)
+   */
+  float log10_imf_max_mass_msun;
+
+  /* ------------ SNe feedback properties ------------ */
+
+  /*! Log 10 of the minimal stellar mass considered for SNII feedback (in solar
+   * masses) */
+  float log10_SNII_min_mass_msun;
+
+  /*! Log 10 of the maximal stellar mass considered for SNII feedback (in solar
+   * masses) */
+  float log10_SNII_max_mass_msun;
+
+  /*! Number of type II supernovae per solar mass */
+  float num_SNII_per_msun;
+
+  /*! Wind delay time for SNII */
+  float SNII_wind_delay;
+
+  /*! Temperature increase induced by SNe feedback */
+  float SNe_deltaT_desired;
+
+  /*! Energy released by one supernova type II in cgs units */
+  double E_SNII_cgs;
+
+  /*! Energy released by one supernova type II in internal units */
+  float E_SNII;
+
+  /*! Minimal energy fraction for supernova type II feedback */
+  double f_E_min;
+
+  /*! Maximal energy fraction for supernova type II feedback */
+  double f_E_max;
+
+  /*! Pivot point for the metallicity dependance of the feedback energy fraction
+   * model */
+  double Z_0;
+
+  /*! Pivot point for the density dependance of the feedback energy fraction
+   * model */
+  double n_0_cgs;
+
+  /*! Slope of the density dependance of the feedback energy fraction model */
+  double n_n;
+
+  /*! Slope of the metallicity dependance of the feedback energy fraction model
+   */
+  double n_Z;
+};
+
+void feedback_props_init(struct feedback_props *fp,
+                         const struct phys_const *phys_const,
+                         const struct unit_system *us,
+                         struct swift_params *params,
+                         const struct hydro_props *hydro_props,
+                         const struct cosmology *cosmo);
+
+#endif /* SWIFT_EAGLE_FEEDBACK_PROPERTIES_H */
diff --git a/src/feedback/EAGLE/feedback_struct.h b/src/feedback/EAGLE/feedback_struct.h
new file mode 100644
index 0000000000000000000000000000000000000000..3c69e8b11a36fc5bbb763270f865b82ea51dc58d
--- /dev/null
+++ b/src/feedback/EAGLE/feedback_struct.h
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Copyright (c) 2018 Matthieu Schaller (schaller@strw.leidenuniv.nl)
+ *
+ * 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_FEEDBACK_STRUCT_EAGLE_H
+#define SWIFT_FEEDBACK_STRUCT_EAGLE_H
+
+#include "chemistry_struct.h"
+
+/**
+ * @brief Feedback fields carried by each star particles
+ */
+struct feedback_spart_data {
+
+  union {
+
+    /**
+     * @brief Values collected from the gas neighbours.
+     */
+    struct {
+
+      /*! Inverse of normalisation factor used for the enrichment */
+      float enrichment_weight_inv;
+
+      /*! Total mass (unweighted) of neighbouring gas particles */
+      float ngb_mass;
+
+    } to_collect;
+
+    /**
+     * @brief Values to be distributed to the gas neighbours.
+     */
+    struct {
+
+      /*! Normalisation factor used for the enrichment */
+      float enrichment_weight;
+
+      /*! Mass released */
+      float mass;
+
+      /*! Total metal mass released */
+      float total_metal_mass;
+
+      /*! Total mass released by each element */
+      float metal_mass[chemistry_element_count];
+
+      /*! Total mass released due to SNIa */
+      float mass_from_SNIa;
+
+      /*! Total metal mass released due to SNIa */
+      float metal_mass_from_SNIa;
+
+      /*! Total iron mass released due to SNIa */
+      float Fe_mass_from_SNIa;
+
+      /*! Total mass released due to SNII */
+      float mass_from_SNII;
+
+      /*! Total metal mass released due to SNII */
+      float metal_mass_from_SNII;
+
+      /*! Total mass released due to AGB */
+      float mass_from_AGB;
+
+      /*! Total metal mass released due to AGB */
+      float metal_mass_from_AGB;
+
+      /*! Energy change due to thermal and kinetic energy of ejecta */
+      float energy;
+
+      /*! Probability to heating neighbouring gas particle for SNII feedback */
+      float SNII_heating_probability;
+
+      /*! Change in energy from SNII feedback energy injection */
+      float SNII_delta_u;
+
+    } to_distribute;
+  };
+};
+
+#endif /* SWIFT_FEEDBACK_STRUCT_EAGLE_H */
diff --git a/src/feedback/EAGLE/imf.h b/src/feedback/EAGLE/imf.h
new file mode 100644
index 0000000000000000000000000000000000000000..5510c95ca197170c01b24fbe10539d1c7010541f
--- /dev/null
+++ b/src/feedback/EAGLE/imf.h
@@ -0,0 +1,478 @@
+/*******************************************************************************
+ * 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_EAGLE_STARS_IMF_H
+#define SWIFT_EAGLE_STARS_IMF_H
+
+/* Some standard headers. */
+#include <string.h>
+
+/* Local includes. */
+#include "inline.h"
+#include "interpolate.h"
+#include "minmax.h"
+#include "yield_tables.h"
+
+/**
+ * @brief the different weightings allowed for the IMF integration
+ */
+enum eagle_imf_integration_type {
+  eagle_imf_integration_no_weight,   /*<! No weighting */
+  eagle_imf_integration_mass_weight, /*<! Weighted by mass */
+  eagle_imf_integration_yield_weight /*<! Weigthed by stellar yields */
+} __attribute__((packed));
+
+/**
+ * @brief determine which IMF mass bins the upper and lower input mass bounds
+ * belong to
+ *
+ * @param log10_min_mass Lower mass bound
+ * @param log10_max_mass Upper mass bound
+ * @param i_min (return) Index of IMF mass bin containing log10_min_mass
+ * @param i_max (return) Index of IMF mass bin containing log10_max_mass
+ * @param feedback_props the #feedback_props data struct
+ */
+INLINE static void determine_imf_bins(
+    double log10_min_mass, double log10_max_mass, int *i_min, int *i_max,
+    const struct feedback_props *feedback_props) {
+
+#ifdef SWIFT_DEBUG_CHECKS
+  if (log10_min_mass > log10_max_mass)
+    error("Lower bound higher than larger bound.");
+#endif
+
+  const int N_bins = eagle_feedback_N_imf_bins;
+  const float *imf_bins_log10 = feedback_props->imf_mass_bin_log10;
+
+  /* Check whether lower mass is within the IMF mass bin range */
+  log10_min_mass = max(log10_min_mass, imf_bins_log10[0]);
+  log10_min_mass = min(log10_min_mass, imf_bins_log10[N_bins - 1]);
+
+  /* Check whether upper mass is within the IMF mass bin range */
+  log10_max_mass = max(log10_max_mass, imf_bins_log10[0]);
+  log10_max_mass = min(log10_max_mass, imf_bins_log10[N_bins - 1]);
+
+  *i_min = 0;
+  while ((*i_min < N_bins - 2) && imf_bins_log10[*i_min + 1] < log10_min_mass) {
+    (*i_min)++;
+  }
+
+  *i_max = 1;
+  while ((*i_max < N_bins - 1) && imf_bins_log10[*i_max] < log10_max_mass) {
+    (*i_max)++;
+  }
+}
+
+/**
+ * @brief Integrate the IMF between a minimum and maximum mass using the
+ * trapezoidal rule. The IMF may be weighted by various quantities, as specified
+ * by the variable, mode, including an input array, stellar_yields.
+ *
+ * @param log10_min_mass log10 mass lower integration bound
+ * @param log10_max_mass log10 mass upper integration bound
+ * @param mode Type of weighting for the IMF integration.
+ * @param stellar_yields Array of weights based on yields. Used only for
+ * yield-weighted integration.
+ * @param feedback_props the #feedback_props data structure
+ */
+INLINE static float integrate_imf(const float log10_min_mass,
+                                  const float log10_max_mass,
+                                  const enum eagle_imf_integration_type mode,
+                                  const float *stellar_yields,
+                                  const struct feedback_props *feedback_props) {
+
+  /* Pull out some common terms */
+  const float *imf = feedback_props->imf;
+  const float *imf_mass_bin = feedback_props->imf_mass_bin;
+  const float *imf_mass_bin_log10 = feedback_props->imf_mass_bin_log10;
+
+  /* IMF mass bin spacing in log10 space. Assumes uniform spacing. */
+  const float imf_log10_mass_bin_size =
+      imf_mass_bin_log10[1] - imf_mass_bin_log10[0];
+
+  /* Determine bins to integrate over based on integration bounds */
+  int i_min, i_max;
+  determine_imf_bins(log10_min_mass, log10_max_mass, &i_min, &i_max,
+                     feedback_props);
+
+  /* Array for the integrand */
+  float integrand[eagle_feedback_N_imf_bins];
+
+  /* Add up the contribution from each of the IMF mass bins */
+  switch (mode) {
+
+    case eagle_imf_integration_no_weight:
+
+      /* Integrate IMF on its own */
+      for (int i = i_min; i < i_max + 1; i++) {
+        integrand[i] = imf[i] * imf_mass_bin[i];
+      }
+      break;
+
+    case eagle_imf_integration_mass_weight:
+
+      /* Integrate IMF weighted by mass */
+      for (int i = i_min; i < i_max + 1; i++) {
+        integrand[i] = imf[i] * imf_mass_bin[i] * imf_mass_bin[i];
+      }
+      break;
+
+    case eagle_imf_integration_yield_weight:
+
+#ifdef SWIFT_DEBUG_CHECKS
+      if (stellar_yields == NULL)
+        error(
+            "Yield array not passed in despite asking for yield-weighted IMf "
+            "integration.");
+#endif
+
+      /* Integrate IMF weighted by yields */
+      for (int i = i_min; i < i_max + 1; i++) {
+        integrand[i] = stellar_yields[i] * imf[i] * imf_mass_bin[i];
+      }
+      break;
+
+    default:
+      error("Invalid mode for IMF integration");
+  }
+
+  /* Integrate using trapezoidal rule */
+  float result = 0.f;
+  for (int i = i_min; i < i_max + 1; i++) {
+    result += integrand[i];
+  }
+
+  /* Update end bins since contribution was overcounted when summing up all
+   * entries */
+  result -= 0.5 * (integrand[i_min] + integrand[i_max]);
+
+  /* Correct first bin */
+  const float first_bin_offset =
+      (log10_min_mass - imf_mass_bin_log10[i_min]) / imf_log10_mass_bin_size;
+
+  if (first_bin_offset < 0.5f) {
+    result -= first_bin_offset * integrand[i_min];
+  } else {
+    result -= 0.5f * integrand[i_min];
+    result -= (first_bin_offset - 0.5f) * integrand[i_min + 1];
+  }
+
+  /* Correct last bin */
+  const float last_bin_offset =
+      (log10_max_mass - imf_mass_bin_log10[i_max - 1]) /
+      imf_log10_mass_bin_size;
+
+  if (last_bin_offset < 0.5) {
+    result -= 0.5f * integrand[i_max];
+    result -= (0.5f - last_bin_offset) * integrand[i_max - 1];
+  } else {
+    result -= (1.f - last_bin_offset) * integrand[i_max];
+  }
+
+  /* The IMF is tabulated in log10, multiply by log10(mass bin size) to get
+   * result of integrating IMF */
+  return result * imf_log10_mass_bin_size * ((float)M_LN10);
+}
+
+/**
+ * @brief Allocate space for IMF table and compute values to populate this
+ * table.
+ *
+ * @param feedback_props #feedback_props data structure
+ */
+INLINE static void init_imf(struct feedback_props *feedback_props) {
+
+  /* Compute size of mass bins in log10 space */
+  const double imf_log10_mass_bin_size =
+      (feedback_props->log10_imf_max_mass_msun -
+       feedback_props->log10_imf_min_mass_msun) /
+      (double)(eagle_feedback_N_imf_bins - 1);
+
+  /* Allocate IMF array */
+  if (swift_memalign("imf-tables", (void **)&feedback_props->imf,
+                     SWIFT_STRUCT_ALIGNMENT,
+                     eagle_feedback_N_imf_bins * sizeof(float)) != 0)
+    error("Failed to allocate IMF bins table");
+
+  /* Allocate array to store IMF mass bins */
+  if (swift_memalign("imf-tables", (void **)&feedback_props->imf_mass_bin,
+                     SWIFT_STRUCT_ALIGNMENT,
+                     eagle_feedback_N_imf_bins * sizeof(float)) != 0)
+    error("Failed to allocate IMF bins table");
+
+  /* Allocate array to store IMF mass bins in log10 space */
+  if (swift_memalign("imf-tables", (void **)&feedback_props->imf_mass_bin_log10,
+                     SWIFT_STRUCT_ALIGNMENT,
+                     eagle_feedback_N_imf_bins * sizeof(float)) != 0)
+    error("Failed to allocate IMF bins table");
+
+  /* Set IMF from Chabrier 2003, PASP, 115, 763
+   * Eq. 17 with values from table 1 */
+  for (int i = 0; i < eagle_feedback_N_imf_bins; i++) {
+
+    /* Logarithmically-spaced bins in units of solar masses */
+    const double log10_mass_msun =
+        feedback_props->log10_imf_min_mass_msun + i * imf_log10_mass_bin_size;
+
+    const double mass_msun = exp10(log10_mass_msun);
+
+    feedback_props->imf_mass_bin[i] = mass_msun;
+    feedback_props->imf_mass_bin_log10[i] = log10_mass_msun;
+
+    if (mass_msun > 1.0) {
+
+      /* High-mass end */
+      feedback_props->imf[i] = 0.237912 * pow(mass_msun, -2.3);
+    } else {
+
+      /* Low-mass end */
+      feedback_props->imf[i] =
+          0.852464 *
+          exp((log10_mass_msun - log10(0.079)) *
+              (log10_mass_msun - log10(0.079)) / (-2.0 * 0.69 * 0.69)) /
+          mass_msun;
+    }
+  }
+
+  /* Normalize the IMF */
+  const float norm = integrate_imf(feedback_props->log10_imf_min_mass_msun,
+                                   feedback_props->log10_imf_max_mass_msun,
+                                   eagle_imf_integration_mass_weight,
+                                   /*(stellar_yields=)*/ NULL, feedback_props);
+
+  for (int i = 0; i < eagle_feedback_N_imf_bins; i++)
+    feedback_props->imf[i] /= norm;
+}
+
+/**
+ * @brief Calculate mass (in solar masses) of stars that died from the star
+ * particle's birth up to its current age (in Gyr).
+ *
+ * Calculation uses the tables of Portinari et al. 1998, A&A, 334, 505
+ *
+ * @param age_Gyr age of star in Gyr.
+ * @param Z Star's metallicity (metal mass fraction).
+ * @param feedback_props the #feedback_props data structure.
+ * @return Mass of stars died up to that age in solar masses.
+ */
+INLINE static float dying_mass_msun(
+    const float age_Gyr, const float Z,
+    const struct feedback_props *feedback_props) {
+
+  // MATTHIEU check this!!!
+
+  /* Pull out some common terms */
+  const double *lifetime_Z = feedback_props->lifetimes.metallicity;
+  const double *lifetime_m = feedback_props->lifetimes.mass;
+  double **const dying_times = feedback_props->lifetimes.dyingtime;
+  const int n_Z = eagle_feedback_lifetime_N_metals;
+  const int n_m = eagle_feedback_lifetime_N_masses;
+
+  /* Early abort? */
+  if (age_Gyr <= 0.f) {
+    return feedback_props->imf_max_mass_msun;
+  }
+
+  const float log10_age_yr = log10f(age_Gyr * 1e9f);
+
+  /* Calculate index along the metallicity axis */
+  int Z_index;
+  float Z_offset;
+  if (Z <= lifetime_Z[0]) {
+
+    /* Before start of the table */
+    Z_index = 0;
+    Z_offset = 0.f;
+
+  } else if (Z >= lifetime_Z[n_Z - 1]) {
+
+    /* After end of the table */
+    Z_index = n_Z - 2;
+    Z_offset = 1.f;
+
+  } else {
+
+    /* Normal case: Somewhere inside the table */
+    for (Z_index = 0; Z_index < n_Z - 1; Z_index++) {
+      if (lifetime_Z[Z_index + 1] > Z) break;
+    }
+
+    Z_offset = (Z - lifetime_Z[Z_index]) /
+               (lifetime_Z[Z_index + 1] - lifetime_Z[Z_index]);
+  }
+
+  /* Check whether we are not beyond the table */
+  int time_index_lowZ = -1;
+  float time_offset_lowZ = 0.f;
+  if (log10_age_yr >= dying_times[Z_index][0]) {
+
+    /* Before start of the table */
+    time_index_lowZ = 0;
+    time_offset_lowZ = 0.f;
+
+  } else if (log10_age_yr <= dying_times[Z_index][n_m - 1]) {
+
+    /* After end of the table */
+    time_index_lowZ = n_m - 2;
+    time_offset_lowZ = 1.0;
+  }
+
+  /* Check whether we are not beyond the table */
+  int time_index_highZ = -1;
+  float time_offset_highZ = 0.f;
+  if (log10_age_yr >= dying_times[Z_index + 1][0]) {
+
+    /* Before start of the table */
+    time_index_highZ = 0;
+    time_offset_highZ = 0.f;
+
+  } else if (log10_age_yr <= dying_times[Z_index + 1][n_m - 1]) {
+
+    /* After end of the table */
+    time_index_highZ = n_m - 2;
+    time_offset_highZ = 1.0;
+  }
+
+  /* Search the table starting from the largest times until we reach
+     a solution for the two bounds */
+  int i = n_m;
+  while (i >= 0 && (time_index_lowZ == -1 || time_index_highZ == -1)) {
+
+    i--;
+
+    if (dying_times[Z_index][i] >= log10_age_yr && time_index_lowZ == -1) {
+
+      /* record index */
+      time_index_lowZ = i;
+
+      /* record distance from table element */
+      time_offset_lowZ =
+          (log10_age_yr - dying_times[Z_index][time_index_lowZ]) /
+          (dying_times[Z_index][time_index_lowZ + 1] -
+           dying_times[Z_index][time_index_lowZ]);
+    }
+
+    if (dying_times[Z_index + 1][i] >= log10_age_yr && time_index_highZ == -1) {
+
+      /* record index */
+      time_index_highZ = i;
+
+      /* record distance from table element */
+      time_offset_highZ =
+          (log10_age_yr - dying_times[Z_index + 1][time_index_highZ]) /
+          (dying_times[Z_index + 1][time_index_highZ + 1] -
+           dying_times[Z_index + 1][time_index_highZ]);
+    }
+  }
+
+  /* And now interpolate the solution */
+  const float mass_low_Z =
+      interpolate_1d(lifetime_m, time_index_lowZ, time_offset_lowZ);
+  const float mass_high_Z =
+      interpolate_1d(lifetime_m, time_index_highZ, time_offset_highZ);
+
+  float mass = (1.f - Z_offset) * mass_low_Z + Z_offset * mass_high_Z;
+
+  /* Check that we haven't killed too many stars */
+  mass = min(mass, feedback_props->imf_max_mass_msun);
+
+  return mass;
+}
+
+/**
+ * @brief Calculate lifetime of stellar population in Gyr for a given mass.
+ *
+ * Calculation uses the tables of Portinari et al. 1998, A&A, 334, 505
+ *
+ * @param mass in solar masses.
+ * @param Z Metallicity (metal mass fraction).
+ * @param feedback_props the #feedback_props data structure.
+ * @return The life time in Giga-years.
+ */
+INLINE static float lifetime_in_Gyr(
+    const float mass, const float Z,
+    const struct feedback_props *feedback_props) {
+
+  /* Pull out some common terms */
+  const double *lifetime_Z = feedback_props->lifetimes.metallicity;
+  const double *lifetime_m = feedback_props->lifetimes.mass;
+  double **const dying_times = feedback_props->lifetimes.dyingtime;
+  const int n_Z = eagle_feedback_lifetime_N_metals;
+  const int n_m = eagle_feedback_lifetime_N_masses;
+
+  /* Calculate index along the mass axis */
+  int m_index;
+  float m_offset;
+  if (mass <= lifetime_m[0]) {
+
+    /* Before start of the table */
+    m_index = 0;
+    m_offset = 0.f;
+
+  } else if (mass >= lifetime_m[n_m - 1]) {
+
+    /* After end of the table */
+    m_index = n_m - 2;
+    m_offset = 1.f;
+
+  } else {
+
+    /* Normal case: Somewhere inside the table */
+    for (m_index = 0; m_index < n_m - 1; m_index++)
+      if (lifetime_m[m_index + 1] > mass) break;
+
+    m_offset = (mass - lifetime_m[m_index]) /
+               (lifetime_m[m_index + 1] - lifetime_m[m_index]);
+  }
+
+  /* Calculate index along the metallicity axis */
+  int Z_index;
+  float Z_offset;
+  if (Z <= lifetime_Z[0]) {
+
+    /* Before start of the table */
+    Z_index = 0;
+    Z_offset = 0.f;
+
+  } else if (Z >= lifetime_Z[n_Z - 1]) {
+
+    /* After end of the table */
+    Z_index = n_Z - 2;
+    Z_offset = 1.f;
+
+  } else {
+
+    for (Z_index = 0; Z_index < n_Z - 1; Z_index++)
+      if (lifetime_Z[Z_index + 1] > Z) break;
+
+    /* Normal case: Somewhere inside the table */
+    Z_offset = (Z - lifetime_Z[Z_index]) /
+               (lifetime_Z[Z_index + 1] - lifetime_Z[Z_index]);
+  }
+
+  /* Interpolation of the table to get the time */
+  const float log_time_years =
+      interpolate_2d(dying_times, Z_index, m_index, Z_offset, m_offset);
+
+  /* Convert to Giga-years */
+  const float time_Gyr = exp10f(log_time_years - 9.f);
+
+  return time_Gyr;
+}
+
+#endif
diff --git a/src/feedback/EAGLE/interpolate.h b/src/feedback/EAGLE/interpolate.h
new file mode 100644
index 0000000000000000000000000000000000000000..2da39c3d200694f9f60fd57904e5254838cb4863
--- /dev/null
+++ b/src/feedback/EAGLE/interpolate.h
@@ -0,0 +1,140 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Coypright (c) 2018 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_EAGLE_FEEDBACK_INTERPOLATE_H
+#define SWIFT_EAGLE_FEEDBACK_INTERPOLATE_H
+
+/* Local includes. */
+#include "error.h"
+#include "inline.h"
+
+/**
+ * @brief Returns the 1d index of element with 2d indices i,j
+ * from a flattened 2d array in row major order
+ *
+ * @param i, j Indices of element of interest
+ * @param Nx, Ny Sizes of array dimensions
+ */
+__attribute__((always_inline)) static INLINE int row_major_index_2d(
+    const int i, const int j, const int Nx, const int Ny) {
+#ifdef SWIFT_DEBUG_CHECKS
+  assert(i < Nx);
+  assert(j < Ny);
+#endif
+
+  return i * Ny + j;
+}
+
+/**
+ * @brief Returns the 1d index of element with 3d indices i,j,k
+ * from a flattened 3d array in row major order
+ *
+ * @param i, j, k Indices of element of interest
+ * @param Nx, Ny, Nz Sizes of array dimensions
+ */
+__attribute__((always_inline)) static INLINE int row_major_index_3d(
+    const int i, const int j, const int k, const int Nx, const int Ny,
+    const int Nz) {
+
+#ifdef SWIFT_DEBUG_CHECKS
+  assert(i < Nx);
+  assert(j < Ny);
+  assert(k < Nz);
+#endif
+
+  return i * Ny * Nz + j * Nz + k;
+}
+
+/**
+ * @brief linear interpolation of 1d table at bin i with offset dx
+ *
+ * @param table array to interpolate
+ * @param i index of cell to interpolate
+ * @param dx offset within cell to interpolate
+ */
+__attribute__((always_inline)) static INLINE double interpolate_1d(
+    const double* table, const int i, const float dx) {
+
+  const float tx = 1.f - dx;
+
+  return tx * table[i] + dx * table[i + 1];
+}
+
+/**
+ * @brief linear interpolation of 2d table at bin i,j with offset dx, dy
+ *
+ * @param table array to interpolate
+ * @param i row index of cell to interpolate
+ * @param j column index of cell to interpolate
+ * @param dx row offset within cell to interpolate
+ * @param dy column offset within cell to interpolate
+ */
+__attribute__((always_inline)) static INLINE double interpolate_2d(
+    double** table, const int i, const int j, const float dx, const float dy) {
+  const float tx = 1.f - dx;
+  const float ty = 1.f - dy;
+
+  double result = tx * ty * table[i][j];
+  result += tx * dy * table[i][j + 1];
+  result += dx * ty * table[i + 1][j];
+  result += dx * dy * table[i + 1][j + 1];
+
+  return result;
+}
+
+/**
+ * @brief linear interpolation of non-uniformly spaced 1d array, array_y, whose
+ * positions are specified in array_x. The function takes an input value in the
+ * range of array_x and returns a value interpolated from array_y with the same
+ * offset in the corresponding bin.
+ *
+ * @param array_x array of values indicating positions of the array to be
+ * interpolated
+ * @param array_y array to interpolate
+ * @param size length of array_x and array_y
+ * @param x value within range of array_x indicating bin and offset within
+ * array_y to interpolate
+ */
+static INLINE double interpolate_1D_non_uniform(const double* array_x,
+                                                const double* array_y,
+                                                const int size,
+                                                const double x) {
+#ifdef SWIFT_DEBUG_CHECKS
+
+  /* Check that x within range of array_x */
+  if (x < array_x[0])
+    error("interpolating value less than array min. value %.5e array min %.5e",
+          x, array_x[0]);
+  if (x > array_x[size - 1])
+    error(
+        "interpolating value greater than array max. value %.5e array max %.5e",
+        x, array_x[size - 1]);
+#endif
+
+  /* Find bin index and offset of x within array_x */
+  int index = 0;
+  while (array_x[index] <= x) index++;
+
+  const double offset =
+      (array_x[index] - x) / (array_x[index] - array_x[index - 1]);
+
+  /* Interpolate array_y */
+  return offset * array_y[index - 1] + (1. - offset) * array_y[index];
+}
+
+#endif /* SWIFT_EAGLE_FEEDBACK_INTERPOLATE_H */
diff --git a/src/feedback/EAGLE/yield_tables.h b/src/feedback/EAGLE/yield_tables.h
new file mode 100644
index 0000000000000000000000000000000000000000..435826f7f94559f094e5e27be31a3ef32d064de1
--- /dev/null
+++ b/src/feedback/EAGLE/yield_tables.h
@@ -0,0 +1,883 @@
+/*******************************************************************************
+ * 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_EAGLE_FEEDBACK_YIELD_TABLES_H
+#define SWIFT_EAGLE_FEEDBACK_YIELD_TABLES_H
+
+/* Local includes. */
+#include "chemistry.h"
+#include "inline.h"
+
+static const float log10_min_metallicity = -20;
+
+/*! Length of the name fields in the yields tables */
+#define eagle_feedback_element_name_length 15
+
+/*! Number of bins used to define the IMF */
+#define eagle_feedback_N_imf_bins 200
+
+/*! Number of elements considered for the SNIa yields */
+#define eagle_feedback_SNIa_N_elements 42
+
+/*! Number of elements considered for the SNII yields */
+#define eagle_feedback_SNII_N_elements 11
+
+/*! Number of mass bins considered for the SNII yields */
+#define eagle_feedback_SNII_N_masses 11
+
+/*! Number of metallicity bins considered for the SNII yields */
+#define eagle_feedback_SNII_N_metals 5
+
+/*! Number of elements considered for the AGB yields */
+#define eagle_feedback_AGB_N_elements 11
+
+/*! Number of mass bins considered for the AGB yields */
+#define eagle_feedback_AGB_N_masses 23
+
+/*! Number of metallicity bins considered for the AGB yields */
+#define eagle_feedback_AGB_N_metals 3
+
+/*! Number od mass bins along the mass axis of the lifetime table */
+#define eagle_feedback_lifetime_N_masses 30
+
+/*! Number od mass bins along the metal axis of the lifetime table */
+#define eagle_feedback_lifetime_N_metals 6
+
+/**
+ * @brief returns index of element_name within array of element names
+ * (element_array)
+ *
+ * @param element_name name of element
+ * @param element_array array of element names
+ * @param n_elements size of element_array
+ */
+INLINE static int get_element_index(const char *element_name,
+                                    char **element_array, int n_elements) {
+
+  /* Compare element name we are trying to index to names in element_array */
+  for (int i = 0; i < n_elements; i++) {
+    if (strcmp(element_array[i], element_name) == 0) return i;
+  }
+
+  /* If we don't find the index return flag  */
+  return -1;
+}
+
+/**
+ * @brief reads yield tables, flattens and stores them in stars_props data
+ * struct
+ *
+ * @param feedback_props the #feedback_props data struct to read the table into.
+ */
+INLINE static void read_yield_tables(struct feedback_props *feedback_props) {
+
+#ifdef HAVE_HDF5
+
+  /* filenames to read HDF5 files */
+  char fname[256], setname[100];
+
+  hid_t file_id, dataset, datatype;
+  herr_t status;
+
+  /* Open SNIa tables for reading */
+  sprintf(fname, "%s/SNIa.hdf5", feedback_props->yield_table_path);
+  file_id = H5Fopen(fname, H5F_ACC_RDONLY, H5P_DEFAULT);
+  if (file_id < 0) error("unable to open file %s\n", fname);
+
+  /* read element name array */
+  datatype = H5Tcopy(H5T_C_S1);
+  H5Tset_size(datatype, H5T_VARIABLE);
+  dataset = H5Dopen(file_id, "Species_names", H5P_DEFAULT);
+  status = H5Dread(dataset, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT,
+                   feedback_props->SNIa_element_names);
+  if (status < 0) error("error reading SNIa element names");
+  status = H5Dclose(dataset);
+  if (status < 0) error("error closing dataset");
+  status = H5Tclose(datatype);
+  if (status < 0) error("error closing datatype");
+
+  /* read SNIa yields */
+  dataset = H5Dopen(file_id, "Yield", H5P_DEFAULT);
+  status = H5Dread(dataset, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT,
+                   feedback_props->yields_SNIa);
+  if (status < 0) error("error reading SNIa yields");
+  status = H5Dclose(dataset);
+  if (status < 0) error("error closing dataset");
+
+  /* read SNIa total metals released */
+  dataset = H5Dopen(file_id, "Total_Metals", H5P_DEFAULT);
+  status = H5Dread(dataset, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT,
+                   &feedback_props->yield_SNIa_total_metals_IMF_resampled);
+  if (status < 0) error("error reading SNIa total metal");
+  status = H5Dclose(dataset);
+  if (status < 0) error("error closing dataset");
+
+  status = H5Fclose(file_id);
+  if (status < 0) error("error closing SNIa file");
+
+  /* Open SNII tables for reading */
+  sprintf(fname, "%s/SNII.hdf5", feedback_props->yield_table_path);
+  file_id = H5Fopen(fname, H5F_ACC_RDONLY, H5P_DEFAULT);
+  if (file_id < 0) error("unable to open file %s\n", fname);
+
+  /* read element name array */
+  datatype = H5Tcopy(H5T_C_S1);
+  H5Tset_size(datatype, H5T_VARIABLE);
+  dataset = H5Dopen(file_id, "Species_names", H5P_DEFAULT);
+  status = H5Dread(dataset, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT,
+                   feedback_props->SNII_element_names);
+  if (status < 0) error("error reading SNII element names");
+  status = H5Dclose(dataset);
+  if (status < 0) error("error closing dataset");
+  status = H5Tclose(datatype);
+  if (status < 0) error("error closing datatype");
+
+  /* read array of masses */
+  dataset = H5Dopen(file_id, "Masses", H5P_DEFAULT);
+  status = H5Dread(dataset, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT,
+                   feedback_props->yield_SNII.mass);
+  if (status < 0) error("error reading SNII masses");
+  status = H5Dclose(dataset);
+  if (status < 0) error("error closing dataset");
+
+  /* read array of metallicities */
+  dataset = H5Dopen(file_id, "Metallicities", H5P_DEFAULT);
+  status = H5Dread(dataset, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT,
+                   feedback_props->yield_SNII.metallicity);
+  if (status < 0) error("error reading SNII metallicities");
+  status = H5Dclose(dataset);
+  if (status < 0) error("error closing dataset");
+
+  /* declare temporary arrays to read data from HDF5 files */
+  double temp_yield_SNII[eagle_feedback_SNII_N_elements]
+                        [eagle_feedback_SNII_N_masses];
+  double temp_ejecta_SNII[eagle_feedback_SNII_N_masses],
+      tempmet1[eagle_feedback_SNII_N_masses];
+  char *metallicity_yield_table_name_SNII[eagle_feedback_SNII_N_metals];
+
+  /* read metallicity names */
+  datatype = H5Tcopy(H5T_C_S1);
+  H5Tset_size(datatype, H5T_VARIABLE);
+  dataset = H5Dopen(file_id, "Yield_names", H5P_DEFAULT);
+  status = H5Dread(dataset, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT,
+                   metallicity_yield_table_name_SNII);
+  if (status < 0) error("error reading yield table names");
+  status = H5Dclose(dataset);
+  if (status < 0) error("error closing dataset");
+  status = H5Tclose(datatype);
+  if (status < 0) error("error closing datatype");
+
+  /* read SNII yield tables */
+  for (int i = 0; i < eagle_feedback_SNII_N_metals; i++) {
+
+    /* read yields to temporary array */
+    sprintf(setname, "/Yields/%s/Yield", metallicity_yield_table_name_SNII[i]);
+    dataset = H5Dopen(file_id, setname, H5P_DEFAULT);
+    status = H5Dread(dataset, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT,
+                     temp_yield_SNII);
+    if (status < 0) error("error reading SNII yield");
+    status = H5Dclose(dataset);
+    if (status < 0) error("error closing dataset");
+
+    /* read mass ejected table to temporary array */
+    sprintf(setname, "/Yields/%s/Ejected_mass",
+            metallicity_yield_table_name_SNII[i]);
+    dataset = H5Dopen(file_id, setname, H5P_DEFAULT);
+    status = H5Dread(dataset, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT,
+                     temp_ejecta_SNII);
+    if (status < 0) error("error reading SNII ejected masses");
+    status = H5Dclose(dataset);
+    if (status < 0) error("error closing dataset");
+
+    /* read total metals table to temporary array */
+    sprintf(setname, "/Yields/%s/Total_Metals",
+            metallicity_yield_table_name_SNII[i]);
+    dataset = H5Dopen(file_id, setname, H5P_DEFAULT);
+    status = H5Dread(dataset, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT,
+                     tempmet1);
+    if (status < 0) error("error reading SNII total metals");
+    status = H5Dclose(dataset);
+    if (status < 0) error("error closing dataset");
+
+    /* Flatten the temporary tables that were read, store in stars_props */
+    for (int k = 0; k < eagle_feedback_SNII_N_masses; k++) {
+      const int flat_index = row_major_index_2d(
+          i, k, eagle_feedback_SNII_N_metals, eagle_feedback_SNII_N_masses);
+
+      feedback_props->yield_SNII.ejecta[flat_index] = temp_ejecta_SNII[k];
+      feedback_props->yield_SNII.total_metals[flat_index] = tempmet1[k];
+
+      for (int j = 0; j < eagle_feedback_SNII_N_elements; j++) {
+
+        const int flat_index_Z = row_major_index_3d(
+            i, j, k, eagle_feedback_SNII_N_metals,
+            eagle_feedback_SNII_N_elements, eagle_feedback_SNII_N_masses);
+
+        feedback_props->yield_SNII.yield[flat_index_Z] = temp_yield_SNII[j][k];
+      }
+    }
+  }
+
+  status = H5Fclose(file_id);
+  if (status < 0) error("error closing file");
+
+  /* Read AGB tables */
+  sprintf(fname, "%s/AGB.hdf5", feedback_props->yield_table_path);
+  file_id = H5Fopen(fname, H5F_ACC_RDONLY, H5P_DEFAULT);
+  if (file_id < 0) error("unable to open file %s\n", fname);
+
+  /* read element name array */
+  datatype = H5Tcopy(H5T_C_S1);
+  H5Tset_size(datatype, H5T_VARIABLE);
+  dataset = H5Dopen(file_id, "Species_names", H5P_DEFAULT);
+  status = H5Dread(dataset, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT,
+                   feedback_props->AGB_element_names);
+  if (status < 0) error("error reading AGB element names");
+  status = H5Dclose(dataset);
+  if (status < 0) error("error closing dataset");
+  status = H5Tclose(datatype);
+  if (status < 0) error("error closing datatype");
+
+  /* read array of masses */
+  dataset = H5Dopen(file_id, "Masses", H5P_DEFAULT);
+  status = H5Dread(dataset, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT,
+                   feedback_props->yield_AGB.mass);
+  if (status < 0) error("error reading AGB masses");
+  status = H5Dclose(dataset);
+  if (status < 0) error("error closing dataset");
+
+  /* read array of metallicities */
+  dataset = H5Dopen(file_id, "Metallicities", H5P_DEFAULT);
+  status = H5Dread(dataset, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT,
+                   feedback_props->yield_AGB.metallicity);
+  if (status < 0) error("error reading AGB metallicities");
+  status = H5Dclose(dataset);
+  if (status < 0) error("error closing dataset");
+
+  /* declare temporary arrays to read data from HDF5 files */
+  double temp_yield_AGB[eagle_feedback_AGB_N_elements]
+                       [eagle_feedback_AGB_N_masses];
+  double temp_ejecta_AGB[eagle_feedback_AGB_N_masses],
+      tempmet2[eagle_feedback_AGB_N_masses];
+  char *metallicity_yield_table_name_AGB[eagle_feedback_AGB_N_metals];
+
+  /* read metallicity names */
+  datatype = H5Tcopy(H5T_C_S1);
+  H5Tset_size(datatype, H5T_VARIABLE);
+  dataset = H5Dopen(file_id, "Yield_names", H5P_DEFAULT);
+  status = H5Dread(dataset, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT,
+                   metallicity_yield_table_name_AGB);
+  if (status < 0) error("error reading yield table names");
+  status = H5Dclose(dataset);
+  if (status < 0) error("error closing dataset");
+  status = H5Tclose(datatype);
+  if (status < 0) error("error closing datatype");
+
+  /* read AGB yield tables */
+  for (int i = 0; i < eagle_feedback_AGB_N_metals; i++) {
+    /* read yields to temporary array */
+    sprintf(setname, "/Yields/%s/Yield", metallicity_yield_table_name_AGB[i]);
+    dataset = H5Dopen(file_id, setname, H5P_DEFAULT);
+    status = H5Dread(dataset, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT,
+                     temp_yield_AGB);
+    if (status < 0) error("error reading AGB yield");
+    status = H5Dclose(dataset);
+    if (status < 0) error("error closing dataset");
+
+    /* read mass ejected table to temporary array */
+    sprintf(setname, "/Yields/%s/Ejected_mass",
+            metallicity_yield_table_name_AGB[i]);
+    dataset = H5Dopen(file_id, setname, H5P_DEFAULT);
+    status = H5Dread(dataset, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT,
+                     temp_ejecta_AGB);
+    if (status < 0) error("error reading AGB ejected masses");
+    status = H5Dclose(dataset);
+    if (status < 0) error("error closing dataset");
+
+    /* read total metals table to temporary array */
+    sprintf(setname, "/Yields/%s/Total_Metals",
+            metallicity_yield_table_name_AGB[i]);
+    dataset = H5Dopen(file_id, setname, H5P_DEFAULT);
+    status = H5Dread(dataset, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT,
+                     tempmet2);
+    if (status < 0) error("error reading AGB total metals");
+    status = H5Dclose(dataset);
+    if (status < 0) error("error closing dataset");
+
+    /* Flatten the temporary tables that were read, store in stars_props */
+    for (int k = 0; k < eagle_feedback_AGB_N_masses; k++) {
+
+      const int flat_index = row_major_index_2d(
+          i, k, eagle_feedback_AGB_N_metals, eagle_feedback_AGB_N_masses);
+
+      feedback_props->yield_AGB.ejecta[flat_index] = temp_ejecta_AGB[k];
+      feedback_props->yield_AGB.total_metals[flat_index] = tempmet2[k];
+
+      for (int j = 0; j < eagle_feedback_AGB_N_elements; j++) {
+        const int flat_index_Z = row_major_index_3d(
+            i, j, k, eagle_feedback_AGB_N_metals, eagle_feedback_AGB_N_elements,
+            eagle_feedback_AGB_N_masses);
+
+        feedback_props->yield_AGB.yield[flat_index_Z] = temp_yield_AGB[j][k];
+      }
+    }
+  }
+
+  status = H5Fclose(file_id);
+  if (status < 0) error("error closing file");
+
+  /* open lifetimes table */
+  sprintf(fname, "%s/Lifetimes.hdf5", feedback_props->yield_table_path);
+  file_id = H5Fopen(fname, H5F_ACC_RDONLY, H5P_DEFAULT);
+  if (file_id < 0) error("unable to open file %s\n", fname);
+
+  /* read lifetimes mass bins */
+  dataset = H5Dopen(file_id, "Masses", H5P_DEFAULT);
+  status = H5Dread(dataset, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT,
+                   feedback_props->lifetimes.mass);
+  if (status < 0) error("error reading lifetime table masses");
+  status = H5Dclose(dataset);
+  if (status < 0) error("error closing dataset");
+
+  /* read metallicity bins */
+  dataset = H5Dopen(file_id, "Metallicities", H5P_DEFAULT);
+  status = H5Dread(dataset, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT,
+                   feedback_props->lifetimes.metallicity);
+  if (status < 0) error("error reading lifetimes metallicities");
+  status = H5Dclose(dataset);
+  if (status < 0) error("error closing dataset");
+
+  /* allocate temporary array to read lifetimes */
+  double temp_lifetimes[eagle_feedback_lifetime_N_metals]
+                       [eagle_feedback_lifetime_N_masses];
+
+  dataset = H5Dopen(file_id, "Lifetimes", H5P_DEFAULT);
+  H5Dread(dataset, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT,
+          temp_lifetimes);
+  H5Dclose(dataset);
+
+  for (int i = 0; i < eagle_feedback_lifetime_N_metals; i++) {
+    for (int j = 0; j < eagle_feedback_lifetime_N_masses; j++) {
+      feedback_props->lifetimes.dyingtime[i][j] = log10(temp_lifetimes[i][j]);
+    }
+  }
+
+  H5Fclose(file_id);
+
+#endif
+}
+
+/**
+ * @brief allocates space for the yield tables
+ *
+ * @param feedback_props the #feedback_props data struct to store the tables in
+ */
+INLINE static void allocate_yield_tables(
+    struct feedback_props *feedback_props) {
+
+  /* Allocate array to store SNIa yield tables */
+  if (swift_memalign("feedback-tables", (void **)&feedback_props->yields_SNIa,
+                     SWIFT_STRUCT_ALIGNMENT,
+                     eagle_feedback_SNIa_N_elements * sizeof(double)) != 0) {
+    error("Failed to allocate SNIa yields array");
+  }
+
+  /* Allocate array to store SNIa yield table resampled by IMF mass bins */
+  if (swift_memalign("feedback-tables",
+                     (void **)&feedback_props->yield_SNIa_IMF_resampled,
+                     SWIFT_STRUCT_ALIGNMENT,
+                     eagle_feedback_SNIa_N_elements * sizeof(double)) != 0) {
+    error("Failed to allocate SNIa IMF resampled yields array");
+  }
+
+  /* Allocate array for AGB mass bins */
+  if (swift_memalign("feedback-tables",
+                     (void **)&feedback_props->yield_AGB.mass,
+                     SWIFT_STRUCT_ALIGNMENT,
+                     eagle_feedback_AGB_N_masses * sizeof(double)) != 0) {
+    error("Failed to allocate AGB mass array");
+  }
+
+  /* Allocate array for AGB metallicity bins */
+  if (swift_memalign("feedback-tables",
+                     (void **)&feedback_props->yield_AGB.metallicity,
+                     SWIFT_STRUCT_ALIGNMENT,
+                     eagle_feedback_AGB_N_metals * sizeof(double)) != 0) {
+    error("Failed to allocate AGB metallicity array");
+  }
+
+  /* Allocate array to store AGB yield tables */
+  if (swift_memalign("feedback-tables",
+                     (void **)&feedback_props->yield_AGB.yield,
+                     SWIFT_STRUCT_ALIGNMENT,
+                     eagle_feedback_AGB_N_metals * eagle_feedback_AGB_N_masses *
+                         eagle_feedback_AGB_N_elements * sizeof(double)) != 0) {
+    error("Failed to allocate AGB yield array");
+  }
+
+  /* Allocate array to store AGB yield table resampled by IMF mass bins */
+  if (swift_memalign("feedback-tables",
+                     (void **)&feedback_props->yield_AGB.yield_IMF_resampled,
+                     SWIFT_STRUCT_ALIGNMENT,
+                     eagle_feedback_AGB_N_metals * eagle_feedback_N_imf_bins *
+                         chemistry_element_count * sizeof(double)) != 0) {
+    error("Failed to allocate AGB IMF resampled array");
+  }
+
+  /* Allocate array to store AGB ejecta tables */
+  if (swift_memalign("feedback-tables",
+                     (void **)&feedback_props->yield_AGB.ejecta,
+                     SWIFT_STRUCT_ALIGNMENT,
+                     eagle_feedback_AGB_N_metals * eagle_feedback_AGB_N_masses *
+                         sizeof(double)) != 0) {
+    error("Failed to allocate AGB ejecta array");
+  }
+
+  /* Allocate array to store AGB ejecta table resampled by IMF mass bins */
+  if (swift_memalign("feedback-tables",
+                     (void **)&feedback_props->yield_AGB.ejecta_IMF_resampled,
+                     SWIFT_STRUCT_ALIGNMENT,
+                     eagle_feedback_AGB_N_metals * eagle_feedback_N_imf_bins *
+                         sizeof(double)) != 0) {
+    error("Failed to allocate AGB ejecta IMF resampled array");
+  }
+
+  /* Allocate array to store table of total metals released by AGB */
+  if (swift_memalign("feedback-tables",
+                     (void **)&feedback_props->yield_AGB.total_metals,
+                     SWIFT_STRUCT_ALIGNMENT,
+                     eagle_feedback_AGB_N_metals * eagle_feedback_AGB_N_masses *
+                         sizeof(double)) != 0) {
+    error("Failed to allocate AGB total metals array");
+  }
+
+  /* Allocate array to store table of total metals released by AGB resampled by
+   * IMF mass bins */
+  if (swift_memalign(
+          "feedback-tables",
+          (void **)&feedback_props->yield_AGB.total_metals_IMF_resampled,
+          SWIFT_STRUCT_ALIGNMENT,
+          eagle_feedback_AGB_N_metals * eagle_feedback_N_imf_bins *
+              sizeof(double)) != 0) {
+    error("Failed to allocate AGB total metals IMF resampled array");
+  }
+
+  /* Allocate array for SNII mass bins */
+  if (swift_memalign("feedback-tables",
+                     (void **)&feedback_props->yield_SNII.mass,
+                     SWIFT_STRUCT_ALIGNMENT,
+                     eagle_feedback_SNII_N_masses * sizeof(double)) != 0) {
+    error("Failed to allocate SNII mass array");
+  }
+
+  /* Allocate array for SNII metallicity bins */
+  if (swift_memalign("feedback-tables",
+                     (void **)&feedback_props->yield_SNII.metallicity,
+                     SWIFT_STRUCT_ALIGNMENT,
+                     eagle_feedback_SNII_N_metals * sizeof(double)) != 0) {
+    error("Failed to allocate SNII metallicity array");
+  }
+
+  /* Allocate array to store SNII yield tables */
+  if (swift_memalign(
+          "feedback-tables", (void **)&feedback_props->yield_SNII.yield,
+          SWIFT_STRUCT_ALIGNMENT,
+          eagle_feedback_SNII_N_metals * eagle_feedback_SNII_N_masses *
+              eagle_feedback_SNII_N_elements * sizeof(double)) != 0) {
+    error("Failed to allocate SNII yield array");
+  }
+
+  /* Allocate array to store SNII yield table resampled by IMF mass bins */
+  if (swift_memalign("feedback-tables",
+                     (void **)&feedback_props->yield_SNII.yield_IMF_resampled,
+                     SWIFT_STRUCT_ALIGNMENT,
+                     eagle_feedback_SNII_N_metals * eagle_feedback_N_imf_bins *
+                         chemistry_element_count * sizeof(double)) != 0) {
+    error("Failed to allocate SNII IMF resampled array");
+  }
+
+  /* Allocate array to store SNII ejecta tables */
+  if (swift_memalign("feedback-tables",
+                     (void **)&feedback_props->yield_SNII.ejecta,
+                     SWIFT_STRUCT_ALIGNMENT,
+                     eagle_feedback_SNII_N_metals *
+                         eagle_feedback_SNII_N_masses * sizeof(double)) != 0) {
+    error("Failed to allocate SNII ejecta array");
+  }
+
+  /* Allocate array to store SNII ejecta table resampled by IMF mass bins */
+  if (swift_memalign("feedback-tables",
+                     (void **)&feedback_props->yield_SNII.ejecta_IMF_resampled,
+                     SWIFT_STRUCT_ALIGNMENT,
+                     eagle_feedback_SNII_N_metals * eagle_feedback_N_imf_bins *
+                         sizeof(double)) != 0) {
+    error("Failed to allocate SNII ejecta IMF resampled array");
+  }
+
+  /* Allocate array to store table of total metals released by SNII */
+  if (swift_memalign("feedback-tables",
+                     (void **)&feedback_props->yield_SNII.total_metals,
+                     SWIFT_STRUCT_ALIGNMENT,
+                     eagle_feedback_SNII_N_metals *
+                         eagle_feedback_SNII_N_masses * sizeof(double)) != 0) {
+    error("Failed to allocate SNII total metals array");
+  }
+
+  /* Allocate array to store table of total metals released by SNII resampled by
+   * IMF mass bins */
+  if (swift_memalign(
+          "feedback-tables",
+          (void **)&feedback_props->yield_SNII.total_metals_IMF_resampled,
+          SWIFT_STRUCT_ALIGNMENT,
+          eagle_feedback_SNII_N_metals * eagle_feedback_N_imf_bins *
+              sizeof(double)) != 0) {
+    error("Failed to allocate SNII total metals IMF resampled array");
+  }
+
+  /* Allocate array for lifetimes mass bins */
+  if (swift_memalign("feedback-tables",
+                     (void **)&feedback_props->lifetimes.mass,
+                     SWIFT_STRUCT_ALIGNMENT,
+                     eagle_feedback_lifetime_N_masses * sizeof(double)) != 0) {
+    error("Failed to allocate lifetime mass array");
+  }
+
+  /* Allocate array for lifetimes metallicity bins */
+  if (swift_memalign("feedback-tables",
+                     (void **)&feedback_props->lifetimes.metallicity,
+                     SWIFT_STRUCT_ALIGNMENT,
+                     eagle_feedback_lifetime_N_metals * sizeof(double)) != 0) {
+    error("Failed to allocate lifetime metallicity array");
+  }
+
+  /* Allocate lifetimes array */
+  feedback_props->lifetimes.dyingtime =
+      (double **)malloc(eagle_feedback_lifetime_N_metals * sizeof(double *));
+  for (int i = 0; i < eagle_feedback_lifetime_N_metals; i++) {
+    feedback_props->lifetimes.dyingtime[i] =
+        (double *)malloc(eagle_feedback_lifetime_N_masses * sizeof(double));
+  }
+
+  /* Allocate arrays to store names of elements tracked for SNIa, SNII, AGB  */
+  feedback_props->SNIa_element_names =
+      (char **)malloc(eagle_feedback_SNIa_N_elements * sizeof(char *));
+  for (int i = 0; i < eagle_feedback_SNIa_N_elements; i++) {
+    feedback_props->SNIa_element_names[i] =
+        (char *)malloc(eagle_feedback_element_name_length * sizeof(char));
+  }
+  feedback_props->SNII_element_names =
+      (char **)malloc(eagle_feedback_SNII_N_elements * sizeof(char *));
+  for (int i = 0; i < eagle_feedback_SNII_N_elements; i++) {
+    feedback_props->SNII_element_names[i] =
+        (char *)malloc(eagle_feedback_element_name_length * sizeof(char));
+  }
+  feedback_props->AGB_element_names =
+      (char **)malloc(eagle_feedback_AGB_N_elements * sizeof(char *));
+  for (int i = 0; i < eagle_feedback_AGB_N_elements; i++) {
+    feedback_props->AGB_element_names[i] =
+        (char *)malloc(eagle_feedback_element_name_length * sizeof(char));
+  }
+
+  /* Allocate array of IMF mass bins */
+  if (swift_memalign("feedback-tables",
+                     (void **)&feedback_props->yield_mass_bins,
+                     SWIFT_STRUCT_ALIGNMENT,
+                     eagle_feedback_N_imf_bins * sizeof(double)) != 0) {
+    error("Failed to allocate imf mass bins array");
+  }
+}
+
+/**
+ * @brief resamples yields based on IMF mass bins
+ *
+ * @param feedback_props the #feedback_props data struct.
+ */
+INLINE static void compute_yields(struct feedback_props *feedback_props) {
+
+  int flat_index_3d, flat_index_2d;
+
+  /* convert SNII tables to log10  */
+  for (int i = 0; i < eagle_feedback_SNII_N_masses; i++) {
+    feedback_props->yield_SNII.mass[i] =
+        log10(feedback_props->yield_SNII.mass[i]);
+  }
+  for (int i = 0; i < eagle_feedback_SNII_N_metals; i++) {
+    if (feedback_props->yield_SNII.metallicity[i] > 0) {
+      feedback_props->yield_SNII.metallicity[i] =
+          log10(feedback_props->yield_SNII.metallicity[i]);
+    } else {
+      feedback_props->yield_SNII.metallicity[i] = log10_min_metallicity;
+    }
+  }
+
+  /* convert AGB tables to log10  */
+  for (int i = 0; i < eagle_feedback_AGB_N_masses; i++) {
+    feedback_props->yield_AGB.mass[i] =
+        log10(feedback_props->yield_AGB.mass[i]);
+  }
+  for (int i = 0; i < eagle_feedback_AGB_N_metals; i++) {
+    if (feedback_props->yield_AGB.metallicity[i] > 0) {
+      feedback_props->yield_AGB.metallicity[i] =
+          log10(feedback_props->yield_AGB.metallicity[i]);
+    } else {
+      feedback_props->yield_AGB.metallicity[i] = log10_min_metallicity;
+    }
+  }
+
+  /* Declare temporary tables to accumulate yields */
+  double SNII_yield[eagle_feedback_SNII_N_masses];
+  double AGB_yield[eagle_feedback_AGB_N_masses];
+  float result;
+
+  /* Resample yields for each element tracked in EAGLE */
+  int element_index = 0;
+  for (enum chemistry_element elem = chemistry_element_H;
+       elem < chemistry_element_count; elem++) {
+    /* SNIa  */
+    element_index = get_element_index(chemistry_get_element_name(elem),
+                                      feedback_props->SNIa_element_names,
+                                      eagle_feedback_SNIa_N_elements);
+    feedback_props->yield_SNIa_IMF_resampled[elem] =
+        feedback_props->yields_SNIa[element_index];
+
+    /* SNII  */
+    element_index = get_element_index(chemistry_get_element_name(elem),
+                                      feedback_props->SNII_element_names,
+                                      eagle_feedback_SNII_N_elements);
+    for (int i = 0; i < eagle_feedback_SNII_N_metals; i++) {
+      for (int j = 0; j < eagle_feedback_SNII_N_masses; j++) {
+        flat_index_3d = row_major_index_3d(
+            i, element_index, j, eagle_feedback_SNII_N_metals,
+            eagle_feedback_SNII_N_elements, eagle_feedback_SNII_N_masses);
+        SNII_yield[j] = feedback_props->yield_SNII.yield[flat_index_3d] *
+                        exp(M_LN10 * (-feedback_props->yield_SNII.mass[j]));
+      }
+
+      for (int k = 0; k < eagle_feedback_N_imf_bins; k++) {
+        if (feedback_props->yield_mass_bins[k] <
+            feedback_props->yield_SNII.mass[0])
+          result = SNII_yield[0];
+        else if (feedback_props->yield_mass_bins[k] >
+                 feedback_props->yield_SNII
+                     .mass[eagle_feedback_SNII_N_masses - 1])
+          result = SNII_yield[eagle_feedback_SNII_N_masses - 1];
+        else {
+          result = interpolate_1D_non_uniform(
+              feedback_props->yield_SNII.mass, SNII_yield,
+              eagle_feedback_SNII_N_masses, feedback_props->yield_mass_bins[k]);
+        }
+
+        flat_index_3d = row_major_index_3d(
+            i, elem, k, eagle_feedback_SNII_N_metals, chemistry_element_count,
+            eagle_feedback_N_imf_bins);
+        feedback_props->yield_SNII.yield_IMF_resampled[flat_index_3d] =
+            exp(M_LN10 * feedback_props->yield_mass_bins[k]) * result;
+      }
+    }
+
+    for (int i = 0; i < eagle_feedback_SNII_N_metals; i++) {
+      for (int k = 0; k < eagle_feedback_N_imf_bins; k++) {
+        flat_index_2d = row_major_index_2d(i, k, eagle_feedback_SNII_N_metals,
+                                           eagle_feedback_N_imf_bins);
+        flat_index_3d = row_major_index_3d(
+            i, elem, k, eagle_feedback_SNII_N_metals, chemistry_element_count,
+            eagle_feedback_N_imf_bins);
+        if (strcmp(chemistry_get_element_name(elem), "Hydrogen") != 0 ||
+            strcmp(chemistry_get_element_name(elem), "Helium") != 0) {
+          feedback_props->yield_SNII
+              .total_metals_IMF_resampled[flat_index_2d] +=
+              (feedback_props->SNII_yield_factor[elem] - 1) *
+              feedback_props->yield_SNII.yield_IMF_resampled[flat_index_3d];
+        }
+
+        feedback_props->yield_SNII.yield_IMF_resampled[flat_index_3d] *=
+            feedback_props->SNII_yield_factor[elem];
+      }
+    }
+
+    /* AGB  */
+    element_index = get_element_index(chemistry_get_element_name(elem),
+                                      feedback_props->AGB_element_names,
+                                      eagle_feedback_AGB_N_elements);
+
+    if (element_index < 0) {
+      error("element not tracked for AGB");
+    } else {
+      for (int i = 0; i < eagle_feedback_AGB_N_metals; i++) {
+        for (int j = 0; j < eagle_feedback_AGB_N_masses; j++) {
+          flat_index_3d = row_major_index_3d(
+              i, element_index, j, eagle_feedback_AGB_N_metals,
+              eagle_feedback_AGB_N_elements, eagle_feedback_AGB_N_masses);
+          AGB_yield[j] = feedback_props->yield_AGB.yield[flat_index_3d] *
+                         exp(M_LN10 * (-feedback_props->yield_AGB.mass[j]));
+        }
+
+        for (int j = 0; j < eagle_feedback_N_imf_bins; j++) {
+          if (feedback_props->yield_mass_bins[j] <
+              feedback_props->yield_AGB.mass[0])
+            result = AGB_yield[0];
+          else if (feedback_props->yield_mass_bins[j] >
+                   feedback_props->yield_AGB
+                       .mass[eagle_feedback_AGB_N_masses - 1])
+            result = AGB_yield[eagle_feedback_AGB_N_masses - 1];
+          else
+            result = interpolate_1D_non_uniform(
+                feedback_props->yield_AGB.mass, AGB_yield,
+                eagle_feedback_AGB_N_masses,
+                feedback_props->yield_mass_bins[j]);
+
+          flat_index_3d = row_major_index_3d(
+              i, elem, j, eagle_feedback_AGB_N_metals, chemistry_element_count,
+              eagle_feedback_N_imf_bins);
+          feedback_props->yield_AGB.yield_IMF_resampled[flat_index_3d] =
+              exp(M_LN10 * feedback_props->yield_mass_bins[j]) * result;
+        }
+      }
+    }
+  }
+}
+
+/**
+ * @brief resamples ejecta based on IMF mass bins
+ *
+ * @param feedback_props the #feedback_props data struct.
+ */
+INLINE static void compute_ejecta(struct feedback_props *feedback_props) {
+
+  /* Declare temporary tables to accumulate yields */
+  double SNII_ejecta[eagle_feedback_SNII_N_masses];
+  double AGB_ejecta[eagle_feedback_AGB_N_masses];
+  float result;
+
+  int flat_index;
+
+  /* Resample SNII ejecta */
+  for (int i = 0; i < eagle_feedback_SNII_N_metals; i++) {
+    for (int k = 0; k < eagle_feedback_SNII_N_masses; k++) {
+      flat_index = row_major_index_2d(i, k, eagle_feedback_SNII_N_metals,
+                                      eagle_feedback_SNII_N_masses);
+      SNII_ejecta[k] = feedback_props->yield_SNII.ejecta[flat_index] *
+                       exp(M_LN10 * (-feedback_props->yield_SNII.mass[k]));
+    }
+
+    for (int k = 0; k < eagle_feedback_N_imf_bins; k++) {
+      if (feedback_props->yield_mass_bins[k] <
+          feedback_props->yield_SNII.mass[0])
+        result = SNII_ejecta[0];
+      else if (feedback_props->yield_mass_bins[k] >
+               feedback_props->yield_SNII
+                   .mass[eagle_feedback_SNII_N_masses - 1])
+        result = SNII_ejecta[eagle_feedback_SNII_N_masses - 1];
+      else
+        result = interpolate_1D_non_uniform(
+            feedback_props->yield_SNII.mass, SNII_ejecta,
+            eagle_feedback_SNII_N_masses, feedback_props->yield_mass_bins[k]);
+
+      flat_index = row_major_index_2d(i, k, eagle_feedback_SNII_N_metals,
+                                      eagle_feedback_N_imf_bins);
+      feedback_props->yield_SNII.ejecta_IMF_resampled[flat_index] =
+          exp(M_LN10 * feedback_props->yield_mass_bins[k]) * result;
+    }
+  }
+
+  /* resample SNII total metals released */
+  for (int i = 0; i < eagle_feedback_SNII_N_metals; i++) {
+    for (int k = 0; k < eagle_feedback_SNII_N_masses; k++) {
+      flat_index = row_major_index_2d(i, k, eagle_feedback_SNII_N_metals,
+                                      eagle_feedback_SNII_N_masses);
+      SNII_ejecta[k] = feedback_props->yield_SNII.total_metals[flat_index] *
+                       exp(M_LN10 * (-feedback_props->yield_SNII.mass[k]));
+    }
+
+    for (int k = 0; k < eagle_feedback_N_imf_bins; k++) {
+      if (feedback_props->yield_mass_bins[k] <
+          feedback_props->yield_SNII.mass[0])
+        result = SNII_ejecta[0];
+      else if (feedback_props->yield_mass_bins[k] >
+               feedback_props->yield_SNII
+                   .mass[eagle_feedback_SNII_N_masses - 1])
+        result = SNII_ejecta[eagle_feedback_SNII_N_masses - 1];
+      else
+        result = interpolate_1D_non_uniform(
+            feedback_props->yield_SNII.mass, SNII_ejecta,
+            eagle_feedback_SNII_N_masses, feedback_props->yield_mass_bins[k]);
+
+      flat_index = row_major_index_2d(i, k, eagle_feedback_SNII_N_metals,
+                                      eagle_feedback_N_imf_bins);
+      feedback_props->yield_SNII.total_metals_IMF_resampled[flat_index] =
+          exp(M_LN10 * feedback_props->yield_mass_bins[k]) * result;
+    }
+  }
+
+  /* AGB yields */
+  for (int i = 0; i < eagle_feedback_AGB_N_metals; i++) {
+    for (int k = 0; k < eagle_feedback_AGB_N_masses; k++) {
+      flat_index = row_major_index_2d(i, k, eagle_feedback_AGB_N_metals,
+                                      eagle_feedback_AGB_N_masses);
+      AGB_ejecta[k] = feedback_props->yield_AGB.ejecta[flat_index] /
+                      exp(M_LN10 * feedback_props->yield_AGB.mass[k]);
+    }
+
+    for (int k = 0; k < eagle_feedback_N_imf_bins; k++) {
+      if (feedback_props->yield_mass_bins[k] <
+          feedback_props->yield_AGB.mass[0])
+        result = AGB_ejecta[0];
+      else if (feedback_props->yield_mass_bins[k] >
+               feedback_props->yield_AGB.mass[eagle_feedback_AGB_N_masses - 1])
+        result = AGB_ejecta[eagle_feedback_AGB_N_masses - 1];
+      else
+        result = interpolate_1D_non_uniform(
+            feedback_props->yield_AGB.mass, AGB_ejecta,
+            eagle_feedback_AGB_N_masses, feedback_props->yield_mass_bins[k]);
+
+      flat_index = row_major_index_2d(i, k, eagle_feedback_AGB_N_metals,
+                                      eagle_feedback_N_imf_bins);
+      feedback_props->yield_AGB.ejecta_IMF_resampled[flat_index] =
+          exp(M_LN10 * feedback_props->yield_mass_bins[k]) * result;
+    }
+  }
+
+  for (int i = 0; i < eagle_feedback_AGB_N_metals; i++) {
+    for (int k = 0; k < eagle_feedback_AGB_N_masses; k++) {
+      flat_index = row_major_index_2d(i, k, eagle_feedback_AGB_N_metals,
+                                      eagle_feedback_AGB_N_masses);
+      AGB_ejecta[k] = feedback_props->yield_AGB.total_metals[flat_index] *
+                      exp(M_LN10 * (-feedback_props->yield_AGB.mass[k]));
+    }
+
+    for (int k = 0; k < eagle_feedback_N_imf_bins; k++) {
+      if (feedback_props->yield_mass_bins[k] <
+          feedback_props->yield_AGB.mass[0])
+        result = AGB_ejecta[0];
+      else if (feedback_props->yield_mass_bins[k] >
+               feedback_props->yield_AGB.mass[eagle_feedback_AGB_N_masses - 1])
+        result = AGB_ejecta[eagle_feedback_AGB_N_masses - 1];
+      else
+        result = interpolate_1D_non_uniform(
+            feedback_props->yield_AGB.mass, AGB_ejecta,
+            eagle_feedback_AGB_N_masses, feedback_props->yield_mass_bins[k]);
+
+      flat_index = row_major_index_2d(i, k, eagle_feedback_AGB_N_metals,
+                                      eagle_feedback_N_imf_bins);
+      feedback_props->yield_AGB.total_metals_IMF_resampled[flat_index] =
+          exp(M_LN10 * feedback_props->yield_mass_bins[k]) * result;
+    }
+  }
+}
+
+#endif /* SWIFT_EAGLE_FEEDBACK_YIELD_TABLES_H */
diff --git a/src/feedback/none/feedback.h b/src/feedback/none/feedback.h
new file mode 100644
index 0000000000000000000000000000000000000000..de37015a9974df93d7dee81f7e386213f83b59bb
--- /dev/null
+++ b/src/feedback/none/feedback.h
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Copyright (c) 2018 Matthieu Schaller (schaller@strw.leidenuniv.nl)
+ *
+ * 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_FEEDBACK_NONE_H
+#define SWIFT_FEEDBACK_NONE_H
+
+#include "cosmology.h"
+#include "error.h"
+#include "feedback_properties.h"
+#include "hydro_properties.h"
+#include "part.h"
+#include "units.h"
+
+/**
+ * @brief Prepares a s-particle for its feedback interactions
+ *
+ * @param sp The particle to act upon
+ */
+__attribute__((always_inline)) INLINE static void feedback_init_spart(
+    struct spart* sp) {}
+
+/**
+ * @brief Should we do feedback for this star?
+ *
+ * @param sp The star to consider.
+ */
+__attribute__((always_inline)) INLINE static int feedback_do_feedback(
+    const struct spart* sp) {
+
+  return 0;
+}
+
+/**
+ * @brief Prepares a star's feedback field before computing what
+ * needs to be distributed.
+ */
+__attribute__((always_inline)) INLINE static void feedback_reset_feedback(
+    struct spart* sp, const struct feedback_props* feedback_props) {}
+
+/**
+ * @brief Initialises the s-particles feedback props for the first time
+ *
+ * This function is called only once just after the ICs have been
+ * read in to do some conversions.
+ *
+ * @param sp The particle to act upon.
+ * @param feedback_props The properties of the feedback model.
+ */
+__attribute__((always_inline)) INLINE static void feedback_first_init_spart(
+    struct spart* sp, const struct feedback_props* feedback_props) {}
+
+/**
+ * @brief Initialises the s-particles feedback props for the first time
+ *
+ * This function is called only once just after the ICs have been
+ * read in to do some conversions.
+ *
+ * @param sp The particle to act upon.
+ * @param feedback_props The properties of the feedback model.
+ */
+__attribute__((always_inline)) INLINE static void feedback_prepare_spart(
+    struct spart* sp, const struct feedback_props* feedback_props) {}
+
+/**
+ * @brief Evolve the stellar properties of a #spart.
+ *
+ * This function allows for example to compute the SN rate before sending
+ * this information to a different MPI rank.
+ *
+ * @param sp The particle to act upon
+ * @param feedback_props The #feedback_props structure.
+ * @param cosmo The current cosmological model.
+ * @param us The unit system.
+ * @param star_age_beg_step The age of the star at the star of the time-step in
+ * internal units.
+ * @param dt The time-step size of this star in internal units.
+ */
+__attribute__((always_inline)) INLINE static void feedback_evolve_spart(
+    struct spart* restrict sp, const struct feedback_props* feedback_props,
+    const struct cosmology* cosmo, const struct unit_system* us,
+    const double star_age_beg_step, const double dt) {}
+
+#endif /* SWIFT_FEEDBACK_NONE_H */
diff --git a/src/feedback/none/feedback_iact.h b/src/feedback/none/feedback_iact.h
new file mode 100644
index 0000000000000000000000000000000000000000..1c2613337a17d55ec1e3c9defd742b1ed0c41fd8
--- /dev/null
+++ b/src/feedback/none/feedback_iact.h
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Coypright (c) 2018 Matthieu Schaller (schaller@strw.leidenuniv.nl)
+ *
+ * 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_NONE_FEEDBACK_IACT_H
+#define SWIFT_NONE_FEEDBACK_IACT_H
+
+/**
+ * @brief Density interaction between two particles (non-symmetric).
+ *
+ * Nothing to do here for the no-feedback model.
+ *
+ * @param r2 Comoving square distance between the two particles.
+ * @param dx Comoving vector separating both particles (pi - pj).
+ * @param hi Comoving smoothing-length of particle i.
+ * @param hj Comoving smoothing-length of particle j.
+ * @param si First sparticle.
+ * @param pj Second particle (not updated).
+ * @param xp Extra particle data (not updated).
+ * @param cosmo The cosmological model.
+ * @param ti_current Current integer time value
+ */
+__attribute__((always_inline)) INLINE static void
+runner_iact_nonsym_feedback_density(const float r2, const float *dx,
+                                    const float hi, const float hj,
+                                    struct spart *restrict si,
+                                    const struct part *restrict pj,
+                                    const struct xpart *restrict xp,
+                                    const struct cosmology *restrict cosmo,
+                                    const integertime_t ti_current) {}
+
+/**
+ * @brief Feedback interaction between two particles (non-symmetric).
+ * Used for updating properties of gas particles neighbouring a star particle
+ *
+ * Nothing to do here for the no-feedback model.
+ *
+ * @param r2 Comoving square distance between the two particles.
+ * @param dx Comoving vector separating both particles (si - pj).
+ * @param hi Comoving smoothing-length of particle i.
+ * @param hj Comoving smoothing-length of particle j.
+ * @param si First (star) particle (not updated).
+ * @param pj Second (gas) particle.
+ * @param xp Extra particle data
+ * @param cosmo The cosmological model.
+ * @param ti_current Current integer time used value for seeding random number
+ * generator
+ */
+__attribute__((always_inline)) INLINE static void
+runner_iact_nonsym_feedback_apply(const float r2, const float *dx,
+                                  const float hi, const float hj,
+                                  const struct spart *restrict si,
+                                  struct part *restrict pj,
+                                  struct xpart *restrict xp,
+                                  const struct cosmology *restrict cosmo,
+                                  const integertime_t ti_current) {}
+
+#endif /* SWIFT_NONE_FEEDBACK_IACT_H */
diff --git a/src/feedback/none/feedback_properties.h b/src/feedback/none/feedback_properties.h
new file mode 100644
index 0000000000000000000000000000000000000000..45b275779780f35547dd158f6a2b44aaeab1dfef
--- /dev/null
+++ b/src/feedback/none/feedback_properties.h
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Coypright (c) 2018 Matthieu Schaller (schaller@strw.leidenuniv.nl)
+ *
+ * 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_NONE_FEEDBACK_PROPERTIES_H
+#define SWIFT_NONE_FEEDBACK_PROPERTIES_H
+
+#include "chemistry.h"
+#include "hydro_properties.h"
+#include "inline.h"
+
+/**
+ * @brief Properties of the EAGLE feedback model.
+ */
+struct feedback_props {};
+
+/**
+ * @brief Initialize the global properties of the feedback scheme.
+ *
+ * Nothing to do here for the no feedback model.
+ *
+ * @param fp The #feedback_props.
+ * @param phys_const The physical constants in the internal unit system.
+ * @param us The internal unit system.
+ * @param params The parsed parameters.
+ * @param hydro_props The already read-in properties of the hydro scheme.
+ * @param cosmo The cosmological model.
+ */
+INLINE static void feedback_props_init(struct feedback_props *fp,
+                                       const struct phys_const *phys_const,
+                                       const struct unit_system *us,
+                                       struct swift_params *params,
+                                       const struct hydro_props *hydro_props,
+                                       const struct cosmology *cosmo) {}
+
+#endif /* SWIFT_NONE_FEEDBACK_PROPERTIES_H */
diff --git a/src/feedback/none/feedback_struct.h b/src/feedback/none/feedback_struct.h
new file mode 100644
index 0000000000000000000000000000000000000000..0dde77bbd7e58a1768abfd285af2804be7c28865
--- /dev/null
+++ b/src/feedback/none/feedback_struct.h
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Copyright (c) 2018 Matthieu Schaller (schaller@strw.leidenuniv.nl)
+ *
+ * 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_FEEDBACK_STRUCT_NONE_H
+#define SWIFT_FEEDBACK_STRUCT_NONE_H
+
+#include "chemistry_struct.h"
+
+/**
+ * @brief Feedback fields carried by each star particles
+ *
+ * Nothing here since this is a no-feedback model.
+ */
+struct feedback_spart_data {};
+
+#endif /* SWIFT_FEEDBACK_STRUCT_NONE_H */
diff --git a/src/feedback_properties.h b/src/feedback_properties.h
new file mode 100644
index 0000000000000000000000000000000000000000..83afbb1eeac2aeab080d9c564542b180ea1429af
--- /dev/null
+++ b/src/feedback_properties.h
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Coypright (c) 2018 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_FEEDBACK_PROPERTIES_H
+#define SWIFT_FEEDBACK_PROPERTIES_H
+
+/* Config parameters. */
+#include "../config.h"
+
+/* Select the correct feedback model */
+#if defined(FEEDBACK_NONE)
+#include "./feedback/none/feedback_properties.h"
+#elif defined(FEEDBACK_EAGLE)
+#include "./feedback/EAGLE/feedback_properties.h"
+#else
+#error "Invalid choice of feedback model"
+#endif
+
+#endif /* SWIFT_FEEDBACK_PROPERTIES_H */
diff --git a/src/feedback_struct.h b/src/feedback_struct.h
new file mode 100644
index 0000000000000000000000000000000000000000..be6d480e7a7a6165fd6f73e4ca0ed15078f06488
--- /dev/null
+++ b/src/feedback_struct.h
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Copyright (c) 2018 Matthieu Schaller (schaller@strw.leidenuniv.nl)
+ *
+ * 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_FEEDBACK_STRUCT_H
+#define SWIFT_FEEDBACK_STRUCT_H
+
+/**
+ * @file src/feedback_struct.h
+ * @brief Branches between the different feedback functions.
+ */
+
+/* Config parameters. */
+#include "../config.h"
+
+/* Import the right feedback definition */
+#if defined(FEEDBACK_NONE)
+#include "./feedback/none/feedback_struct.h"
+#elif defined(FEEDBACK_EAGLE)
+#include "./feedback/EAGLE/feedback_struct.h"
+#else
+#error "Invalid choice of feedback function."
+#endif
+
+#endif /* SWIFT_FEEDBACK_STRUCT_H */
diff --git a/src/hydro/Gadget2/hydro.h b/src/hydro/Gadget2/hydro.h
index f05e3229a03f18115aa0e60ba5fee94bc39c5b9e..e6df246dd10e84822b5c1cb806c6ad9840089f20 100644
--- a/src/hydro/Gadget2/hydro.h
+++ b/src/hydro/Gadget2/hydro.h
@@ -672,8 +672,8 @@ __attribute__((always_inline)) INLINE static void hydro_predict_extra(
 #ifdef SWIFT_DEBUG_CHECKS
   if (p->entropy + p->entropy_dt * dt_therm <= 0)
     error(
-        "Negative entropy for particle id %llu old entropy %.5e d_entropy %.5e "
-        "entropy_dt %.5e dt therm %.5e",
+        "Negative entropy for particle id %llu old entropy %.e d_entropy %.e "
+        "entropy_dt %.e dt therm %.e",
         p->id, p->entropy, p->entropy_dt * dt_therm, p->entropy_dt, dt_therm);
 #endif
   p->entropy += p->entropy_dt * dt_therm;
diff --git a/src/hydro/Gadget2/hydro_iact.h b/src/hydro/Gadget2/hydro_iact.h
index 1ded85acfb7486b1286ddfbbfa698da0f4344e7d..819ba3889b008e859939ff1d0c2b6ac62a1be30a 100644
--- a/src/hydro/Gadget2/hydro_iact.h
+++ b/src/hydro/Gadget2/hydro_iact.h
@@ -595,7 +595,6 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force(
   const float r = r2 * r_inv;
 
   /* Get some values in local variables. */
-  // const float mi = pi->mass;
   const float mj = pj->mass;
   const float rhoi = pi->rho;
   const float rhoj = pj->rho;
@@ -1071,13 +1070,16 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_limiter(
   /* Wake up the neighbour? */
   if (pi->force.v_sig > const_limiter_max_v_sig_ratio * pj->force.v_sig) {
 
-    pj->wakeup = time_bin_awake;
+    // ALEXEI seems to crash with this option when running with debug checks
+    // on comparing ti_kick to ti_start in kick_part. Use code below instead
+    // (commented MATTHIEU)
+    // pj->wakeup = time_bin_awake;
 
     // MATTHIEU
-    // if (pj->wakeup == time_bin_not_awake)
-    // pj->wakeup = time_bin_awake;
-    // else if (pj->wakeup > 0)
-    // pj->wakeup = -pj->wakeup;
+    if (pj->wakeup == time_bin_not_awake)
+      pj->wakeup = time_bin_awake;
+    else if (pj->wakeup > 0)
+      pj->wakeup = -pj->wakeup;
   }
 }
 
diff --git a/src/hydro_properties.c b/src/hydro_properties.c
index ca38be1d2e32d7e4830d878e65bae796b7806457..e5126fe67584a4401061cc795d105d9a0d1d7b07 100644
--- a/src/hydro_properties.c
+++ b/src/hydro_properties.c
@@ -136,7 +136,7 @@ void hydro_props_init(struct hydro_props *p,
       params, "SPH:initial_temperature", hydro_props_default_init_temp);
 
   if (p->initial_temperature < 0.f)
-    error("ERROR: Minimal temperature set to a negative value!!!");
+    error("ERROR: Initial temperature set to a negative value!!!");
 
   /* Minimal temperature */
   p->minimal_temperature = parser_get_opt_param_float(
diff --git a/src/part.h b/src/part.h
index b5c5c09104f113abfa1d0335723e592ecade0d91..629f6dbfa58692fc067546b2eb32c89519dc93d7 100644
--- a/src/part.h
+++ b/src/part.h
@@ -94,7 +94,9 @@
 #endif
 
 /* Import the right star particle definition */
-#if defined(STARS_NONE)
+#if defined(FEEDBACK_CONST)
+#include "./stars/const/stars_part.h"
+#elif defined(STARS_NONE)
 #include "./stars/Default/stars_part.h"
 #elif defined(STARS_EAGLE)
 #include "./stars/EAGLE/stars_part.h"
diff --git a/src/runner.c b/src/runner.c
index d1511c5cb1f52aeb5bb6134f8cf4d5d91aeb6ff8..d5535737ff7c2b19f901e2f9809f6084f1d336b9 100644
--- a/src/runner.c
+++ b/src/runner.c
@@ -50,6 +50,7 @@
 #include "engine.h"
 #include "entropy_floor.h"
 #include "error.h"
+#include "feedback.h"
 #include "gravity.h"
 #include "hydro.h"
 #include "hydro_properties.h"
@@ -137,7 +138,10 @@ void runner_do_stars_ghost(struct runner *r, struct cell *c, int timer) {
 
   struct spart *restrict sparts = c->stars.parts;
   const struct engine *e = r->e;
+  const struct unit_system *us = e->internal_units;
+  const int with_cosmology = (e->policy & engine_policy_cosmology);
   const struct cosmology *cosmo = e->cosmology;
+  const struct feedback_props *feedback_props = e->feedback_props;
   const float stars_h_max = e->hydro_properties->h_max;
   const float stars_h_min = e->hydro_properties->h_min;
   const float eps = e->stars_properties->h_tolerance;
@@ -256,6 +260,7 @@ void runner_do_stars_ghost(struct runner *r, struct cell *c, int timer) {
               ((sp->h <= stars_h_min) && (f > 0.f))) {
 
             stars_reset_feedback(sp);
+            feedback_reset_feedback(sp, feedback_props);
 
             /* Ok, we are done with this particle */
             continue;
@@ -277,12 +282,6 @@ void runner_do_stars_ghost(struct runner *r, struct cell *c, int timer) {
                 n_target, left[i], right[i]);
           }
 
-#ifdef SWIFT_DEBUG_CHECKS
-          if ((f > 0.f && h_new > h_old) || (f < 0.f && h_new < h_old))
-            error(
-                "Smoothing length correction not going in the right direction");
-#endif
-
           /* Safety check: truncate to the range [ h_old/2 , 2h_old ]. */
           h_new = min(h_new, 2.f * h_old);
           h_new = max(h_new, 0.5f * h_old);
@@ -323,6 +322,7 @@ void runner_do_stars_ghost(struct runner *r, struct cell *c, int timer) {
 
             /* Re-initialise everything */
             stars_init_spart(sp);
+            feedback_init_spart(sp);
 
             /* Off we go ! */
             continue;
@@ -356,8 +356,51 @@ void runner_do_stars_ghost(struct runner *r, struct cell *c, int timer) {
 
         stars_reset_feedback(sp);
 
-        /* Compute the stellar evolution  */
-        stars_evolve_spart(sp, e->stars_properties, cosmo);
+        /* Only do feedback if stars have a reasonable birth time */
+        if (feedback_do_feedback(sp)) {
+
+          const integertime_t ti_step = get_integer_timestep(sp->time_bin);
+          const integertime_t ti_begin =
+              get_integer_time_begin(e->ti_current - 1, sp->time_bin);
+
+          /* Get particle time-step */
+          double dt;
+          if (with_cosmology) {
+            dt = cosmology_get_delta_time(e->cosmology, ti_begin,
+                                          ti_begin + ti_step);
+          } else {
+            dt = get_timestep(sp->time_bin, e->time_base);
+          }
+
+          /* Calculate age of the star at current time */
+          double star_age_end_of_step;
+          if (with_cosmology) {
+            star_age_end_of_step = cosmology_get_delta_time_from_scale_factors(
+                cosmo, sp->birth_scale_factor, (float)cosmo->a);
+          } else {
+            star_age_end_of_step = e->time - sp->birth_time;
+          }
+
+          /* Has this star been around for a while ? */
+          if (star_age_end_of_step > 0.) {
+
+            /* Age of the star at the start of the step */
+            const double star_age_beg_of_step =
+                max(star_age_end_of_step - dt, 0.);
+
+            /* Compute the stellar evolution  */
+            feedback_evolve_spart(sp, feedback_props, cosmo, us,
+                                  star_age_beg_of_step, dt);
+          } else {
+
+            /* Reset the feedback fields of the star particle */
+            feedback_reset_feedback(sp, feedback_props);
+          }
+        } else {
+
+          /* Reset the feedback fields of the star particle */
+          feedback_reset_feedback(sp, feedback_props);
+        }
       }
 
       /* We now need to treat the particles whose smoothing length had not
@@ -1562,12 +1605,14 @@ void runner_do_ghost(struct runner *r, struct cell *c, int timer) {
         const float h_init = h_0[i];
         const float h_old = p->h;
         const float h_old_dim = pow_dimension(h_old);
+        // const float h_old_inv_dim = pow_dimension(1.f / h_old);
         const float h_old_dim_minus_one = pow_dimension_minus_one(h_old);
 
         float h_new;
         int has_no_neighbours = 0;
 
-        if (p->density.wcount == 0.f) { /* No neighbours case */
+        if (p->density.wcount == 0.f) {
+          // 1e-5 * kernel_root * h_old_inv_dim) { /* No neighbours case */
 
           /* Flag that there were no neighbours */
           has_no_neighbours = 1;
@@ -2952,7 +2997,7 @@ void runner_do_limiter(struct runner *r, struct cell *c, int force, int timer) {
         p->wakeup = time_bin_not_awake;
 
       /* Bip, bip, bip... wake-up time */
-      if (p->wakeup == time_bin_awake) {
+      if (p->wakeup <= time_bin_awake) {
 
         /* Apply the limiter and get the new time-step size */
         const integertime_t ti_new_step = timestep_limit_part(p, xp, e);
diff --git a/src/runner_doiact_stars.h b/src/runner_doiact_stars.h
index 6b8b12ad966d6ee1271ae8e5d48a0e2b5d9166c4..841515b0b079bf29a9c3dfd5c28ec8cc8848de32 100644
--- a/src/runner_doiact_stars.h
+++ b/src/runner_doiact_stars.h
@@ -88,6 +88,7 @@ void DOSELF1_STARS(struct runner *r, struct cell *c, int timer) {
 #endif
 
   const struct engine *e = r->e;
+  const integertime_t ti_current = e->ti_current;
   const struct cosmology *cosmo = e->cosmology;
 
   /* Anything to do here? */
@@ -102,6 +103,7 @@ void DOSELF1_STARS(struct runner *r, struct cell *c, int timer) {
   const int count = c->hydro.count;
   struct spart *restrict sparts = c->stars.parts;
   struct part *restrict parts = c->hydro.parts;
+  struct xpart *restrict xparts = c->hydro.xparts;
 
   /* Loop over the sparts in ci. */
   for (int sid = 0; sid < scount; sid++) {
@@ -121,6 +123,8 @@ void DOSELF1_STARS(struct runner *r, struct cell *c, int timer) {
 
       /* Get a pointer to the jth particle. */
       struct part *restrict pj = &parts[pjd];
+      struct xpart *restrict xpj = &xparts[pjd];
+      const float hj = pj->h;
 
       /* Early abort? */
       if (part_is_inhibited(pj, e)) continue;
@@ -139,7 +143,14 @@ void DOSELF1_STARS(struct runner *r, struct cell *c, int timer) {
 #endif
 
       if (r2 < hig2) {
-        IACT_STARS(r2, dx, hi, pj->h, si, pj, a, H);
+        IACT_STARS(r2, dx, hi, hj, si, pj, a, H);
+#if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
+        runner_iact_nonsym_feedback_density(r2, dx, hi, hj, si, pj, xpj, cosmo,
+                                            ti_current);
+#elif (FUNCTION_TASK_LOOP == TASK_LOOP_FEEDBACK)
+        runner_iact_nonsym_feedback_apply(r2, dx, hi, hj, si, pj, xpj, cosmo,
+                                          ti_current);
+#endif
       }
     } /* loop over the parts in ci. */
   }   /* loop over the sparts in ci. */
@@ -164,20 +175,22 @@ void DO_NONSYM_PAIR1_STARS_NAIVE(struct runner *r, struct cell *restrict ci,
 #endif
 
   const struct engine *e = r->e;
+  const integertime_t ti_current = e->ti_current;
   const struct cosmology *cosmo = e->cosmology;
 
   /* Anything to do here? */
   if (cj->hydro.count == 0 || ci->stars.count == 0) return;
   if (!cell_is_active_stars(ci, e)) return;
 
+  /* Cosmological terms */
+  const float a = cosmo->a;
+  const float H = cosmo->H;
+
   const int scount_i = ci->stars.count;
   const int count_j = cj->hydro.count;
   struct spart *restrict sparts_i = ci->stars.parts;
   struct part *restrict parts_j = cj->hydro.parts;
-
-  /* Cosmological terms */
-  const float a = cosmo->a;
-  const float H = cosmo->H;
+  struct xpart *restrict xparts_j = cj->hydro.xparts;
 
   /* Get the relative distance between the pairs, wrapping. */
   double shift[3] = {0.0, 0.0, 0.0};
@@ -206,6 +219,8 @@ void DO_NONSYM_PAIR1_STARS_NAIVE(struct runner *r, struct cell *restrict ci,
 
       /* Get a pointer to the jth particle. */
       struct part *restrict pj = &parts_j[pjd];
+      struct xpart *restrict xpj = &xparts_j[pjd];
+      const float hj = pj->h;
 
       /* Skip inhibited particles. */
       if (part_is_inhibited(pj, e)) continue;
@@ -223,8 +238,17 @@ void DO_NONSYM_PAIR1_STARS_NAIVE(struct runner *r, struct cell *restrict ci,
         error("Particle pj not drifted to current time");
 #endif
 
-      if (r2 < hig2) IACT_STARS(r2, dx, hi, pj->h, si, pj, a, H);
+      if (r2 < hig2) {
+        IACT_STARS(r2, dx, hi, hj, si, pj, a, H);
 
+#if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
+        runner_iact_nonsym_feedback_density(r2, dx, hi, hj, si, pj, xpj, cosmo,
+                                            ti_current);
+#elif (FUNCTION_TASK_LOOP == TASK_LOOP_FEEDBACK)
+        runner_iact_nonsym_feedback_apply(r2, dx, hi, hj, si, pj, xpj, cosmo,
+                                          ti_current);
+#endif
+      }
     } /* loop over the parts in cj. */
   }   /* loop over the parts in ci. */
 }
@@ -241,17 +265,18 @@ void DO_NONSYM_PAIR1_STARS_NAIVE(struct runner *r, struct cell *restrict ci,
 void DO_SYM_PAIR1_STARS(struct runner *r, struct cell *ci, struct cell *cj,
                         const int sid, const double *shift) {
 
-  const struct engine *restrict e = r->e;
-  const struct cosmology *restrict cosmo = e->cosmology;
-
-  /* Get the cutoff shift. */
-  double rshift = 0.0;
-  for (int k = 0; k < 3; k++) rshift += shift[k] * runner_shift[sid][k];
+  const struct engine *e = r->e;
+  const integertime_t ti_current = e->ti_current;
+  const struct cosmology *cosmo = e->cosmology;
 
   /* Cosmological terms */
   const float a = cosmo->a;
   const float H = cosmo->H;
 
+  /* Get the cutoff shift. */
+  double rshift = 0.0;
+  for (int k = 0; k < 3; k++) rshift += shift[k] * runner_shift[sid][k];
+
 #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
   const int do_ci_stars = (ci->nodeID == e->nodeID) && (ci->stars.count != 0) &&
                           (cj->hydro.count != 0) && cell_is_active_stars(ci, e);
@@ -290,6 +315,7 @@ void DO_SYM_PAIR1_STARS(struct runner *r, struct cell *ci, struct cell *cj,
     const int count_j = cj->hydro.count;
     struct spart *restrict sparts_i = ci->stars.parts;
     struct part *restrict parts_j = cj->hydro.parts;
+    struct xpart *restrict xparts_j = cj->hydro.xparts;
     const double dj_min = sort_j[0].d;
     const float dx_max_rshift =
         (ci->stars.dx_max_sort + cj->hydro.dx_max_sort) - rshift;
@@ -326,6 +352,7 @@ void DO_SYM_PAIR1_STARS(struct runner *r, struct cell *ci, struct cell *cj,
 
         /* Recover pj */
         struct part *pj = &parts_j[sort_j[pjd].i];
+        struct xpart *xpj = &xparts_j[sort_j[pjd].i];
 
         /* Skip inhibited particles. */
         if (part_is_inhibited(pj, e)) continue;
@@ -375,8 +402,15 @@ void DO_SYM_PAIR1_STARS(struct runner *r, struct cell *ci, struct cell *cj,
 
         /* Hit or miss? */
         if (r2 < hig2) {
-
           IACT_STARS(r2, dx, hi, hj, spi, pj, a, H);
+
+#if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
+          runner_iact_nonsym_feedback_density(r2, dx, hi, hj, spi, pj, xpj,
+                                              cosmo, ti_current);
+#elif (FUNCTION_TASK_LOOP == TASK_LOOP_FEEDBACK)
+          runner_iact_nonsym_feedback_apply(r2, dx, hi, hj, spi, pj, xpj, cosmo,
+                                            ti_current);
+#endif
         }
       } /* loop over the parts in cj. */
     }   /* loop over the parts in ci. */
@@ -405,6 +439,7 @@ void DO_SYM_PAIR1_STARS(struct runner *r, struct cell *ci, struct cell *cj,
     const int count_i = ci->hydro.count;
     const int count_j = cj->stars.count;
     struct part *restrict parts_i = ci->hydro.parts;
+    struct xpart *restrict xparts_i = ci->hydro.xparts;
     struct spart *restrict sparts_j = cj->stars.parts;
     const double di_max = sort_i[count_i - 1].d - rshift;
     const float dx_max_rshift =
@@ -442,6 +477,7 @@ void DO_SYM_PAIR1_STARS(struct runner *r, struct cell *ci, struct cell *cj,
 
         /* Recover pi */
         struct part *pi = &parts_i[sort_i[pid].i];
+        struct xpart *xpi = &xparts_i[sort_i[pid].i];
 
         /* Skip inhibited particles. */
         if (part_is_inhibited(pi, e)) continue;
@@ -493,6 +529,14 @@ void DO_SYM_PAIR1_STARS(struct runner *r, struct cell *ci, struct cell *cj,
         if (r2 < hjg2) {
 
           IACT_STARS(r2, dx, hj, hi, spj, pi, a, H);
+
+#if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
+          runner_iact_nonsym_feedback_density(r2, dx, hj, hi, spj, pi, xpi,
+                                              cosmo, ti_current);
+#elif (FUNCTION_TASK_LOOP == TASK_LOOP_FEEDBACK)
+          runner_iact_nonsym_feedback_apply(r2, dx, hj, hi, spj, pi, xpi, cosmo,
+                                            ti_current);
+#endif
         }
       } /* loop over the parts in ci. */
     }   /* loop over the parts in cj. */
@@ -538,18 +582,20 @@ void DOPAIR1_SUBSET_STARS(struct runner *r, struct cell *restrict ci,
                           const int flipped, const double *shift) {
 
   const struct engine *e = r->e;
+  const integertime_t ti_current = e->ti_current;
   const struct cosmology *cosmo = e->cosmology;
 
+  /* Cosmological terms */
+  const float a = cosmo->a;
+  const float H = cosmo->H;
+
   const int count_j = cj->hydro.count;
   struct part *restrict parts_j = cj->hydro.parts;
+  struct xpart *restrict xparts_j = cj->hydro.xparts;
 
   /* Early abort? */
   if (count_j == 0) return;
 
-  /* Cosmological terms */
-  const float a = cosmo->a;
-  const float H = cosmo->H;
-
   /* Pick-out the sorted lists. */
   const struct entry *restrict sort_j = cj->hydro.sort[sid];
   const float dxj = cj->hydro.dx_max_sort;
@@ -575,6 +621,7 @@ void DOPAIR1_SUBSET_STARS(struct runner *r, struct cell *restrict ci,
 
         /* Get a pointer to the jth particle. */
         struct part *restrict pj = &parts_j[sort_j[pjd].i];
+        struct xpart *restrict xpj = &xparts_j[sort_j[pjd].i];
 
         /* Skip inhibited particles. */
         if (part_is_inhibited(pj, e)) continue;
@@ -582,6 +629,7 @@ void DOPAIR1_SUBSET_STARS(struct runner *r, struct cell *restrict ci,
         const double pjx = pj->x[0];
         const double pjy = pj->x[1];
         const double pjz = pj->x[2];
+        const float hj = pj->h;
 
         /* Compute the pairwise distance. */
         float dx[3] = {(float)(pix - pjx), (float)(piy - pjy),
@@ -598,7 +646,15 @@ void DOPAIR1_SUBSET_STARS(struct runner *r, struct cell *restrict ci,
 
         /* Hit or miss? */
         if (r2 < hig2) {
-          IACT_STARS(r2, dx, hi, pj->h, spi, pj, a, H);
+          IACT_STARS(r2, dx, hi, hj, spi, pj, a, H);
+
+#if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
+          runner_iact_nonsym_feedback_density(r2, dx, hi, hj, spi, pj, xpj,
+                                              cosmo, ti_current);
+#elif (FUNCTION_TASK_LOOP == TASK_LOOP_FEEDBACK)
+          runner_iact_nonsym_feedback_apply(r2, dx, hi, hj, spi, pj, xpj, cosmo,
+                                            ti_current);
+#endif
         }
       } /* loop over the parts in cj. */
     }   /* loop over the sparts in ci. */
@@ -625,6 +681,7 @@ void DOPAIR1_SUBSET_STARS(struct runner *r, struct cell *restrict ci,
 
         /* Get a pointer to the jth particle. */
         struct part *restrict pj = &parts_j[sort_j[pjd].i];
+        struct xpart *restrict xpj = &xparts_j[sort_j[pjd].i];
 
         /* Skip inhibited particles. */
         if (part_is_inhibited(pj, e)) continue;
@@ -632,6 +689,7 @@ void DOPAIR1_SUBSET_STARS(struct runner *r, struct cell *restrict ci,
         const double pjx = pj->x[0];
         const double pjy = pj->x[1];
         const double pjz = pj->x[2];
+        const float hj = pj->h;
 
         /* Compute the pairwise distance. */
         float dx[3] = {(float)(pix - pjx), (float)(piy - pjy),
@@ -648,7 +706,15 @@ void DOPAIR1_SUBSET_STARS(struct runner *r, struct cell *restrict ci,
 
         /* Hit or miss? */
         if (r2 < hig2) {
-          IACT_STARS(r2, dx, hi, pj->h, spi, pj, a, H);
+          IACT_STARS(r2, dx, hi, hj, spi, pj, a, H);
+
+#if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
+          runner_iact_nonsym_feedback_density(r2, dx, hi, hj, spi, pj, xpj,
+                                              cosmo, ti_current);
+#elif (FUNCTION_TASK_LOOP == TASK_LOOP_FEEDBACK)
+          runner_iact_nonsym_feedback_apply(r2, dx, hi, hj, spi, pj, xpj, cosmo,
+                                            ti_current);
+#endif
         }
       } /* loop over the parts in cj. */
     }   /* loop over the sparts in ci. */
@@ -677,26 +743,31 @@ void DOPAIR1_SUBSET_STARS_NAIVE(struct runner *r, struct cell *restrict ci,
 #ifdef SWIFT_DEBUG_CHECKS
   if (ci->nodeID != engine_rank) error("Should be run on a different node");
 #endif
+
   const struct engine *e = r->e;
+  const integertime_t ti_current = e->ti_current;
   const struct cosmology *cosmo = e->cosmology;
 
+  /* Cosmological terms */
+  const float a = cosmo->a;
+  const float H = cosmo->H;
+
   const int count_j = cj->hydro.count;
   struct part *restrict parts_j = cj->hydro.parts;
+  struct xpart *restrict xparts_j = cj->hydro.xparts;
 
   /* Early abort? */
   if (count_j == 0) return;
 
-  /* Cosmological terms */
-  const float a = cosmo->a;
-  const float H = cosmo->H;
-
   /* Loop over the parts_i. */
   for (int pid = 0; pid < scount; pid++) {
 
     /* Get a hold of the ith part in ci. */
     struct spart *restrict spi = &sparts_i[ind[pid]];
-    double spix[3];
-    for (int k = 0; k < 3; k++) spix[k] = spi->x[k] - shift[k];
+
+    const double pix = spi->x[0] - (shift[0]);
+    const double piy = spi->x[1] - (shift[1]);
+    const double piz = spi->x[2] - (shift[2]);
     const float hi = spi->h;
     const float hig2 = hi * hi * kernel_gamma2;
 
@@ -710,17 +781,20 @@ void DOPAIR1_SUBSET_STARS_NAIVE(struct runner *r, struct cell *restrict ci,
 
       /* Get a pointer to the jth particle. */
       struct part *restrict pj = &parts_j[pjd];
+      struct xpart *restrict xpj = &xparts_j[pjd];
 
       /* Skip inhibited particles */
       if (part_is_inhibited(pj, e)) continue;
 
+      const double pjx = pj->x[0];
+      const double pjy = pj->x[1];
+      const double pjz = pj->x[2];
+      const float hj = pj->h;
+
       /* Compute the pairwise distance. */
-      float r2 = 0.0f;
-      float dx[3];
-      for (int k = 0; k < 3; k++) {
-        dx[k] = spix[k] - pj->x[k];
-        r2 += dx[k] * dx[k];
-      }
+      float dx[3] = {(float)(pix - pjx), (float)(piy - pjy),
+                     (float)(piz - pjz)};
+      const float r2 = dx[0] * dx[0] + dx[1] * dx[1] + dx[2] * dx[2];
 
 #ifdef SWIFT_DEBUG_CHECKS
       /* Check that particles have been drifted to the current time */
@@ -729,7 +803,15 @@ void DOPAIR1_SUBSET_STARS_NAIVE(struct runner *r, struct cell *restrict ci,
 #endif
       /* Hit or miss? */
       if (r2 < hig2) {
-        IACT_STARS(r2, dx, hi, pj->h, spi, pj, a, H);
+        IACT_STARS(r2, dx, hi, hj, spi, pj, a, H);
+
+#if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
+        runner_iact_nonsym_feedback_density(r2, dx, hi, hj, spi, pj, xpj, cosmo,
+                                            ti_current);
+#elif (FUNCTION_TASK_LOOP == TASK_LOOP_FEEDBACK)
+        runner_iact_nonsym_feedback_apply(r2, dx, hi, hj, spi, pj, xpj, cosmo,
+                                          ti_current);
+#endif
       }
     } /* loop over the parts in cj. */
   }   /* loop over the parts in ci. */
@@ -754,6 +836,7 @@ void DOSELF1_SUBSET_STARS(struct runner *r, struct cell *restrict ci,
 #endif
 
   const struct engine *e = r->e;
+  const integertime_t ti_current = e->ti_current;
   const struct cosmology *cosmo = e->cosmology;
 
   /* Cosmological terms */
@@ -762,6 +845,7 @@ void DOSELF1_SUBSET_STARS(struct runner *r, struct cell *restrict ci,
 
   const int count_i = ci->hydro.count;
   struct part *restrict parts_j = ci->hydro.parts;
+  struct xpart *restrict xparts_j = ci->hydro.xparts;
 
   /* Early abort? */
   if (count_i == 0) return;
@@ -787,6 +871,7 @@ void DOSELF1_SUBSET_STARS(struct runner *r, struct cell *restrict ci,
 
       /* Get a pointer to the jth particle. */
       struct part *restrict pj = &parts_j[pjd];
+      struct xpart *restrict xpj = &xparts_j[pjd];
 
       /* Early abort? */
       if (part_is_inhibited(pj, e)) continue;
@@ -807,6 +892,13 @@ void DOSELF1_SUBSET_STARS(struct runner *r, struct cell *restrict ci,
       /* Hit or miss? */
       if (r2 < hig2) {
         IACT_STARS(r2, dx, hi, pj->h, spi, pj, a, H);
+#if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY)
+        runner_iact_nonsym_feedback_density(r2, dx, hi, pj->h, spi, pj, xpj,
+                                            cosmo, ti_current);
+#elif (FUNCTION_TASK_LOOP == TASK_LOOP_FEEDBACK)
+        runner_iact_nonsym_feedback_apply(r2, dx, hi, pj->h, spi, pj, xpj,
+                                          cosmo, ti_current);
+#endif
       }
     } /* loop over the parts in cj. */
   }   /* loop over the parts in ci. */
@@ -1858,7 +1950,7 @@ void DOSUB_PAIR1_STARS(struct runner *r, struct cell *ci, struct cell *cj,
 
       if (!(cj->hydro.sorted & (1 << sid)) ||
           cj->hydro.dx_max_sort_old > cj->dmin * space_maxreldx)
-        error("Interacting unsorted cell (parts).");
+        error("Interacting unsorted cell (parts). %i", cj->nodeID);
     }
 
     if (do_cj) {
diff --git a/src/space.c b/src/space.c
index 50e2ebdd7cf76cdce5ac8f365056ec974f994f59..9b5d509051f21a92e6232ce678b3db5d8878f802 100644
--- a/src/space.c
+++ b/src/space.c
@@ -4187,6 +4187,8 @@ void space_first_init_sparts_mapper(void *restrict map_data, int count,
   const struct space *restrict s = (struct space *)extra_data;
   const struct engine *e = s->e;
 
+  const struct chemistry_global_data *chemistry = e->chemistry;
+
 #ifdef SWIFT_DEBUG_CHECKS
   const ptrdiff_t delta = sp - s->sparts;
 #endif
@@ -4196,6 +4198,7 @@ void space_first_init_sparts_mapper(void *restrict map_data, int count,
   const int with_feedback = (e->policy & engine_policy_feedback);
 
   const struct cosmology *cosmo = e->cosmology;
+  const struct stars_props *stars_properties = e->stars_properties;
   const float a_factor_vel = cosmo->a;
 
   /* Convert velocities to internal units */
@@ -4231,7 +4234,10 @@ void space_first_init_sparts_mapper(void *restrict map_data, int count,
   /* Initialise the rest */
   for (int k = 0; k < count; k++) {
 
-    stars_first_init_spart(&sp[k]);
+    stars_first_init_spart(&sp[k], stars_properties);
+
+    /* Also initialise the chemistry */
+    chemistry_first_init_spart(chemistry, &sp[k]);
 
 #ifdef SWIFT_DEBUG_CHECKS
     if (sp[k].gpart && sp[k].gpart->id_or_neg_offset != -(k + delta))
diff --git a/src/stars.h b/src/stars.h
index fc7ee74d3a2cae91ee209c4008eee4d5dd0f375e..dd8390e0206580fc2a07a08e51bb69c6ee5ab5ed 100644
--- a/src/stars.h
+++ b/src/stars.h
@@ -29,11 +29,8 @@
 #elif defined(STARS_EAGLE)
 #include "./stars/EAGLE/stars.h"
 #include "./stars/EAGLE/stars_iact.h"
-#elif defined(STARS_GEAR)
-#include "./stars/GEAR/stars.h"
-#include "./stars/GEAR/stars_iact.h"
 #else
 #error "Invalid choice of star model"
 #endif
 
-#endif
+#endif /* SWIFT_STARS_H */
diff --git a/src/stars/Default/stars.h b/src/stars/Default/stars.h
index 1ff4936284c4d8913417c502db69a372fc83bc06..804fe6085d7b420955ab04c099c12e32f6a6929c 100644
--- a/src/stars/Default/stars.h
+++ b/src/stars/Default/stars.h
@@ -40,9 +40,10 @@ __attribute__((always_inline)) INLINE static float stars_compute_timestep(
  * read in to do some conversions.
  *
  * @param sp The particle to act upon
+ * @param stars_properties The properties of the stellar model.
  */
 __attribute__((always_inline)) INLINE static void stars_first_init_spart(
-    struct spart* sp) {
+    struct spart* sp, const struct stars_props* stars_properties) {
 
   sp->time_bin = 0;
 }
@@ -89,10 +90,7 @@ __attribute__((always_inline)) INLINE static void stars_reset_predicted_values(
  * @param sp The particle to act upon
  */
 __attribute__((always_inline)) INLINE static void stars_end_feedback(
-    struct spart* sp) {
-
-  sp->feedback.h_dt *= sp->h * hydro_dimension_inv;
-}
+    struct spart* sp) {}
 
 /**
  * @brief Kick the additional variables
@@ -143,20 +141,6 @@ __attribute__((always_inline)) INLINE static void stars_spart_has_no_neighbours(
   sp->density.wcount_dh = 0.f;
 }
 
-/**
- * @brief Evolve the stellar properties of a #spart.
- *
- * This function allows for example to compute the SN rate before sending
- * this information to a different MPI rank.
- *
- * @param sp The particle to act upon
- * @param cosmo The current cosmological model.
- * @param stars_properties The #stars_props
- */
-__attribute__((always_inline)) INLINE static void stars_evolve_spart(
-    struct spart* restrict sp, const struct stars_props* stars_properties,
-    const struct cosmology* cosmo) {}
-
 /**
  * @brief Reset acceleration fields of a particle
  *
@@ -168,9 +152,6 @@ __attribute__((always_inline)) INLINE static void stars_evolve_spart(
 __attribute__((always_inline)) INLINE static void stars_reset_feedback(
     struct spart* restrict p) {
 
-  /* Reset time derivative */
-  p->feedback.h_dt = 0.f;
-
 #ifdef DEBUG_INTERACTIONS_STARS
   for (int i = 0; i < MAX_NUM_OF_NEIGHBOURS_STARS; ++i)
     p->ids_ngbs_force[i] = -1;
@@ -178,4 +159,14 @@ __attribute__((always_inline)) INLINE static void stars_reset_feedback(
 #endif
 }
 
+/**
+ * @brief Initializes constants related to stellar evolution, initializes imf,
+ * reads and processes yield tables
+ *
+ * @param params swift_params parameters structure
+ * @param stars stars_props data structure
+ */
+inline static void stars_evolve_init(struct swift_params* params,
+                                     struct stars_props* restrict stars) {}
+
 #endif /* SWIFT_DEFAULT_STARS_H */
diff --git a/src/stars/Default/stars_iact.h b/src/stars/Default/stars_iact.h
index 0a9fa7f792527b44c46ff950ba82b1708ed410ff..1b68e83d7237f3bd042e520d2514df3506f93f1d 100644
--- a/src/stars/Default/stars_iact.h
+++ b/src/stars/Default/stars_iact.h
@@ -33,10 +33,11 @@
  * @param H Current Hubble parameter.
  */
 __attribute__((always_inline)) INLINE static void
-runner_iact_nonsym_stars_density(float r2, const float *dx, float hi, float hj,
+runner_iact_nonsym_stars_density(const float r2, const float *dx,
+                                 const float hi, const float hj,
                                  struct spart *restrict si,
-                                 const struct part *restrict pj, float a,
-                                 float H) {
+                                 const struct part *restrict pj, const float a,
+                                 const float H) {
 
   float wi, wi_dx;
 
@@ -76,30 +77,11 @@ runner_iact_nonsym_stars_density(float r2, const float *dx, float hi, float hj,
  * @param H Current Hubble parameter.
  */
 __attribute__((always_inline)) INLINE static void
-runner_iact_nonsym_stars_feedback(float r2, const float *dx, float hi, float hj,
-                                  struct spart *restrict si,
-                                  struct part *restrict pj, float a, float H) {
-
-  const float mj = hydro_get_mass(pj);
-  const float rhoj = hydro_get_comoving_density(pj);
-  const float r = sqrtf(r2);
-  const float ri = 1.f / r;
-
-  /* Get the kernel for hi. */
-  float hi_inv = 1.0f / hi;
-  float hid_inv = pow_dimension_plus_one(hi_inv); /* 1/h^(d+1) */
-  float xi = r * hi_inv;
-  float wi, wi_dx;
-  kernel_deval(xi, &wi, &wi_dx);
-  float wi_dr = hid_inv * wi_dx;
-
-  /* Compute dv dot r */
-  float dvdr = (si->v[0] - pj->v[0]) * dx[0] + (si->v[1] - pj->v[1]) * dx[1] +
-               (si->v[2] - pj->v[2]) * dx[2];
-
-  /* Get the time derivative for h. */
-  si->feedback.h_dt -= mj * dvdr * ri / rhoj * wi_dr;
-
+runner_iact_nonsym_stars_feedback(const float r2, const float *dx,
+                                  const float hi, const float hj,
+                                  const struct spart *restrict si,
+                                  struct part *restrict pj, const float a,
+                                  const float H) {
 #ifdef DEBUG_INTERACTIONS_STARS
   /* Update ngb counters */
   if (si->num_ngb_force < MAX_NUM_OF_NEIGHBOURS_STARS)
@@ -110,4 +92,4 @@ runner_iact_nonsym_stars_feedback(float r2, const float *dx, float hi, float hj,
 #endif
 }
 
-#endif /* SWIFT_DEFAULT_STARS_IACT_H */
+#endif
diff --git a/src/stars/Default/stars_io.h b/src/stars/Default/stars_io.h
index 26a42b8c0f80beb32695e2cb00716f283289663d..5ff57549b9d0db37d6929c1e9fbb8da8372d7e6c 100644
--- a/src/stars/Default/stars_io.h
+++ b/src/stars/Default/stars_io.h
@@ -103,12 +103,14 @@ INLINE static void stars_write_particles(const struct spart *sparts,
  * @param us The internal unit system.
  * @param params The parsed parameters.
  * @param p The already read-in properties of the hydro scheme.
+ * @param cosmo The cosmological model.
  */
 INLINE static void stars_props_init(struct stars_props *sp,
                                     const struct phys_const *phys_const,
                                     const struct unit_system *us,
                                     struct swift_params *params,
-                                    const struct hydro_props *p) {
+                                    const struct hydro_props *p,
+                                    const struct cosmology *cosmo) {
 
   /* Kernel properties */
   sp->eta_neighbours = parser_get_opt_param_float(
diff --git a/src/stars/Default/stars_part.h b/src/stars/Default/stars_part.h
index bed2e14756ff2b2b83dbd1f5de821aae4ca7be51..05035039d22c7767bde99b5148b49c4b72492f09 100644
--- a/src/stars/Default/stars_part.h
+++ b/src/stars/Default/stars_part.h
@@ -22,8 +22,9 @@
 /* Some standard headers. */
 #include <stdlib.h>
 
-/* Read chemistry */
+/* Read additional subgrid models */
 #include "chemistry_struct.h"
+#include "feedback_struct.h"
 #include "tracers_struct.h"
 
 /**
@@ -70,12 +71,15 @@ struct spart {
 
   } density;
 
-  struct {
+  /* Not used in the default stars */
+  union {
+    double birth_time;
 
-    /* Change in smoothing length over time. */
-    float h_dt;
+    double birth_scale_factor;
+  };
 
-  } feedback;
+  /*! Feedback structure */
+  struct feedback_spart_data feedback_data;
 
   /*! Tracer structure */
   struct tracers_xpart_data tracers_data;
diff --git a/src/stars/EAGLE/stars.h b/src/stars/EAGLE/stars.h
index ea63dd84453d7c02efc1232a2d96ef14af840b29..9577ea65e9f6c2c015505c7bdd193ccad9de03d8 100644
--- a/src/stars/EAGLE/stars.h
+++ b/src/stars/EAGLE/stars.h
@@ -20,7 +20,6 @@
 #define SWIFT_EAGLE_STARS_H
 
 #include <float.h>
-#include "minmax.h"
 
 /**
  * @brief Computes the gravity time-step of a given star particle.
@@ -49,7 +48,6 @@ __attribute__((always_inline)) INLINE static void stars_init_spart(
 
   sp->density.wcount = 0.f;
   sp->density.wcount_dh = 0.f;
-  sp->rho_gas = 0.f;
 }
 
 /**
@@ -58,14 +56,15 @@ __attribute__((always_inline)) INLINE static void stars_init_spart(
  * This function is called only once just after the ICs have been
  * read in to do some conversions.
  *
- * @param sp The particle to act upon
+ * @param sp The particle to act upon.
+ * @param stars_properties Properties of the stars model.
  */
 __attribute__((always_inline)) INLINE static void stars_first_init_spart(
-    struct spart* sp) {
+    struct spart* sp, const struct stars_props* stars_properties) {
 
   sp->time_bin = 0;
-  sp->birth_density = -1.f;
-  sp->birth_time = -1.f;
+  sp->birth_density = 0.f;
+  sp->birth_time = stars_properties->spart_first_init_birth_time;
 
   stars_init_spart(sp);
 }
@@ -77,18 +76,7 @@ __attribute__((always_inline)) INLINE static void stars_first_init_spart(
  * @param dt_drift The drift time-step for positions.
  */
 __attribute__((always_inline)) INLINE static void stars_predict_extra(
-    struct spart* restrict sp, float dt_drift) {
-
-  // MATTHIEU
-  /* const float h_inv = 1.f / sp->h; */
-
-  /* /\* Predict smoothing length *\/ */
-  /* const float w1 = sp->feedback.h_dt * h_inv * dt_drift; */
-  /* if (fabsf(w1) < 0.2f) */
-  /*   sp->h *= approx_expf(w1); /\* 4th order expansion of exp(w) *\/ */
-  /* else */
-  /*   sp->h *= expf(w1); */
-}
+    struct spart* restrict sp, float dt_drift) {}
 
 /**
  * @brief Sets the values to be predicted in the drifts to their values at a
@@ -107,10 +95,7 @@ __attribute__((always_inline)) INLINE static void stars_reset_predicted_values(
  * @param sp The particle to act upon
  */
 __attribute__((always_inline)) INLINE static void stars_end_feedback(
-    struct spart* sp) {
-
-  sp->feedback.h_dt *= sp->h * hydro_dimension_inv;
-}
+    struct spart* sp) {}
 
 /**
  * @brief Kick the additional variables
@@ -137,7 +122,6 @@ __attribute__((always_inline)) INLINE static void stars_end_density(
   const float h_inv_dim_plus_one = h_inv_dim * h_inv; /* 1/h^(d+1) */
 
   /* Finish the calculation by inserting the missing h-factors */
-  sp->rho_gas *= h_inv_dim;
   sp->density.wcount *= h_inv_dim;
   sp->density.wcount_dh *= h_inv_dim_plus_one;
 }
@@ -155,22 +139,23 @@ __attribute__((always_inline)) INLINE static void stars_spart_has_no_neighbours(
   /* Re-set problematic values */
   sp->density.wcount = 0.f;
   sp->density.wcount_dh = 0.f;
-  sp->rho_gas = 0.f;
 }
 
 /**
- * @brief Evolve the stellar properties of a #spart.
+ * @brief Reset acceleration fields of a particle
  *
- * This function allows for example to compute the SN rate before sending
- * this information to a different MPI rank.
+ * This is the equivalent of hydro_reset_acceleration.
+ * We do not compute the acceleration on star, therefore no need to use it.
  *
- * @param sp The particle to act upon
- * @param cosmo The current cosmological model.
- * @param stars_properties The #stars_props
+ * @param p The particle to act upon
  */
-__attribute__((always_inline)) INLINE static void stars_evolve_spart(
-    struct spart* restrict sp, const struct stars_props* stars_properties,
-    const struct cosmology* cosmo) {}
+__attribute__((always_inline)) INLINE static void stars_reset_acceleration(
+    struct spart* restrict p) {
+
+#ifdef DEBUG_INTERACTIONS_STARS
+  p->num_ngb_force = 0;
+#endif
+}
 
 /**
  * @brief Reset acceleration fields of a particle
@@ -183,9 +168,6 @@ __attribute__((always_inline)) INLINE static void stars_evolve_spart(
 __attribute__((always_inline)) INLINE static void stars_reset_feedback(
     struct spart* restrict p) {
 
-  /* Reset time derivative */
-  p->feedback.h_dt = 0.f;
-
 #ifdef DEBUG_INTERACTIONS_STARS
   for (int i = 0; i < MAX_NUM_OF_NEIGHBOURS_STARS; ++i)
     p->ids_ngbs_force[i] = -1;
diff --git a/src/stars/EAGLE/stars_iact.h b/src/stars/EAGLE/stars_iact.h
index aad611f50424a5ff8965835d4a2363d49406eb1c..784fe241dcc19139596ba9d28955838f362518bf 100644
--- a/src/stars/EAGLE/stars_iact.h
+++ b/src/stars/EAGLE/stars_iact.h
@@ -19,6 +19,8 @@
 #ifndef SWIFT_EAGLE_STARS_IACT_H
 #define SWIFT_EAGLE_STARS_IACT_H
 
+#include "random.h"
+
 /**
  * @brief Density interaction between two particles (non-symmetric).
  *
@@ -32,13 +34,11 @@
  * @param H Current Hubble parameter.
  */
 __attribute__((always_inline)) INLINE static void
-runner_iact_nonsym_stars_density(float r2, const float *dx, float hi, float hj,
+runner_iact_nonsym_stars_density(const float r2, const float *dx,
+                                 const float hi, const float hj,
                                  struct spart *restrict si,
-                                 const struct part *restrict pj, float a,
-                                 float H) {
-
-  /* Get the gas mass. */
-  const float mj = hydro_get_mass(pj);
+                                 const struct part *restrict pj, const float a,
+                                 const float H) {
 
   float wi, wi_dx;
 
@@ -55,9 +55,6 @@ runner_iact_nonsym_stars_density(float r2, const float *dx, float hi, float hj,
   si->density.wcount += wi;
   si->density.wcount_dh -= (hydro_dimension * wi + ui * wi_dx);
 
-  /* Compute contribution to the density */
-  si->rho_gas += mj * wi;
-
 #ifdef DEBUG_INTERACTIONS_STARS
   /* Update ngb counters */
   if (si->num_ngb_density < MAX_NUM_OF_NEIGHBOURS_STARS)
@@ -68,19 +65,30 @@ runner_iact_nonsym_stars_density(float r2, const float *dx, float hi, float hj,
 
 /**
  * @brief Feedback interaction between two particles (non-symmetric).
+ * Used for updating properties of gas particles neighbouring a star particle
  *
  * @param r2 Comoving square distance between the two particles.
- * @param dx Comoving vector separating both particles (pi - pj).
+ * @param dx Comoving vector separating both particles (si - pj).
  * @param hi Comoving smoothing-length of particle i.
  * @param hj Comoving smoothing-length of particle j.
- * @param si First sparticle.
- * @param pj Second particle (not updated).
+ * @param si First (star) particle (not updated).
+ * @param pj Second (gas) particle.
  * @param a Current scale factor.
  * @param H Current Hubble parameter.
  */
 __attribute__((always_inline)) INLINE static void
-runner_iact_nonsym_stars_feedback(float r2, const float *dx, float hi, float hj,
-                                  struct spart *restrict si,
-                                  struct part *restrict pj, float a, float H) {}
+runner_iact_nonsym_stars_feedback(const float r2, const float *dx,
+                                  const float hi, const float hj,
+                                  const struct spart *restrict si,
+                                  struct part *restrict pj, const float a,
+                                  const float H) {
+
+#ifdef DEBUG_INTERACTIONS_STARS
+  /* Update ngb counters */
+  if (si->num_ngb_feedback < MAX_NUM_OF_NEIGHBOURS_STARS)
+    si->ids_ngbs_feedback[si->num_ngb_feedback] = pj->id;
+  ++si->num_ngb_feedback;
+#endif
+}
 
 #endif /* SWIFT_EAGLE_STARS_IACT_H */
diff --git a/src/stars/EAGLE/stars_io.h b/src/stars/EAGLE/stars_io.h
index d93b4bf7cf81c56bb65d7d5d8801f843a492ead0..df4810f12e8d6ec3997037eeb87d157418fb91a0 100644
--- a/src/stars/EAGLE/stars_io.h
+++ b/src/stars/EAGLE/stars_io.h
@@ -35,7 +35,7 @@ INLINE static void stars_read_particles(struct spart *sparts,
                                         int *num_fields) {
 
   /* Say how much we want to read */
-  *num_fields = 5;
+  *num_fields = 6;
 
   /* List what we want to read */
   list[0] = io_make_input_field("Coordinates", DOUBLE, 3, COMPULSORY,
@@ -48,6 +48,8 @@ INLINE static void stars_read_particles(struct spart *sparts,
                                 UNIT_CONV_NO_UNITS, sparts, id);
   list[4] = io_make_input_field("SmoothingLength", FLOAT, 1, OPTIONAL,
                                 UNIT_CONV_LENGTH, sparts, h);
+  list[5] = io_make_input_field("Masses", FLOAT, 1, COMPULSORY, UNIT_CONV_MASS,
+                                sparts, mass_init);
 }
 
 /**
@@ -62,7 +64,7 @@ INLINE static void stars_write_particles(const struct spart *sparts,
                                          int *num_fields) {
 
   /* Say how much we want to write */
-  *num_fields = 9;
+  *num_fields = 8;
 
   /* List what we want to write */
   list[0] = io_make_output_field("Coordinates", DOUBLE, 3, UNIT_CONV_LENGTH,
@@ -81,8 +83,6 @@ INLINE static void stars_write_particles(const struct spart *sparts,
                                  sparts, mass_init);
   list[7] = io_make_output_field("BirthTime", FLOAT, 1, UNIT_CONV_TIME, sparts,
                                  birth_time);
-  list[8] = io_make_output_field("GasDensity", FLOAT, 1, UNIT_CONV_DENSITY,
-                                 sparts, rho_gas);
 }
 
 /**
@@ -95,12 +95,14 @@ INLINE static void stars_write_particles(const struct spart *sparts,
  * @param us The internal unit system.
  * @param params The parsed parameters.
  * @param p The already read-in properties of the hydro scheme.
+ * @param cosmo The cosmological model.
  */
 INLINE static void stars_props_init(struct stars_props *sp,
                                     const struct phys_const *phys_const,
                                     const struct unit_system *us,
                                     struct swift_params *params,
-                                    const struct hydro_props *p) {
+                                    const struct hydro_props *p,
+                                    const struct cosmology *cosmo) {
 
   /* Kernel properties */
   sp->eta_neighbours = parser_get_opt_param_float(
@@ -121,9 +123,6 @@ INLINE static void stars_props_init(struct stars_props *sp,
   sp->max_smoothing_iterations = parser_get_opt_param_int(
       params, "Stars:max_ghost_iterations", p->max_smoothing_iterations);
 
-  /* Initialize with solar abundance */
-  // sp->chemistry_data.smoothed_metal_mass_fraction_total =
-
   /* Time integration properties */
   const float max_volume_change =
       parser_get_opt_param_float(params, "Stars:max_volume_change", -1);
@@ -131,6 +130,11 @@ INLINE static void stars_props_init(struct stars_props *sp,
     sp->log_max_h_change = p->log_max_h_change;
   else
     sp->log_max_h_change = logf(powf(max_volume_change, hydro_dimension_inv));
+
+  /* Read birth time to set all stars in ICs to (defaults to -1 to indicate star
+   * present in ICs) */
+  sp->spart_first_init_birth_time =
+      parser_get_opt_param_float(params, "Stars:birth_time", -1);
 }
 
 /**
diff --git a/src/stars/EAGLE/stars_part.h b/src/stars/EAGLE/stars_part.h
index 664b5c0d03dd5b762aab0a0f582f22312b2196c6..fce47de63c2b76d907cc8da905d91b6999d9e41f 100644
--- a/src/stars/EAGLE/stars_part.h
+++ b/src/stars/EAGLE/stars_part.h
@@ -23,8 +23,9 @@
 /* Some standard headers. */
 #include <stdlib.h>
 
-/* Read chemistry */
+/* Read additional aubgrid models */
 #include "chemistry_struct.h"
+#include "feedback_struct.h"
 #include "tracers_struct.h"
 
 /**
@@ -61,12 +62,6 @@ struct spart {
   /*! Particle smoothing length. */
   float h;
 
-  /*! Density of the gas surrounding the star. */
-  float rho_gas;
-
-  /*! Particle time bin */
-  timebin_t time_bin;
-
   struct {
 
     /* Number of neighbours. */
@@ -77,14 +72,7 @@ struct spart {
 
   } density;
 
-  struct {
-
-    /* Change in smoothing length over time. */
-    float h_dt;
-
-  } feedback;
-
-  /*! Union for the birth time and birht scale factor */
+  /*! Union for the birth time and birth scale factor */
   union {
 
     /*! Birth time */
@@ -97,12 +85,18 @@ struct spart {
   /*! Birth density */
   float birth_density;
 
+  /*! Feedback structure */
+  struct feedback_spart_data feedback_data;
+
   /*! Tracer structure */
   struct tracers_xpart_data tracers_data;
 
   /*! Chemistry structure */
   struct chemistry_part_data chemistry_data;
 
+  /*! Particle time bin */
+  timebin_t time_bin;
+
 #ifdef SWIFT_DEBUG_CHECKS
 
   /* Time of the last drift */
@@ -114,11 +108,18 @@ struct spart {
 #endif
 
 #ifdef DEBUG_INTERACTIONS_STARS
-  /*! List of interacting particles in the density SELF and PAIR */
-  long long ids_ngbs_density[MAX_NUM_OF_NEIGHBOURS_STARS];
 
   /*! Number of interactions in the density SELF and PAIR */
   int num_ngb_density;
+
+  /*! List of interacting particles in the density SELF and PAIR */
+  long long ids_ngbs_density[MAX_NUM_OF_NEIGHBOURS_STARS];
+
+  /*! Number of interactions in the force SELF and PAIR */
+  int num_ngb_force;
+
+  /*! List of interacting particles in the force SELF and PAIR */
+  long long ids_ngbs_force[MAX_NUM_OF_NEIGHBOURS_STARS];
 #endif
 
 } SWIFT_STRUCT_ALIGN;
@@ -131,7 +132,7 @@ struct stars_props {
   /*! Resolution parameter */
   float eta_neighbours;
 
-  /*! Target weightd number of neighbours (for info only)*/
+  /*! Target weighted number of neighbours (for info only)*/
   float target_neighbours;
 
   /*! Smoothing length tolerance */
@@ -145,6 +146,9 @@ struct stars_props {
 
   /*! Maximal change of h over one time-step */
   float log_max_h_change;
+
+  /*! Value to set birth time of stars read from ICs */
+  float spart_first_init_birth_time;
 };
 
 #endif /* SWIFT_EAGLE_STAR_PART_H */
diff --git a/src/stars_io.h b/src/stars_io.h
index c2a095c47c8d491fe6cf97d22c367d1e9d4a7fd6..18224b1ef9a189c719d3674a037eb4b26cd14d4e 100644
--- a/src/stars_io.h
+++ b/src/stars_io.h
@@ -23,7 +23,9 @@
 #include "./const.h"
 
 /* Load the correct star type */
-#if defined(STARS_NONE)
+#if defined(FEEDBACK_CONST)
+#include "./stars/const/stars_io.h"
+#elif defined(STARS_NONE)
 #include "./stars/Default/stars_io.h"
 #elif defined(STARS_EAGLE)
 #include "./stars/EAGLE/stars_io.h"
diff --git a/src/swift.h b/src/swift.h
index b63eafc574c78ee0808ff4ed9df2f4f0dcbc9097..cd7159e63d129e97f8aac5c8d426fd041bd298b0 100644
--- a/src/swift.h
+++ b/src/swift.h
@@ -40,6 +40,8 @@
 #include "engine.h"
 #include "entropy_floor.h"
 #include "error.h"
+#include "feedback.h"
+#include "feedback_properties.h"
 #include "gravity.h"
 #include "gravity_derivatives.h"
 #include "gravity_properties.h"
diff --git a/src/timestep.h b/src/timestep.h
index 40750c07f1309289303375dcaa890ea5c3f556d0..c2b1a10fcb3b0426e7c34625d65c1fd5353d25e9 100644
--- a/src/timestep.h
+++ b/src/timestep.h
@@ -201,14 +201,8 @@ __attribute__((always_inline)) INLINE static integertime_t get_spart_timestep(
     new_dt_self = gravity_compute_timestep_self(
         sp->gpart, a_hydro, e->gravity_properties, e->cosmology);
 
-  /* Limit change in smoothing length */
-  const float dt_h_change = (sp->feedback.h_dt != 0.0f)
-                                ? fabsf(e->stars_properties->log_max_h_change *
-                                        sp->h / sp->feedback.h_dt)
-                                : FLT_MAX;
-
   /* Take the minimum of all */
-  float new_dt = min4(new_dt_stars, new_dt_self, new_dt_ext, dt_h_change);
+  float new_dt = min3(new_dt_stars, new_dt_self, new_dt_ext);
 
   /* Apply the maximal displacement constraint (FLT_MAX  if non-cosmological)*/
   new_dt = min(new_dt, e->dt_max_RMS_displacement);
diff --git a/src/timestep_limiter.h b/src/timestep_limiter.h
index db5e044132370c273f66aefd8e2d116642b28a73..d8555a352c8e1a799ac13d268932c9d37f30fe33 100644
--- a/src/timestep_limiter.h
+++ b/src/timestep_limiter.h
@@ -107,6 +107,7 @@ __attribute__((always_inline)) INLINE static integertime_t timestep_limit_part(
     dt_kick_therm = -(old_dti / 2) * time_base;
     dt_kick_corr = -(old_dti / 2) * time_base;
   }
+
   kick_part(p, xp, dt_kick_hydro, dt_kick_grav, dt_kick_therm, dt_kick_corr,
             e->cosmology, e->hydro_properties, e->entropy_floor,
             old_ti_beg + old_dti / 2, old_ti_beg);
@@ -127,6 +128,7 @@ __attribute__((always_inline)) INLINE static integertime_t timestep_limit_part(
     dt_kick_therm = (new_dti / 2) * time_base;
     dt_kick_corr = (new_dti / 2) * time_base;
   }
+
   kick_part(p, xp, dt_kick_hydro, dt_kick_grav, dt_kick_therm, dt_kick_corr,
             e->cosmology, e->hydro_properties, e->entropy_floor, new_ti_beg,
             new_ti_beg + new_dti / 2);
diff --git a/src/tools.c b/src/tools.c
index 457b7eae2490362feabaf8555217d17d766269c6..7290abc063c58a8b2d85b1137d23d3f647dbf456 100644
--- a/src/tools.c
+++ b/src/tools.c
@@ -644,6 +644,7 @@ void self_all_force(struct runner *r, struct cell *ci) {
 }
 
 void self_all_stars_density(struct runner *r, struct cell *ci) {
+
   float r2, hi, hj, hig2, dxi[3];
   struct spart *spi;
   struct part *pj;
diff --git a/tests/Makefile.am b/tests/Makefile.am
index f18b6c44c63f6e394bc2b47616f86da5dbcd54e2..5f95e7d8c1d7f8cf78a9207b6b4ac374a0b87745 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -41,7 +41,7 @@ check_PROGRAMS = testGreetings testReading testSingle testTimeIntegration \
 		 testVoronoi1D testVoronoi2D testVoronoi3D testPeriodicBC \
 		 testGravityDerivatives testPotentialSelf testPotentialPair testEOS testUtilities \
 		 testSelectOutput testCbrt testCosmology testOutputList test27cellsStars \
-		 test27cellsStars_subset testCooling
+		 test27cellsStars_subset testCooling testFeedback
 
 # Rebuild tests when SWIFT is updated.
 $(check_PROGRAMS): ../src/.libs/libswiftsim.a
@@ -132,6 +132,8 @@ testUtilities_SOURCES = testUtilities.c
 
 testCooling_SOURCES = testCooling.c
 
+testFeedback_SOURCES = testFeedback.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/testFeedback.c b/tests/testFeedback.c
new file mode 100644
index 0000000000000000000000000000000000000000..56b4fedf7734ee25f67626bb2fd0aa7fc98571d3
--- /dev/null
+++ b/tests/testFeedback.c
@@ -0,0 +1,279 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Copyright (C) 2015 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/>.
+ *
+ ******************************************************************************/
+
+#include "swift.h"
+
+#if defined(STARS_EAGLE) && defined(FEEDBACK_EAGLE)
+/**
+ * @brief compute the relative error between two floats
+ *
+ * @param a, b numbers between which to compute the relative difference
+ */
+float relative_error(float a, float b) { return fabs((a - b) / b); }
+
+/**
+ * @brief Test function to check feedback is working correctly. Produces a table
+ * of values for the cumulative amount of mass enrichment up to a given time
+ * from the birth of the star (normalized by the initial stellar mass). Compares
+ * these results to those produced by an analogous test in EAGLE.
+ */
+int main(int argc, char *argv[]) {
+
+  /* Declare relevant structs */
+  struct swift_params *params = malloc(sizeof(struct swift_params));
+  struct unit_system us;
+  struct chemistry_global_data chem_data;
+  struct part p;
+  struct xpart xp;
+  struct spart sp;
+  struct phys_const phys_const;
+  struct cosmology cosmo;
+  struct hydro_props hydro_properties;
+  struct stars_props stars_properties;
+  struct feedback_props feedback_properties;
+  char *parametersFileName = "./testFeedback.yml";
+
+  /* Read the parameter file */
+  if (params == NULL) error("Error allocating memory for the parameter file.");
+  message("Reading runtime parameters from file '%s'", parametersFileName);
+  parser_read_file(parametersFileName, params);
+
+  /* Init units */
+  units_init_from_params(&us, params, "InternalUnitSystem");
+  phys_const_init(&us, params, &phys_const);
+
+  /* Init chemistry */
+  chemistry_init(params, &us, &phys_const, &chem_data);
+  chemistry_first_init_part(&phys_const, &us, &cosmo, &chem_data, &p, &xp);
+  chemistry_print(&chem_data);
+
+  /* Init cosmology */
+  cosmology_init(params, &us, &phys_const, &cosmo);
+  cosmology_print(&cosmo);
+
+  /* Init hydro properties */
+  hydro_props_init(&hydro_properties, &phys_const, &us, params);
+
+  /* Init star properties */
+  stars_props_init(&stars_properties, &phys_const, &us, params,
+                   &hydro_properties, &cosmo);
+
+  /* Init star properties */
+  feedback_props_init(&feedback_properties, &phys_const, &us, params,
+                      &hydro_properties, &cosmo);
+
+  /* Init spart */
+  stars_first_init_spart(&sp, &stars_properties);
+
+  /* Define an initial stellar mass. (for use when calling the feedback
+   * functions, the results are presented per initial stellar mass, so the
+   * actual value does not matter. */
+  sp.mass_init = 4.706273e-5;
+
+  /* Set metal mass fractions */
+  for (int i = 0; i < chemistry_element_count; i++)
+    sp.chemistry_data.metal_mass_fraction[i] = 0.f;
+  sp.chemistry_data.metal_mass_fraction[0] = 0.752;
+  sp.chemistry_data.metal_mass_fraction[1] = 0.248;
+  sp.chemistry_data.metal_mass_fraction_total = 0.01;
+
+  /* Define how long to run for and what interval should be between consecutive
+   * times for which feedback is calculated for */
+  float Gyr_to_s = 3.154e16;
+  float dt = 0.1 * Gyr_to_s / units_cgs_conversion_factor(&us, UNIT_CONV_TIME);
+  float max_age =
+      13.f * Gyr_to_s / units_cgs_conversion_factor(&us, UNIT_CONV_TIME);
+
+  /* Zero feedback quantities */
+  for (int i = 0; i < chemistry_element_count; i++)
+    sp.feedback_data.to_distribute.metal_mass[i] = 0.f;
+  sp.feedback_data.to_distribute.metal_mass_from_SNIa = 0.f;
+  sp.feedback_data.to_distribute.metal_mass_from_SNII = 0.f;
+  sp.feedback_data.to_distribute.metal_mass_from_AGB = 0.f;
+  sp.feedback_data.to_distribute.mass_from_AGB = 0.f;
+  sp.feedback_data.to_distribute.mass_from_SNII = 0.f;
+  sp.feedback_data.to_distribute.mass_from_SNIa = 0.f;
+  sp.feedback_data.to_distribute.Fe_mass_from_SNIa = 0.f;
+  sp.feedback_data.to_distribute.total_metal_mass = 0.f;
+  sp.feedback_data.to_distribute.mass = 0.f;
+
+  /* Open EAGLE test file for reading  */
+  FILE *EAGLE_test;
+  const char EAGLE_fname[75] =
+      "/cosma/home/dp004/dc-bori1/Eagle/data1/z_0.01/StellarEvolutionTotal.txt";
+  if (!(EAGLE_test = fopen(EAGLE_fname, "r"))) {
+    error("error in opening file '%s'\n", EAGLE_fname);
+  }
+
+  /* Declare constants necessary for reading EAGLE data */
+  char *line = NULL;
+  size_t len = 0;
+  const int n_fields = 19;
+  float tol = 1e-5;
+
+  /* Declare array to store one line of data from EAGLE test */
+  float eagle_data[n_fields];
+
+  /* read first line */
+  if (getline(&line, &len, EAGLE_test) == -1)
+    error("failed to read first line of EAGLE test file");
+
+  /* Open file for writing SWIFT feedback test output */
+  FILE *Total_output;
+  const char Total_fname[25] = "test_feedback_total.txt";
+  if (!(Total_output = fopen(Total_fname, "w"))) {
+    error("error in opening file '%s'\n", Total_fname);
+  }
+  fprintf(Total_output,
+          "# time[Gyr] | total mass | metal mass: total | H | He | C | N  | O  "
+          "| Ne | Mg | Si | Fe | per solar mass (m,z)_AGB (m,z)_SNII "
+          "(m,z,M_fe)_SNIa \n");
+
+  /* Loop over times for which to calculate feedback */
+  for (float age = 0; age <= max_age; age += dt) {
+
+    /* Compute feedback */
+    compute_stellar_evolution(&feedback_properties, &cosmo, &sp, &us, age, dt);
+
+    /* Print computed values to file */
+    float age_Gyr =
+        age * units_cgs_conversion_factor(&us, UNIT_CONV_TIME) / Gyr_to_s;
+    fprintf(Total_output, "%f %e %e ", age_Gyr,
+            sp.feedback_data.to_distribute.mass / sp.mass_init,
+            sp.feedback_data.to_distribute.total_metal_mass / sp.mass_init);
+    for (int i = 0; i < chemistry_element_count; i++)
+      fprintf(Total_output, "%e ",
+              sp.feedback_data.to_distribute.metal_mass[i] / sp.mass_init);
+    fprintf(Total_output, " %e %e %e %e %e %e %e",
+            sp.feedback_data.to_distribute.mass_from_AGB / sp.mass_init,
+            sp.feedback_data.to_distribute.metal_mass_from_AGB / sp.mass_init,
+            sp.feedback_data.to_distribute.mass_from_SNII / sp.mass_init,
+            sp.feedback_data.to_distribute.metal_mass_from_SNII / sp.mass_init,
+            sp.feedback_data.to_distribute.mass_from_SNIa / sp.mass_init,
+            sp.feedback_data.to_distribute.metal_mass_from_SNIa / sp.mass_init,
+            sp.feedback_data.to_distribute.Fe_mass_from_SNIa / sp.mass_init);
+    fprintf(Total_output, "\n");
+
+    /* Read data from EAGLE test and compare it to what we calculated */
+    if (!feof(EAGLE_test)) {
+      int ret = fscanf(
+          EAGLE_test,
+          "%e %e %e %e %e %e %e %e %e %e %e %e %e %e %e %e %e %e %e ",
+          &eagle_data[0], &eagle_data[1], &eagle_data[2], &eagle_data[3],
+          &eagle_data[4], &eagle_data[5], &eagle_data[6], &eagle_data[7],
+          &eagle_data[8], &eagle_data[9], &eagle_data[10], &eagle_data[11],
+          &eagle_data[12], &eagle_data[13], &eagle_data[14], &eagle_data[15],
+          &eagle_data[16], &eagle_data[17], &eagle_data[18]);
+      if (ret == 0) error("Error reading input.");
+      if (relative_error(age_Gyr, eagle_data[0]) > tol)
+        error(
+            "relative error in age greater than tolerance. Swift: %e Eagle %e",
+            age_Gyr, eagle_data[0]);
+      if (relative_error(sp.feedback_data.to_distribute.mass / sp.mass_init,
+                         eagle_data[1]) > tol)
+        error(
+            "relative error in total mass greater than tolerance. Swift: %e "
+            "Eagle %e",
+            sp.feedback_data.to_distribute.mass / sp.mass_init, eagle_data[1]);
+      if (relative_error(
+              sp.feedback_data.to_distribute.total_metal_mass / sp.mass_init,
+              eagle_data[2]) > tol)
+        error(
+            "relative error in total metal mass greater than tolerance. Swift: "
+            "%e Eagle %e",
+            sp.feedback_data.to_distribute.total_metal_mass / sp.mass_init,
+            eagle_data[2]);
+      for (int i = 0; i < chemistry_element_count; i++)
+        if (relative_error(
+                sp.feedback_data.to_distribute.metal_mass[i] / sp.mass_init,
+                eagle_data[3 + i]) > tol)
+          error(
+              "relative error in mass released for element %d greater than "
+              "tolerance. Swift: %e Eagle %e",
+              i, age_Gyr, eagle_data[3 + i]);
+      if (relative_error(
+              sp.feedback_data.to_distribute.mass_from_AGB / sp.mass_init,
+              eagle_data[12]) > tol)
+        error(
+            "relative error in mass from AGB greater than tolerance. Swift: %e "
+            "Eagle %e",
+            sp.feedback_data.to_distribute.mass_from_AGB / sp.mass_init,
+            eagle_data[12]);
+      if (relative_error(
+              sp.feedback_data.to_distribute.metal_mass_from_AGB / sp.mass_init,
+              eagle_data[13]) > tol)
+        error(
+            "relative error in metal mass from AGB greater than tolerance. "
+            "Swift: %e Eagle %e",
+            sp.feedback_data.to_distribute.metal_mass_from_AGB / sp.mass_init,
+            eagle_data[13]);
+      if (relative_error(
+              sp.feedback_data.to_distribute.mass_from_SNII / sp.mass_init,
+              eagle_data[14]) > tol)
+        error(
+            "relative error in mass from SNII greater than tolerance. Swift: "
+            "%e Eagle %e",
+            sp.feedback_data.to_distribute.mass_from_SNII / sp.mass_init,
+            eagle_data[14]);
+      if (relative_error(sp.feedback_data.to_distribute.metal_mass_from_SNII /
+                             sp.mass_init,
+                         eagle_data[15]) > tol)
+        error(
+            "relative error in metal mass from SNII greater than tolerance. "
+            "Swift: %e Eagle %e",
+            sp.feedback_data.to_distribute.metal_mass_from_SNII / sp.mass_init,
+            eagle_data[15]);
+      if (relative_error(
+              sp.feedback_data.to_distribute.mass_from_SNIa / sp.mass_init,
+              eagle_data[16]) > tol)
+        error(
+            "relative error in mass from SNIa greater than tolerance. Swift: "
+            "%e Eagle %e",
+            sp.feedback_data.to_distribute.mass_from_SNIa / sp.mass_init,
+            eagle_data[16]);
+      if (relative_error(sp.feedback_data.to_distribute.metal_mass_from_SNIa /
+                             sp.mass_init,
+                         eagle_data[17]) > tol)
+        error(
+            "relative error in metal mass from SNIa greater than tolerance. "
+            "Swift: %e Eagle %e",
+            sp.feedback_data.to_distribute.metal_mass_from_SNIa / sp.mass_init,
+            eagle_data[17]);
+      if (relative_error(
+              sp.feedback_data.to_distribute.Fe_mass_from_SNIa / sp.mass_init,
+              eagle_data[18]) > tol)
+        error(
+            "relative error in iron mass from SNIa greater than tolerance. "
+            "Swift: %e Eagle %e",
+            sp.feedback_data.to_distribute.Fe_mass_from_SNIa / sp.mass_init,
+            eagle_data[18]);
+    } else {
+      error("Failed to read line of EAGLE test file data");
+    }
+  }
+
+  return 0;
+}
+
+#else
+
+/* Don't do anything if not using EAGLE stars */
+int main(int argc, char *argv[]) { return 0; }
+
+#endif
diff --git a/tests/testFeedback.yml b/tests/testFeedback.yml
new file mode 100644
index 0000000000000000000000000000000000000000..af1b2cb531bef7b02544765553b1337b440f269e
--- /dev/null
+++ b/tests/testFeedback.yml
@@ -0,0 +1,30 @@
+# Define the system of units to use internally. 
+InternalUnitSystem:
+  UnitMass_in_cgs:     1.98848e43    # 10^10 M_sun in grams
+  UnitLength_in_cgs:   3.08567758e24 # Mpc in centimeters
+  UnitVelocity_in_cgs: 1e5   # km/s in centimeters per second
+  UnitCurrent_in_cgs:  1.   # Amperes
+  UnitTemp_in_cgs:     1.   # Kelvin
+
+# Cosmological parameters
+Cosmology:
+  h:              0.6777        # Reduced Hubble constant
+  a_begin:        0.5           # 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
+
+# Parameters for the hydrodynamics scheme
+SPH:
+  resolution_eta:        1.2348   # Target smoothing length in units of the mean inter-particle separation 
+  CFL_condition:         0.1      # Courant-Friedrich-Levy condition for time integration.
+
+EAGLEFeedback:
+  filename:     /cosma5/data/Eagle/BG_Tables/YieldTables/
+  imf_model:    Chabrier
+  continuous_heating_switch: 0
+  SNIa_timescale_Gyr:        2.0
+  SNIa_efficiency:           2.e-3
+  SNII_wind_delay_Gyr:       0.03
+  SNe_heating_temperature_K: 3.16228e7
diff --git a/theory/Talks/SPHERIC_2013/eagle_50.png b/theory/Talks/SPHERIC_2013/eagle_50.png
deleted file mode 100644
index ab40f1c2ecf6a82266f1a1f9ccd0ea8a285c938a..0000000000000000000000000000000000000000
Binary files a/theory/Talks/SPHERIC_2013/eagle_50.png and /dev/null differ