diff --git a/examples/MHDTests/CoolingHaloWithSpin_MHD/1Dprofiles.py b/examples/MHDTests/CoolingHaloWithSpin_MHD/1Dprofiles.py
index ee568c98ee39df18e615f2c750589a68f2f81294..f47a488a905f39ce0e38149d1d5e30241c618f70 100644
--- a/examples/MHDTests/CoolingHaloWithSpin_MHD/1Dprofiles.py
+++ b/examples/MHDTests/CoolingHaloWithSpin_MHD/1Dprofiles.py
@@ -18,8 +18,8 @@ GYR_IN_CGS = 3.1536e16  # gigayear
 # First set unit velocity and then the circular velocity parameter for the isothermal potential
 const_unit_velocity_in_cgs = 1.0e5  # kms^-1
 
-h = 0.681  # 0.67777  # hubble parameter
-H_0_cgs = 100.0 * h * KM_PER_SEC_IN_CGS / (1.0e6 * PARSEC_IN_CGS)
+h_dim = 0.704 #0.681  # 0.67777  # hubble parameter
+H_0_cgs = 100.0 * h_dim * KM_PER_SEC_IN_CGS / (1.0e6 * PARSEC_IN_CGS)
 
 # From this we can find the virial radius, the radius within which the average density of the halo is
 # 200. * the mean matter density
@@ -28,7 +28,7 @@ H_0_cgs = 100.0 * h * KM_PER_SEC_IN_CGS / (1.0e6 * PARSEC_IN_CGS)
 f_b = 0.17
 c_200 = 7.2
 spin_lambda = 0.05
-nH_max_cgs = 1e0
+nH_max_cgs = 1e2
 M_200_cgs = 1e12 * MSOL_IN_CGS
 rhoc_cgs = 3 * H_0_cgs ** 2 / (8 * np.pi * CONST_G_CGS)
 r_200_cgs = (3 * M_200_cgs / (4 * np.pi * rhoc_cgs * 200)) ** (1 / 3)
@@ -79,76 +79,43 @@ n_gas = data.metadata.n_gas
 rho = data.gas.densities
 m = data.gas.masses
 coords = data.gas.coordinates
+coords_center = coords - data.metadata.boxsize / 2
+radius = np.linalg.norm(coords_center,axis=1)
 velocities = data.gas.velocities
-l = np.vstack([m, m, m]).T * np.cross(
-    (coords - data.metadata.boxsize / 2), velocities
-)  # specific angular momentum
-rho.convert_to_units(unyt.g * unyt.cm ** (-3))
+
+# calculate specific angular momentum j(r)
+rotation_axis = np.array([0,0,1])
+e_phi = np.cross(rotation_axis[None,:],coords_center)
+e_phi = e_phi/np.linalg.norm(e_phi,axis=1)[:,None]
+v_phi = velocities[:,0]*e_phi[:,0]+velocities[:,1]*e_phi[:,1]+velocities[:,2]*e_phi[:,2]
+e_r = np.cross(e_phi,rotation_axis[None,:])
+axis_dist = coords_center[:,0]*e_r[:,0]+coords_center[:,1]*e_r[:,1]+coords_center[:,2]*e_r[:,2]
+j = v_phi * radius**2 / axis_dist
+omega = v_phi / axis_dist
+Jtot = np.sum(omega * axis_dist**2 * m)
 
 P = data.gas.pressures
 T = data.gas.temperatures
-
 B = data.gas.magnetic_flux_densities
-
 Bx, By = B[:, 0], B[:, 1]
-
 normB = np.sqrt(B[:, 0] ** 2 + B[:, 1] ** 2 + B[:, 2] ** 2)
-
 divB = data.gas.magnetic_divergences
-
 h = data.gas.smoothing_lengths
-
 errB = np.log10(h * abs(divB) / normB)
 
-# Generate mass weighted maps of quantities of interest
-data.gas.mass_weighted_densities = data.gas.masses * rho
-
-data.gas.mass_weighted_pressures = data.gas.masses * P
-
-data.gas.mass_weighted_Bx = data.gas.masses * Bx
 
-data.gas.mass_weighted_By = data.gas.masses * By
+rho_units = unyt.g * unyt.cm ** (-3)
+r_units = 1e3 * PARSEC_IN_CGS * unyt.cm
+P_units = MSOL_IN_CGS / PARSEC_IN_CGS / GYR_IN_CGS ** 2 * (unyt.g / (unyt.cm * unyt.s**2))
+j_units =  (1e3 * PARSEC_IN_CGS) / GYR_IN_CGS * (unyt.cm**2/unyt.s) 
+nH_units = unyt.cm ** (-3)
 
-data.gas.mass_weighted_errB = data.gas.masses * errB
-
-data.gas.mass_weighted_T = data.gas.masses * T
-
-common_arguments = dict(
-    data=data, z_slice=0.5 * data.metadata.boxsize[2], resolution=512, parallel=True
-)
-
-mass_map = slice_gas(**common_arguments, project="masses")
-
-mass_weighted_density_map = slice_gas(
-    **common_arguments, project="mass_weighted_densities"
-)
-
-mass_weighted_pressure_map = slice_gas(
-    **common_arguments, project="mass_weighted_pressures"
-)
-
-mass_weighted_Bx_map = slice_gas(**common_arguments, project="mass_weighted_Bx")
-
-mass_weighted_By_map = slice_gas(**common_arguments, project="mass_weighted_By")
-
-mass_weighted_errB_map = slice_gas(**common_arguments, project="mass_weighted_errB")
-mass_weighted_T_map = slice_gas(**common_arguments, project="mass_weighted_T")
-
-# Take out mass dependence
-density_map = mass_weighted_density_map / mass_map
-pressure_map = mass_weighted_pressure_map / mass_map
-Bx_map = mass_weighted_Bx_map / mass_map
-By_map = mass_weighted_By_map / mass_map
-errB_map = mass_weighted_errB_map / mass_map
-T_map = mass_weighted_T_map / mass_map
-
-map_pixel_length = len(mass_map)
-
-n_H = density_map / m_H_cgs
-
-x = np.linspace(0.0, 1.0, map_pixel_length)
-slice_ind = int(np.round(y0 * map_pixel_length, 0))
+rho.convert_to_units(rho_units)
+P.convert_to_units(P_units)
+j.convert_to_units(j_units)
+n_H = rho/(m_H_cgs * unyt.g)
 
+radius = np.linalg.norm(coords_center,axis=1)
 
 # Plot maps
 plt.rcParams.update({"font.size": 16})
@@ -158,42 +125,19 @@ ny = 4
 fig, axs = plt.subplots(ny, nx, figsize=((10 * nx, 5 * ny)))
 fig.subplots_adjust(hspace=0.1)
 
-Lbox_kpc = data.metadata.boxsize.to(PARSEC_IN_CGS * 1e3 * unyt.cm).value[0]
-# locs = [map_pixel_length / 4, map_pixel_length / 2, 3 * map_pixel_length / 4]
-# labels = [-Lbox_kpc / 4, 0, Lbox_kpc / 4]
-x = np.linspace(-Lbox_kpc / 2, Lbox_kpc / 2, map_pixel_length)
-slice_ind = int(np.floor(y0 * map_pixel_length))
-
 # plot density
-axs[0].plot(x, n_H[:, slice_ind], "k-", color="black")
+axs[0].scatter(radius.to(r_units), n_H.to(nH_units), s=0.1, color='black')
 axs[0].set_yscale("log")
 axs[0].set_yticks(np.logspace(-7, 2, 10))
 axs[0].set_ylim(1e-7, 1e2)
 
-# plot temperature
-P = pressure_map[:, slice_ind].to(
-    MSOL_IN_CGS * unyt.g / (PARSEC_IN_CGS * unyt.cm * (GYR_IN_CGS * unyt.s) ** 2)
-)
-axs[1].plot(x, P, "k-", color="black")
+# plot Pressure
+axs[1].scatter(radius.to(r_units), P.to(P_units), s=0.1, color='black')
 axs[1].set_yscale("log")
 
-# plot mass
-coords = coords.to(1e3 * PARSEC_IN_CGS * unyt.cm).value - Lbox_kpc / 2
-r_values = np.logspace(np.log10(1e-6), np.log10(Lbox_kpc / 2), 100)
-rp_kpc = np.linalg.norm(coords, axis=1)
-m = data.gas.masses.to(MSOL_IN_CGS * unyt.g).value
-M_x = np.array([np.sum(m[rp_kpc <= r_values[i]]) for i in range(len(r_values))])
-axs[2].scatter(r_values, M_x, color="black", marker="+", s=100)
-
 # plot specific angular momentum
-l_units_cgs = (
-    const_unit_mass_in_cgs * const_unit_length_in_cgs * const_unit_velocity_in_cgs
-)
-l = l.to(l_units_cgs * unyt.g * unyt.cm ** 2 / unyt.s).value
-L_r = np.array([np.sum(l[rp_kpc <= r_values[i]], axis=0) for i in range(len(r_values))])
-norm_L_r = np.sqrt(L_r[:, 0] ** 2 + L_r[:, 1] ** 2 + L_r[:, 2] ** 2)
-# axs[3].scatter(r_values,norm_L_r,color='black', marker='+',s=100)
-
+axs[2].scatter(radius.to(r_units), j.to(j_units), s=0.1, color='black')
+axs[2].set_yscale("log")
 
 # NFW-like gas density profile
 def rho_r(r_value, f_b, M_200_cgs, r_200_cgs, c_200):
@@ -273,100 +217,116 @@ def T_vs_r(P0_cgs, r_value, r_max, f_b, M_200_cgs, r_200_cgs, c_200):
     )
     return result_cgs
 
+# define specific angular momentum distribution
+def j(r_value, j_max, s, f_b, M_200_cgs, r_200_cgs, c_200):
+    return (
+        j_max
+        * (Mgas_r(r_value, f_b, M_200_cgs, r_200_cgs, c_200) / (M_200_cgs * f_b)) ** s
+    )
+def jsimple(r_value, j_max, s, f_b, M_200_cgs, r_200_cgs, c_200):
+    return (
+        j_max
+        * r_value**s
+    )
 
-r_200_kpc = r_200_cgs / (PARSEC_IN_CGS * 1e3)
-n_H_analytic = rho_r(np.abs(x) / r_200_kpc, f_b, M_200_cgs, r_200_cgs, c_200) / m_H_cgs
-M_gas_analytic = (
-    Mgas_r(np.abs(x) / r_200_kpc, f_b, M_200_cgs, r_200_cgs, c_200) / MSOL_IN_CGS
-)
 
-# Angular momentum
-Total_E = v_200 ** 2 / 2.0
-J_cgs = (
-    spin_lambda
-    * const_G
-    / np.sqrt(Total_E)
-    * const_unit_length_in_cgs
-    * const_unit_velocity_in_cgs
-)
+rmax = (r_200_cgs*unyt.cm).to(radius.units) #np.max(radius)
+rmin = np.min(radius) 
+r_analytic = np.logspace(np.log10(rmin.value),np.log10(rmax.value),1000)*radius.units
+#r_analytic = np.linspace(rmin.value,rmax.value,10000)*radius.units
+rho_analytic = rho_r((r_analytic/(r_200_cgs*unyt.cm)).value, f_b, M_200_cgs, r_200_cgs, c_200) 
+Mgas_analytic = Mgas_r((r_analytic/(r_200_cgs*unyt.cm)).value, f_b, M_200_cgs, r_200_cgs, c_200)
+nH_analytic = rho_analytic/m_H_cgs * nH_units
 
-L_200_cgs = (
-    J_cgs * M_200_cgs * f_b
-)  # np.linalg.norm(np.sum(l[rp_kpc<=r_200_kpc],axis=0))
-Mass_ratio = Mgas_r(np.abs(x) / r_200_kpc, f_b, M_200_cgs, r_200_cgs, c_200) / (
-    f_b * M_200_cgs
-)
-L_analytic = Mass_ratio * L_200_cgs / l_units_cgs
 
-# Gas parameters
-gamma = 5.0 / 3.0
 T0_cgs = (
     T_200_cgs
 )  # 1e5 # gas temperature on the edge of the box (if we want to set this manually)
-
 rho0_cgs = rho_r(
-    Lbox_kpc / r_200_kpc * np.sqrt(3) / 2, f_b, M_200_cgs, r_200_cgs, c_200
-)  # gas density on the edge
-P0_cgs = rho0_cgs * kb_cgs * T0_cgs / m_H_cgs  # gas pressure on the edge of the box
+    (rmax/(r_200_cgs*unyt.cm)).value, f_b, M_200_cgs, r_200_cgs, c_200
+) 
 
-Pressure_UNIT = MSOL_IN_CGS / PARSEC_IN_CGS / GYR_IN_CGS ** 2
-P_analytic = [
+P0_cgs = rho0_cgs * kb_cgs * T0_cgs / m_H_cgs  # gas pressure on the edge of the box
+P_analytic =np.array( [
     P_vs_r(
         P0_cgs,
-        np.abs(x[i] / r_200_kpc),
-        Lbox_kpc / r_200_kpc * np.sqrt(3) / 2,
+        (r_analytic[i]/(r_200_cgs*unyt.cm)).value,
+        (rmax/(r_200_cgs*unyt.cm)).value,
         f_b,
         M_200_cgs,
         r_200_cgs,
         c_200,
     )
-    / Pressure_UNIT
-    for i in range(map_pixel_length)
-]  # gas particle internal energies
-# T_analytic = [T_vs_r(P0_cgs, np.abs(x[i]/r_200_kpc), Lbox_kpc/r_200_kpc*np.sqrt(3)/2, f_b, M_200_cgs, r_200_cgs, c_200) for i in range(map_pixel_length)] # gas particle internal energies
+    for i in range(len(r_analytic))
+]) * (unyt.g/(unyt.cm*unyt.s**2))  # gas particle internal energies
 
+# Normalize to Bullock
+mask_r200 = radius<=(r_200_cgs * unyt.cm)
+Jtot = np.sum(omega[mask_r200] * axis_dist[mask_r200]**2 * m[mask_r200]) 
+jsp = Jtot / np.sum(m[mask_r200])
 
-# locs = [map_pixel_length / 4, map_pixel_length / 2, 3 * map_pixel_length / 4, map_pixel_length]
-# labels = np.array([Lbox_kpc / 4, Lbox_kpc / 2, 3*Lbox_kpc / 4, Lbox_kpc])
-locs = np.linspace(0, 400, 9)
-labels = np.round(locs, 0)
+jsp_B =  (np.sqrt(2) * v_200_cgs * (unyt.cm/unyt.s))*r_200_cgs*(unyt.cm)*spin_lambda 
+print('Total spin ratio: ',jsp_B.to(j_units).value/jsp.to(j_units).value)
 
-axs[0].set_xlabel(r"$r$ [kpc]")
-axs[0].set_xticks(locs, labels)
-axs[0].set_xlim(0, map_pixel_length / 2)
-axs[0].plot(x, n_H_analytic, "k-", color="red")
-axs[0].set_ylabel(r"$n_H(r)$ $[cm^{-3}]$")
-axs[0].axvline(x=r_200_kpc, color="gray", ls="dashed", label="$R_200$")
+############
+
+j_1_analytic = j((r_analytic/(r_200_cgs*unyt.cm)).value, 1, 1, f_b, M_200_cgs, r_200_cgs, c_200)
+j_1_analytic_simple = jsimple((r_analytic/(r_200_cgs*unyt.cm)).value, 1, 2, f_b, M_200_cgs, r_200_cgs, c_200)
+
+int_dOmega = 8*np.pi/3 # integral over angles from axial distance squared: int Sin^2 (theta)dphi d Cos (theta)  
+
+jsp_1_analytic = (np.sum(j_1_analytic[:-1] * rho_analytic[:-1] * (unyt.g/unyt.cm**3) * int_dOmega * r_analytic[:-1]**2*np.diff(r_analytic)))/(np.sum(rho_analytic[:-1] * (unyt.g/unyt.cm**3) * 4 * np.pi * r_analytic[:-1]**2*np.diff(r_analytic)))
+jsp_1_analytic_simple = (np.sum(j_1_analytic_simple[:-1] * rho_analytic[:-1] * (unyt.g/unyt.cm**3) * int_dOmega * r_analytic[:-1]**2*np.diff(r_analytic)))/(np.sum(rho_analytic[:-1] * (unyt.g/unyt.cm**3) * 4 * np.pi * r_analytic[:-1]**2*np.diff(r_analytic)))
+
+j_analytic = j_1_analytic / jsp_1_analytic * jsp_B
+
+j_analytic_simple = j_1_analytic_simple / jsp_1_analytic_simple * jsp_B
+
+
+
+#
+# plot density
+axs[0].plot(r_analytic.to(r_units), nH_analytic.to(nH_units), color='red',label = r'$\rho_{\rm NFW}^{gas}(r)$')
+axs[0].set_yscale("log")
 axs[0].set_xscale("log")
-axs[0].set_xlim(0.5, 300)
+axs[0].set_xlim([rmin,rmax])
+axs[0].legend()
 
-axs[1].set_xlabel(r"$r$ [kpc]")
-axs[1].set_xticks(locs, labels)
-axs[1].set_xlim(0, map_pixel_length / 2)
-axs[1].plot(x, P_analytic, "k-", color="red")
-axs[1].set_ylabel(r"$P(r)$ $[M_{sol} \cdot pc^{-1} \cdot Gyr^{-2}]$")
+# plot Pressure
+axs[1].plot(r_analytic.to(r_units), P_analytic.to(P_units), color='red',label = r'$P_{hyd. eq.}(r)$')
 axs[1].set_yscale("log")
-axs[1].set_yticks(np.logspace(3, 8, 6))
-axs[1].set_ylim(1e3, 1e8)
-axs[1].axvline(x=r_200_kpc, color="gray", ls="dashed", label="$R_200$")
 axs[1].set_xscale("log")
-axs[1].set_xlim(0.5, 300)
+axs[1].set_xlim([rmin,rmax])
+axs[1].legend()
 
-axs[2].set_xlabel(r"$r$ [kpc]")
-axs[2].set_xticks(locs, labels)
-axs[2].set_xlim(0, map_pixel_length / 2)
-axs[2].plot(x, M_gas_analytic, "k-", color="red")
-axs[2].set_ylabel(r"$M_{gas}(<r)$ $[M_{sol}]$")
-axs[2].set_yscale("log")
-axs[2].set_yticks(np.logspace(7, 12, 6))
-axs[2].set_ylim(1e7, 1e12)
-axs[2].axvline(x=r_200_kpc, color="gray", ls="dashed", label="$R_200$")
-axs[2].axhline(
-    y=f_b * M_200_cgs / (MSOL_IN_CGS), color="gray", ls="dashed", label="$M_200$"
-)
+# plot j(r)
+axs[2].plot(r_analytic.to(r_units), j_analytic.to(j_units), color='red',label = r'$\rm j(r)\sim M(r)$')
+axs[2].plot(r_analytic.to(r_units), j_analytic_simple.to(j_units), color='red', linestyle='dashed',label=r'$\rm j(r)\sim r^2$')
 axs[2].set_xscale("log")
-axs[2].set_xlim(0.5, 300)
+axs[2].set_xlim([rmin,rmax])
+axs[2].legend()
+
+# limits
+axs[0].set_ylim(1e-7, 1e2)
+axs[0].set_yticks(np.logspace(-7, 2, 10))
+axs[1].set_ylim(1e1, 1e9)
+axs[1].set_yticks(np.logspace(1, 9, 9))
+axs[2].set_ylim(1e18, 1e27)
+axs[2].set_yticks(np.logspace(18, 27, 10))
+
+axs[0].set_xlim(1e-2, 1e3)
+axs[1].set_xlim(1e-2, 1e3)
+axs[2].set_xlim(1e-2, 1e3)
 
+# add labels
+axs[0].set_ylabel(r"$n_H(r)$ $[cm^{-3}]$")
+axs[1].set_ylabel(r"$P(r)$ $[\rm M_{sol} \cdot pc^{-1} \cdot Gyr^{-2}]$")
+axs[2].set_ylabel(r"$j(r)$ $[\rm kpc^{2} \cdot Gyr^{-1} ]$")
+
+# vertical lines
+axs[0].axvline(x=(r_200_cgs*unyt.cm).to(r_units),color='gray',label=r'$R_{200}$')
+axs[1].axvline(x=(r_200_cgs*unyt.cm).to(r_units),color='gray',label=r'$R_{200}$')
+axs[2].axvline(x=(r_200_cgs*unyt.cm).to(r_units),color='gray',label=r'$R_{200}$')
 
 Ninfo = 3
 text_common_args = dict(
@@ -376,7 +336,7 @@ text_common_args = dict(
 axs[Ninfo].text(
     0.5,
     0.8,
-    r"Cooling Halo with Spin at $t=%.2f$, $y_0 = %.4f$" % (data.metadata.time, y0),
+    r"Cooling Halo with Spin, IC quality check.",
     **text_common_args,
 )
 axs[Ninfo].text(0.5, 0.7, r"SWIFT %s" % git.decode("utf-8"), **text_common_args)
@@ -389,16 +349,7 @@ axs[Ninfo].text(
     **text_common_args,
 )
 axs[Ninfo].text(
-    0.5, 0.3, r"Artificial diffusion: $%.2f$ " % (artDiffusion), **text_common_args
-)
-axs[Ninfo].text(
-    0.5,
-    0.2,
-    r"Dedner Hyp, Hyp_div(v), Par: $%.2f,%.2f,%.2f$ " % (dedHyp, dedHypDivv, dedPar),
-    **text_common_args,
-)
-axs[Ninfo].text(
-    0.5, 0.1, r"Physical resistivity: $\eta$: $%.2f$ " % (eta), **text_common_args
+    0.5, 0.3, r"Dimenstionless hubble constant: $%.3f$ " % h_dim, **text_common_args
 )
 axs[Ninfo].text(
     0.5, 0.0, r"Number of particles: $N_p$: $%.0f$ " % (n_gas), **text_common_args
diff --git a/examples/MHDTests/CoolingHaloWithSpin_MHD/README b/examples/MHDTests/CoolingHaloWithSpin_MHD/README
index adc8ad69e6a50d981c11eb868785b30a1be9e552..6d246217c5ef7e6d0b6343ccb797bbfd5824866b 100644
--- a/examples/MHDTests/CoolingHaloWithSpin_MHD/README
+++ b/examples/MHDTests/CoolingHaloWithSpin_MHD/README
@@ -24,15 +24,22 @@ collapse into a spinning disc.
 
 Compilation
 -----------
-for runs with EAGLE cooling+chemistry+entropy floor
-./configure --with-spmhd=direct-induction --with-cooling=EAGLE --with-chemistry=EAGLE --with-entropy-floor=EAGLE --with-ext-potential=nfw --with-kernel=quintic-spline --disable-hand-vec --disable-compiler-warnings --disable-doxygen-doc
+
+for runs with EAGLE cooling+chemistry+entropy floor+star formation + feedback
+./configure --with-spmhd=direct-induction --with-cooling=EAGLE --with-chemistry=EAGLE --with-entropy-floor=EAGLE --with-ext-potential=nfw --with-kernel=quintic-spline --disable-hand-vec --disable-compiler-warnings --disable-doxygen-doc --with-stars=EAGLE --with-star-formation=EAGLE --with-tracers=EAGLE --with-feedback=EAGLE
+
+for runs with EAGLE cooling+chemistry+entropy floor+star formation
+./configure --with-spmhd=direct-induction --with-cooling=EAGLE --with-chemistry=EAGLE --with-entropy-floor=EAGLE --with-ext-potential=nfw --with-kernel=quintic-spline --disable-hand-vec --disable-compiler-warnings --disable-doxygen-doc --with-stars=EAGLE --with-star-formation=EAGLE
 
 for runs with lambda cooling
 ./configure --with-spmhd=direct-induction --with-cooling=const-lambda --with-ext-potential=nfw --with-kernel=quintic-spline --disable-hand-vec --disable-compiler-warnings --disable-doxygen-doc
 
+Note: when running with self gravity but without feedback excessive clumping will happen. Since there is no density limiter, the clumps collapse until they reach sizes ~ softening length. Rotation can dilute and destabilize these clums, so adding more angular momentum might help in this case.
+
 Setup
 -----
-We follow R. Pakmor, V. Springel, 1212.1452
+IC generation similar to R. Pakmor, V. Springel, 1212.1452
+Run parameters for EAGLE model mostly follow run L025N0376 from J. Schaye et al. 1407.7040  
 
 Snapshot slices
 ---------------
diff --git a/examples/MHDTests/CoolingHaloWithSpin_MHD/cooling_halo.yml b/examples/MHDTests/CoolingHaloWithSpin_MHD/cooling_halo.yml
index 6b8b89af1cc7cd641b6a819a8ca4eaae612b5db3..c875f3677dc51720e053cc543b74e594799f86e7 100644
--- a/examples/MHDTests/CoolingHaloWithSpin_MHD/cooling_halo.yml
+++ b/examples/MHDTests/CoolingHaloWithSpin_MHD/cooling_halo.yml
@@ -1,80 +1,126 @@
-# Define the system of units to use internally. 
+# Define the system of units to use internally.
 InternalUnitSystem:
-  UnitMass_in_cgs:     1.98848e39    # 10^6 solar masses
-  UnitLength_in_cgs:   3.0856776e21  # Kiloparsecs
-  UnitVelocity_in_cgs: 1e5           # Kilometres per second
+  UnitMass_in_cgs:     1.9891E43   # 10^10 solar masses 
+  UnitLength_in_cgs:   3.08567758E21   # 1 kpc 
+  UnitVelocity_in_cgs: 1E5   # km/s
   UnitCurrent_in_cgs:  2.088431e13    # Amperes
   UnitTemp_in_cgs:     1             # Kelvin
 
 # Parameters governing the time integration
 TimeIntegration:
   time_begin: 0.    # The starting time of the simulation (in internal units).
-  time_end:   10.   # The end time of the simulation (in internal units).
+  time_end:   3.   # The end time of the simulation (in internal units).
   dt_min:     1e-12 #1e-8  # The minimal time-step size of the simulation (in internal units).
   dt_max:     1e-1  # The maximal time-step size of the simulation (in internal units).
 
 # Parameters governing the conserved quantities statistics
 Statistics:
-  delta_time:          1e-2 # Time between statistics output
-
-Scheduler:
-  tasks_per_cell:      200
+  delta_time:  0.01023    # Time difference between consecutive outputs (in internal units)  0.001023 TU = 10 Myr
+  compression: 4           # Compress the snapshots
+  recording_triggers_part: [-1, -1]   # Not recording as we have many snapshots
+  recording_triggers_bpart: [-1, -1]  # Not recording as we have many snapshots 
 
 # Parameters governing the snapshots
 Snapshots:
   basename:            CoolingHalo  # Common part of the name of output files
-  time_first:          0.               # Time of the first output (in internal units)
-  delta_time:          0.1 #0.1             # Time difference between consecutive outputs (in internal units)
-
+  time_first:          0.           # Time of the first output (in internal units)
+  delta_time:          0.01023      # Time difference between consecutive outputs (in internal units)
+  compression: 4           # Compress the snapshots
+  recording_triggers_part: [-1, -1]   # Not recording as we have many snapshots
+  recording_triggers_bpart: [-1, -1]  # Not recording as we have many snapshots 
+ 
 # Parameters for the hydrodynamics scheme
 SPH:
   resolution_eta:        1.595     # Target smoothing length in units of the mean inter-particle separation (1.2349 == 48Ngbs with the cubic spline kernel).
   CFL_condition:         0.05      # Courant-Friedrich-Levy condition for time integration.
   minimal_temperature:   1e2       # Kelvin
-  h_tolerance: 1e-6
-
+  h_tolerance: 1e-6               # smoothing length accuracy
+  h_max:                 10.
+ 
 # Parameters for MHD schemes
 MHD:
   monopole_subtraction:   1.0
   artificial_diffusion:   0.0
-  hyperbolic_dedner:      1.0 #1.0
-  hyperbolic_dedner_divv: 0.0
+  hyperbolic_dedner:      1.0 
+  hyperbolic_dedner_divv: 0.5
   parabolic_dedner:       1.0
   resistive_eta:          0.0
 
 # Parameters related to the initial conditions
 InitialConditions:
   file_name:  CoolingHalo.hdf5       # The file to read
-  periodic:   1
- 
-# Note: softening 2.6 below is for 1.4e7 Msol particle mass to impose density cut 1e2 cm^-3
+  periodic:   0 
+  stars_smoothing_length:  0.5
  
 # External potential parameters
 NFWPotential:
     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)
-    M_200:           1000000        # M200 of the galaxy disk
-    h:               0.681          # reduced Hubble constant (using FLAMINGO cosmology) (value does not specify the used units!)
+    M_200:           100        # M200 of the galaxy disk
+    h:               0.704          # reduced Hubble constant (using FLAMINGO cosmology) (value does not specify the used units!)
     concentration:   7.2            # concentration of the Halo
     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.569 #2.6            # Softening size (internal units)
-    #diskfraction:    0.0            # Disk mass fraction
-    #bulgefraction:   0.0            # Bulge mass fraction
+    epsilon:         0.7             # Softening size (internal units)
 
 # Parameters for the self-gravity scheme
 Gravity:
-  eta:                0.025
-  MAC:                adaptive
-  theta_cr:           0.7
-  epsilon_fmm:        0.001
-  max_physical_baryon_softening:  0.569 #2.6  # Physical softening length (in internal units). Depends on resolution!
-  mesh_side_length:   64
+  eta:          0.025                 # Constant dimensionless multiplier for time integration.
+  MAC:          adaptive
+  theta_cr:     0.6                 # Opening angle (Multipole acceptance criterion).
+  epsilon_fmm:            0.001
+  max_physical_DM_softening:     0.7  # Physical softening length (in internal units).
+  max_physical_baryon_softening: 0.7  # Physical softening length (in internal units).
+
+# Parameters for the stars
+Stars:
+  overwrite_birth_time:        1     # Make sure the stars in the ICs do not do any feedback
+  birth_time:                 -1.    # by setting all of their birth times to -1
+  timestep_age_threshold_Myr: 10.    # Age at which stars switch from young to old (in Mega-years).
+  max_timestep_young_Myr:      0.1   # Maximal time-step length of young stars (in Mega-years).
+  max_timestep_old_Myr:        1.0   # Maximal time-step length of old stars (in Mega-years).
+  luminosity_filename:   ./photometry
+
+# Standard EAGLE cooling options
+EAGLECooling:
+  dir_name:                ./coolingtables/  # Location of the Wiersma+09 cooling tables
+  H_reion_z:               11.5              # Redshift of Hydrogen re-ionization
+  H_reion_eV_p_H:          2.0
+  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
 
-# Simple model cooling parameters
-LambdaCooling:
-  lambda_nH2_cgs:              1e-23  # Cooling rate divided by square Hydrogen number density (in cgs units [erg * s^-1 * cm^3])
-  cooling_tstep_mult:          0.1    # Dimensionless pre-factor for the time-step condition
+# Solar abundances
+EAGLEChemistry:
+  init_abundance_metal:     0.0129       # Inital fraction of particle mass in *all* metals
+  init_abundance_Hydrogen:  0.7065       # Inital fraction of particle mass in Hydrogen
+  init_abundance_Helium:    0.2806       # Inital fraction of particle mass in Helium
+  init_abundance_Carbon:    0.00207      # Inital fraction of particle mass in Carbon
+  init_abundance_Nitrogen:  0.000836     # Inital fraction of particle mass in Nitrogen
+  init_abundance_Oxygen:    0.00549      # Inital fraction of particle mass in Oxygen
+  init_abundance_Neon:      0.00141      # Inital fraction of particle mass in Neon
+  init_abundance_Magnesium: 0.000591     # Inital fraction of particle mass in Magnesium
+  init_abundance_Silicon:   0.000683     # Inital fraction of particle mass in Silicon
+  init_abundance_Iron:      0.0011       # Inital fraction of particle mass in Iron
 
+# EAGLE star formation parameters
+EAGLEStarFormation:
+  SF_threshold:                      Zdep         # Zdep (Schaye 2004) or Subgrid
+  SF_model:                          PressureLaw  # PressureLaw (Schaye et al. 2008) or SchmidtLaw
+  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.
+  min_over_density:                  100.0        # 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.
+  EOS_entropy_margin_dex:            0.3          # When using Z-based SF threshold, logarithm base 10 of the maximal entropy above the EOS at which stars can form.
+  threshold_norm_H_p_cm3:            0.1          # When using Z-based SF threshold, normalisation of the metal-dependant density threshold for star formation in Hydrogen atoms per cm^3.
+  threshold_Z0:                      0.002        # When using Z-based SF threshold, reference metallicity (metal mass fraction) for the metal-dependant threshold for star formation.
+  threshold_slope:                   -0.64        # When using Z-based SF threshold, slope of the metal-dependant star formation threshold
+  threshold_max_density_H_p_cm3:     10.0         # When using Z-based SF threshold, maximal density of the metal-dependant density threshold for star formation in Hydrogen atoms per cm^3.
+  threshold_temperature1_K:          1000         # When using subgrid-based SF threshold, subgrid temperature below which gas is star-forming.
+  threshold_temperature2_K:          31622        # When using subgrid-based SF threshold, subgrid temperature below which gas is star-forming if also above the density limit.
+  threshold_number_density_H_p_cm3:  10           # When using subgrid-based SF threshold, subgrid number density above which gas is star-forming if also below the second temperature limit.
+  #
 # Parameters for the EAGLE "equation of state"
 EAGLEEntropyFloor:
   Jeans_density_threshold_H_p_cm3: 1e-4      # Physical density above which the EAGLE Jeans limiter entropy floor kicks in expressed in Hydrogen atoms per cm^3.
@@ -86,39 +132,46 @@ EAGLEEntropyFloor:
   Cool_temperature_norm_K:        10.        # Temperature of the EAGLE Cool limiter entropy floor at the density threshold expressed in Kelvin. (NOTE: This is below the min T and hence this floor does nothing)
   Cool_gamma_effective:           1.         # Slope the of the EAGLE Cool limiter entropy floor
 
-
-# Use primordial abundances
-EAGLEChemistry:
-  init_abundance_metal:     0.
-  init_abundance_Hydrogen:  0.755
-  init_abundance_Helium:    0.245
-  init_abundance_Carbon:    0.
-  init_abundance_Nitrogen:  0.
-  init_abundance_Oxygen:    0.
-  init_abundance_Neon:      0.
-  init_abundance_Magnesium: 0.
-  init_abundance_Silicon:   0.
-  init_abundance_Iron:      0.
-
-# 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   
-
-# Standard EAGLE cooling options
-EAGLECooling:
-  dir_name:                ./coolingtables/  # Location of the Wiersma+09 cooling tables
-  H_reion_z:               7.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
-
+# EAGLE feedback model with constant feedback energy fraction
+EAGLEFeedback:
+  use_SNII_feedback:                    1               # Global switch for SNII thermal (stochastic) feedback.
+  use_SNIa_feedback:                    1               # Global switch for SNIa thermal (continuous) 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:                   8.0             # Minimal mass considered for SNII stars in solar masses.
+  SNII_max_mass_Msun:                 100.0             # Maximal mass considered for SNII stars in solar masses.
+  SNII_feedback_model:                  MinimumDistance # Feedback modes: Random, Isotropic, MinimumDistance, MinimumDensity
+  SNII_sampled_delay:                   1               # Sample the SNII lifetimes to do feedback.
+  SNII_delta_T_K:                       3.16228e7       # Change in temperature to apply to the gas particle in a SNII thermal feedback event in Kelvin.
+  SNII_delta_v_km_p_s:                  200             # Velocity kick applied by the stars when doing SNII feedback (in km/s).
+  SNII_energy_erg:                      1.0e51          # Energy of one SNII explosion in ergs.
+  SNII_energy_fraction_function:        EAGLE           # Type of functional form to use for scaling the energy fraction with density and metallicity ('EAGLE', 'Separable', or 'Independent').
+  SNII_energy_fraction_min:             1.0             # Minimal fraction of energy applied in a SNII feedback event.
+  SNII_energy_fraction_max:             1.0             # Maximal 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:     1.4588          # 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.
+  SNII_energy_fraction_use_birth_density: 0             # Are we using the density at birth to compute f_E or at feedback time?
+  SNII_energy_fraction_use_birth_metallicity: 0         # Are we using the metallicity at birth to compuote f_E or at feedback time?
+  SNIa_DTD:                             Exponential     # Functional form of the SNIa delay time distribution.
+  SNIa_DTD_delay_Gyr:                   0.04            # Stellar age after which SNIa start in Gyr (40 Myr corresponds to stars ~ 8 Msun).
+  SNIa_DTD_exp_timescale_Gyr:           2.0             # Time-scale of the exponential decay of the SNIa rates in Gyr.
+  SNIa_DTD_exp_norm_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.
+  stellar_evolution_age_cut_Gyr:        0.1             # Age in Gyr above which the enrichment is downsampled.
+  stellar_evolution_sampling_rate:       10             # Number of time-steps in-between two enrichment events for a star above the age threshold.
+  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/MHDTests/CoolingHaloWithSpin_MHD/getEaglePhotometryTable.sh b/examples/MHDTests/CoolingHaloWithSpin_MHD/getEaglePhotometryTable.sh
new file mode 100755
index 0000000000000000000000000000000000000000..ee9c3b422f19518612416da0913b162fd4a120ff
--- /dev/null
+++ b/examples/MHDTests/CoolingHaloWithSpin_MHD/getEaglePhotometryTable.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+wget http://virgodb.cosma.dur.ac.uk/swift-webstorage/YieldTables/EAGLE/photometry.tar.gz
+tar -xf photometry.tar.gz
diff --git a/examples/MHDTests/CoolingHaloWithSpin_MHD/getYieldTable.sh b/examples/MHDTests/CoolingHaloWithSpin_MHD/getYieldTable.sh
new file mode 100755
index 0000000000000000000000000000000000000000..26eef020cab82acee2c80e88089df1790b281eab
--- /dev/null
+++ b/examples/MHDTests/CoolingHaloWithSpin_MHD/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/MHDTests/CoolingHaloWithSpin_MHD/makeIC.py b/examples/MHDTests/CoolingHaloWithSpin_MHD/makeIC.py
index ecd957484ca3440b16b2d42c9add49b0025e5d56..a06466e55816062f2c98cc4ca588f99d60adb6ee 100644
--- a/examples/MHDTests/CoolingHaloWithSpin_MHD/makeIC.py
+++ b/examples/MHDTests/CoolingHaloWithSpin_MHD/makeIC.py
@@ -41,30 +41,36 @@ const_unit_velocity_in_cgs = 1.0e5  # kms^-1
 
 # Cosmological parameters
 OMEGA = 0.3  # Cosmological matter fraction at z = 0
-h = 0.681  # 0.67777  # hubble parameter
+h = 0.704  # 0.67777  # hubble parameter
 # Find H_0, the inverse Hubble time, in cgs
 H_0_cgs = 100.0 * h * KM_PER_SEC_IN_CGS / (1.0e6 * PARSEC_IN_CGS)
 
 # DM halo parameters
 spin_lambda = 0.05  # spin parameter
-spin_lambda_choice = "Bullock"  # which definition of spin parameter to use
 f_b = 0.17  # baryon fraction
 c_200 = 7.2  # concentration parameter
 
 # Set the magnitude of the uniform seed magnetic field
-B0_Gaussian_Units = 1e-9  # 1e-6  # 1 micro Gauss
+B0_Gaussian_Units = 1e-9 # 1e-3 micro Gauss
 B0_cgs = np.sqrt(CONST_MU0_CGS / (4.0 * np.pi)) * B0_Gaussian_Units
 
 # SPH
-eta = 1.3663  # kernel smoothing
+eta = 1.595  # kernel smoothing
 
 # Additional options
 spin_lambda_choice = (
-    "Bullock"
+    "Peebles"
 )  # which definition of spin parameter to use (Peebles or Bullock)
 save_to_vtk = False
 plot_v_distribution = False
 
+AMP = "r^s" # sets angular momentum profile to be a function of M(r) or r^s 
+AMPs = 2 # power in agnular momentum profile
+
+with_noise = True # add gaussian uncertainty for particle positions
+noise_sigma = 0.5
+noise_mean = 0.0
+
 # From this we can find the virial radius, the radius within which the average density of the halo is
 # 200. * the mean matter density
 
@@ -112,9 +118,11 @@ print("G=", const_G)
 
 # Parameters
 periodic = 1  # 1 For periodic box
-boxSize = 4.0
+boxSize = 2.0 # in units of r_200 
+R_max = boxSize/6 #boxSize/6 # set maximal halo radius (we simulate only part of a halo) 
 G = const_G
 N = int(sys.argv[1])  # Number of particles
+N = int(N*6/np.pi)   # renormalize number of particles to get required N after cutting a sphere
 IAsource = "IAfile"
 
 # Create the file
@@ -190,10 +198,9 @@ coords -= 0.5
 # cut a sphere
 r_uni = np.linalg.norm(coords, axis=1)
 coords = coords[r_uni <= 0.5]
-coords *= boxSize * np.sqrt(3)
+coords *= 2*R_max
 
 # calculate max distance from the center (units of r_200)
-R_max = np.sqrt(3) * (boxSize / 2)
 r_s = 1 / c_200
 # calculate distances to the center
 r_uni = np.linalg.norm(coords, axis=1)
@@ -301,6 +308,18 @@ r = np.logspace(
     round(10 * N ** (1 / 3)),
 )
 
+# Add noise
+if with_noise:
+    radius = np.sqrt(
+        (coords[:, 0]) ** 2
+        + (coords[:, 1]) ** 2
+        + (coords[:, 2]) ** 2
+    )
+    l = (gas_particle_mass*M_200_cgs/rho_r(radius, f_b, M_200_cgs, r_200_cgs, c_200))**(1/3)/r_200_cgs 
+    random_amps = noise_sigma * np.random.randn(len(coords),3) + noise_mean
+    coords += random_amps * l[:,None]
+
+
 # shift to centre of box
 coords += np.full(coords.shape, boxSize / 2.0)
 print("x range = (%f,%f)" % (np.min(coords[:, 0]), np.max(coords[:, 0])))
@@ -397,11 +416,17 @@ print("j_sp =", j_sp)
 # is proportional to j/r^2
 
 # define specific angular momentum distribution
-def j(r_value, j_max, s, f_b, M_200_cgs, r_200_cgs, c_200):
-    return (
-        j_max
-        * (Mgas_r(r_value, f_b, M_200_cgs, r_200_cgs, c_200) / (M_200_cgs * f_b)) ** s
-    )
+def j(r_value, j_max, s, f_b, M_200_cgs, r_200_cgs, c_200, angular_momentum_profile="M(r)"):
+    if angular_momentum_profile == "M(r)":
+        return (
+            j_max
+            * (Mgas_r(r_value, f_b, M_200_cgs, r_200_cgs, c_200) / (M_200_cgs * f_b)) ** s
+        )
+    elif angular_momentum_profile=="r^s": # for rigid body rotation use r^2
+        return (
+            j_max
+            * r_value**s
+        )
 
 
 omega = np.zeros((N, 3))
@@ -410,7 +435,7 @@ radius_vect = np.zeros((N, 3))
 l = np.zeros((N, 3))
 for i in range(N):
     radius_vect[i, :] = coords[i, :] - boxSize / 2.0
-    omega[i, 2] = j(radius[i], 1, 1, f_b, M_200_cgs, r_200_cgs, c_200) / radius[i] ** 2
+    omega[i, 2] = j(radius[i], 1, AMPs, f_b, M_200_cgs, r_200_cgs, c_200,AMP) / radius[i] ** 2
     v[i, :] = np.cross(omega[i, :], radius_vect[i, :])
     B[i, 0] = B0_cgs / const_unit_magnetic_field_in_cgs
     l[i, :] = gas_particle_mass * np.cross(radius_vect[i, :], v[i, :])
@@ -418,7 +443,8 @@ for i in range(N):
 # select particles inside R_200
 mask_r_200 = radius <= 1
 Lp_tot = np.sum(l[mask_r_200], axis=0)
-Lp_tot_abs = np.linalg.norm(Lp_tot)
+Lp_tot_abs = np.linalg.norm(Lp_tot) 
+jsp = Lp_tot_abs/gas_mass
 normV = np.linalg.norm(v, axis=1)
 
 if spin_lambda_choice == "Peebles":
@@ -430,17 +456,15 @@ if spin_lambda_choice == "Peebles":
         / (const_unit_velocity_in_cgs ** 2)
     )
     Ep_tot = np.sum(Ep_kin[mask_r_200] + Ep_pot[mask_r_200])
-    calc_spin_par_P = (
-        Lp_tot_abs * np.sqrt(np.abs(Ep_tot)) / const_G / (f_b * 1) ** (5 / 2)
+    jsp_P = (
+        const_G * (gas_mass) ** (3 / 2) / np.sqrt(np.abs(Ep_tot))
     )
-    v *= spin_lambda / calc_spin_par_P
-    l *= spin_lambda / calc_spin_par_P
+    v *= jsp_P/jsp
+
 elif spin_lambda_choice == "Bullock":
     # Normalize to Bullock
-    jp_sp = Lp_tot_abs / (gas_particle_mass * np.sum(mask_r_200))
-    calc_spin_par_B = jp_sp / (np.sqrt(2) * 1 * v_200)
-    v *= spin_lambda / calc_spin_par_B
-    l *= spin_lambda / calc_spin_par_B
+    jsp_B = (np.sqrt(2) * v_200 )*spin_lambda
+    v *= jsp_B/jsp
 
 # Draw velocity distribution
 if plot_v_distribution:
@@ -488,9 +512,8 @@ ds[()] = m
 m = np.zeros(1)
 
 # Smoothing lengths
-l = (4.0 * np.pi * radius ** 2 / N) ** (
-    1.0 / 3.0
-)  # local mean inter-particle separation
+
+l = (gas_particle_mass*M_200_cgs/rho_r(radius, f_b, M_200_cgs, r_200_cgs, c_200))**(1/3)/r_200_cgs 
 h = np.full((N,), eta * l)
 ds = grp.create_dataset("SmoothingLength", (N,), "f")
 ds[()] = h
diff --git a/examples/MHDTests/CoolingHaloWithSpin_MHD/plotSolutionReference.py b/examples/MHDTests/CoolingHaloWithSpin_MHD/plotSolutionReference.py
index a563d432517d48f16a5a76f48af9729ac6138c01..efd156b9cab4dd41b251bf6f27613e9a08c849c2 100644
--- a/examples/MHDTests/CoolingHaloWithSpin_MHD/plotSolutionReference.py
+++ b/examples/MHDTests/CoolingHaloWithSpin_MHD/plotSolutionReference.py
@@ -80,7 +80,7 @@ rotation_matrix = [[1,0,0],
 rotation_matrix = [[0, 0, 1], [0, 1, 0], [-1, 0, 0]]
 
 # set plot area
-Lslice_kPc = 20.0  # 2*21.5
+Lslice_kPc = 20.0
 Lslice = Lslice_kPc * 3.08e18 * 1e3 * unyt.cm
 
 visualise_region_xy = [
@@ -204,7 +204,7 @@ fig, ax = plt.subplots(ny, nx, sharey=True, figsize=(5 * nx, 5 * ny))
 a00 = ax[0, 0].contourf(
     np.log10(nH_map.value),
     # np.log10(density_map.value),
-    cmap="jet",  # "plasma",#"gist_stern",#"RdBu",
+    cmap="plasma", 
     extend="both",
     levels=np.linspace(-4, 2, 100),
     # levels=np.linspace(-7, -1, 100),
@@ -213,7 +213,7 @@ a00 = ax[0, 0].contourf(
 a01 = ax[0, 1].contourf(
     np.log10(nH_map_xy.value).T,
     # np.log10(density_map_xy.value).T,
-    cmap="jet",  # "plasma",#"gist_stern", #"RdBu",
+    cmap="plasma",  
     extend="both",
     levels=np.linspace(-4, 2, 100),
     # levels=np.linspace(-7, -1, 100),
@@ -236,13 +236,13 @@ a01 = ax[0, 1].contourf(
 # )
 a10 = ax[1, 0].contourf(
     np.maximum(np.log10(normB_map.value), -6),
-    cmap="jet",  # "viridis", #"nipy_spectral_r",
+    cmap="viridis", 
     extend="both",
     levels=np.linspace(-2, 2, 100),
 )
 a11 = ax[1, 1].contourf(
     np.maximum(np.log10(normB_map_xy.value), -6).T,
-    cmap="jet",  # "viridis", #"nipy_spectral_r",
+    cmap="viridis", 
     extend="both",
     levels=np.linspace(-2, 2, 100),
 )
diff --git a/examples/MHDTests/CoolingHaloWithSpin_MHD/plotSpectrum.py b/examples/MHDTests/CoolingHaloWithSpin_MHD/plotSpectrum.py
new file mode 100644
index 0000000000000000000000000000000000000000..576975125b4a3d7433f922896743553beb8e6197
--- /dev/null
+++ b/examples/MHDTests/CoolingHaloWithSpin_MHD/plotSpectrum.py
@@ -0,0 +1,339 @@
+import numpy as np
+import h5py
+import unyt
+import matplotlib.pyplot as plt
+import argparse
+
+from swiftsimio import load
+from swiftsimio.visualisation.volume_render import render_gas
+
+
+# Parse command line arguments
+argparser = argparse.ArgumentParser()
+argparser.add_argument("input")
+argparser.add_argument("output")
+#argparser.add_argument("resolution")
+args = argparser.parse_args()
+
+# Load snapshot
+filename = args.input
+data = load(filename)
+
+time = np.round(data.metadata.time,2)
+print("Plotting at ", time)
+
+Lbox = data.metadata.boxsize
+
+# Retrieve some information about the simulation run
+artDiffusion = data.metadata.hydro_scheme["Artificial Diffusion Constant"]
+dedHyp = data.metadata.hydro_scheme["Dedner Hyperbolic Constant"]
+dedHypDivv = data.metadata.hydro_scheme["Dedner Hyperbolic div(v) Constant"]
+dedPar = data.metadata.hydro_scheme["Dedner Parabolic Constant"]
+eta = data.metadata.hydro_scheme["Resistive Eta"]
+git = data.metadata.code["Git Revision"]
+gitBranch = data.metadata.code["Git Branch"]
+hydroScheme = data.metadata.hydro_scheme["Scheme"]
+kernel = data.metadata.hydro_scheme["Kernel function"]
+neighbours = data.metadata.hydro_scheme["Kernel target N_ngb"]
+
+# Retrieve particle attributes of interest
+v = data.gas.velocities
+rho = data.gas.densities
+B = data.gas.magnetic_flux_densities
+h = data.gas.smoothing_lengths
+normB = np.sqrt(B[:, 0] ** 2 + B[:, 1] ** 2 + B[:, 2] ** 2)
+
+divB = data.gas.magnetic_divergences
+minh = np.min(h.value)
+
+# Renormalize quantities
+mu0 = 1.25663706127e-6 * unyt.kg * unyt.m / (unyt.s ** 2 * unyt.statA ** 2)
+# note that older swiftsimio version is using statA even if swift has MF as A
+#mu0 = 1.25663706127e-1 * unyt.g * unyt.cm / (unyt.s ** 2 * unyt.statA ** 2)
+v = v * (rho[:, None]/2)**0.5
+B = B / np.sqrt(2*mu0)
+
+#Npside = int(len(h)**(1/3))+1
+
+# Generate mass weighted maps of quantities of interest
+data.gas.mass_weighted_vx = data.gas.masses * v[:,0]
+data.gas.mass_weighted_vy = data.gas.masses * v[:,1]
+data.gas.mass_weighted_vz = data.gas.masses * v[:,2]
+
+data.gas.mass_weighted_Bx = data.gas.masses * B[:,0]
+data.gas.mass_weighted_By = data.gas.masses * B[:,1]
+data.gas.mass_weighted_Bz = data.gas.masses * B[:,2]
+
+data.gas.mass_weighted_error = data.gas.masses * np.maximum(h * abs(divB) / (normB + 0.01 * np.max(normB)), 1e-6)
+
+#res = 128 #Npside #int(args.resolution)
+
+#Lslice = 0.5*Lbox
+Lslice_kPc = 20  # 2*21.5
+Lslice = Lslice_kPc * 3.08e18 * 1e3 * unyt.cm
+
+k_slice = 2*np.pi/Lslice
+k_res = np.max(2*np.pi/h)
+
+res = int((2*Lslice/np.min(h)).value) #Npside #int(args.resolution)
+
+# resolution limiter
+resmax= 512
+print('Suggested maximal resoluiton: ',res)
+res = min([res,resmax])
+
+print('Spectral resolution: ',res)
+
+center = Lbox/2
+visualise_region = [
+    center[0] - Lslice,
+    center[0] + Lslice,
+    center[1] - Lslice,
+    center[1] + Lslice,
+    center[2] - Lslice,
+    center[2] + Lslice,
+]
+
+common_arguments = dict(
+    data=data, resolution=res, parallel=True,periodic=True,region=visualise_region,
+)
+
+
+mass_cube = render_gas(**common_arguments, project="masses")
+min_nonzero_m =np.min( mass_cube.flatten()[mass_cube.flatten().value!=0.0])
+mass_cube[mass_cube.value==0]=1e-2*min_nonzero_m
+
+mass_weighted_vx_cube = render_gas(**common_arguments, project="mass_weighted_vx")
+mass_weighted_vy_cube = render_gas(**common_arguments, project="mass_weighted_vy")
+mass_weighted_vz_cube = render_gas(**common_arguments, project="mass_weighted_vz")
+
+mass_weighted_Bx_cube = render_gas(**common_arguments, project="mass_weighted_Bx")
+mass_weighted_By_cube = render_gas(**common_arguments, project="mass_weighted_By")
+mass_weighted_Bz_cube = render_gas(**common_arguments, project="mass_weighted_Bz")
+
+mass_weighted_error_cube = render_gas(**common_arguments, project="mass_weighted_error")
+
+
+vx_cube = mass_weighted_vx_cube/mass_cube
+vy_cube = mass_weighted_vy_cube/mass_cube
+vz_cube = mass_weighted_vz_cube/mass_cube
+
+Bx_cube = mass_weighted_Bx_cube/mass_cube
+By_cube = mass_weighted_By_cube/mass_cube
+Bz_cube = mass_weighted_Bz_cube/mass_cube
+
+error_cube = mass_weighted_error_cube/mass_cube 
+
+unit_energy = unyt.g * unyt.cm**2 / unyt.s**2
+unit_energy_density = unit_energy / unyt.cm**3
+unit_sqrt_energy_density = (unit_energy_density)**0.5
+unit_length = 1e3*unyt.pc
+
+vx_cube.convert_to_units(unit_sqrt_energy_density)
+vy_cube.convert_to_units(unit_sqrt_energy_density)
+vz_cube.convert_to_units(unit_sqrt_energy_density)
+
+Bx_cube.convert_to_units(unit_sqrt_energy_density)
+By_cube.convert_to_units(unit_sqrt_energy_density)
+Bz_cube.convert_to_units(unit_sqrt_energy_density)
+
+k_slice = 2*np.pi/Lslice
+k_res = np.max(2*np.pi/h)
+
+k_slice.convert_to_units(1/unit_length)
+k_res.convert_to_units(1/unit_length)
+
+def compute_power_spectrum_scal(Q, dx, nbins):
+    # Grid size
+    Nx, Ny, Nz = Q.shape
+
+    # Compute Fourier transforms
+    Q_k = np.fft.fftn(Q)
+
+    # Compute power spectrum (squared magnitude of Fourier components)
+    Q_power_k = np.abs(Q_k)**2
+
+    # Compute the corresponding wavenumbers
+    kx = np.fft.fftfreq(Nx, d=dx) * 2 * np.pi
+    ky = np.fft.fftfreq(Ny, d=dx) * 2 * np.pi
+    kz = np.fft.fftfreq(Nz, d=dx) * 2 * np.pi
+
+    # Create 3D arrays of wavevectors
+    KX, KY, KZ = np.meshgrid(kx, ky, kz, indexing='ij')
+    k_mag = np.sqrt(KX**2 + KY**2 + KZ**2)
+
+    # Flatten arrays for binning
+    k_mag_flat = k_mag.flatten()
+    Q_power_flat = Q_power_k.flatten()
+
+    # Define k bins (you can tweak bin size)
+    k_bins = np.linspace(0, np.max(2*np.pi/minh), num=nbins)
+
+    # exclude 0th mode:
+    k_bins = k_bins[1:]
+    k_mag_flat = k_mag_flat[1:]
+    Q_power_flat = Q_power_flat[1:]
+
+    k_bin_centers = 0.5 * (k_bins[1:] + k_bins[:-1])
+
+    # Bin the power spectrum
+    power_spectrum, _ = np.histogram(k_mag_flat, bins=k_bins, weights=Q_power_flat)
+    counts, _ = np.histogram(k_mag_flat, bins=k_bins)
+    
+    # Avoid division by zero
+    power_spectrum = np.where(counts > 0, power_spectrum / counts, 0)
+
+    return k_bin_centers, power_spectrum
+
+def compute_power_spectrum_vec(Qx, Qy, Qz, dx,nbins):
+    # Ensure all arrays are unyt arrays with same units
+    dx = dx #.to(unyt.pc)
+    volume_element = dx**3  # single cell volume in cm^3
+
+    # Get shape
+    Nx, Ny, Nz = Qx.shape
+
+    # Fourier transform (keep units)
+    Qx_k = np.fft.fftn(Qx.value) * volume_element.value
+    Qy_k = np.fft.fftn(Qy.value) * volume_element.value
+    Qz_k = np.fft.fftn(Qz.value) * volume_element.value
+
+    # Reapply units
+    Qx_k = Qx_k * Qx.units * volume_element.units
+    Qy_k = Qy_k * Qy.units * volume_element.units
+    Qz_k = Qz_k * Qz.units * volume_element.units
+
+    # Power in k-space
+    Pk = (np.abs(Qx_k)**2 + np.abs(Qy_k)**2 + np.abs(Qz_k)**2)#.to(unyt.g/(unyt.s**2)*unyt.cm**5)  # or appropriate units
+
+    # Compute wavenumbers
+    kx = np.fft.fftfreq(Nx, d=dx.value) * 2 * np.pi / dx.units #unyt.cm**-1
+    ky = np.fft.fftfreq(Ny, d=dx.value) * 2 * np.pi / dx.units #unyt.cm**-1
+    kz = np.fft.fftfreq(Nz, d=dx.value) * 2 * np.pi / dx.units #unyt.cm**-1
+    KX, KY, KZ = np.meshgrid(kx, ky, kz, indexing='ij')
+    k_mag = np.sqrt(KX**2 + KY**2 + KZ**2)
+
+    # Calculate monopole component
+    Q_dot_k = Qx_k * KX + Qy_k * KY + Qz_k * KZ
+    Qx_k_div = KX * Q_dot_k / k_mag**2
+    Qy_k_div = KY * Q_dot_k / k_mag**2
+    Qz_k_div = KZ * Q_dot_k / k_mag**2
+    Pk_div = (np.abs(Qx_k_div)**2 + np.abs(Qy_k_div)**2 + np.abs(Qz_k_div)**2)#.to(unyt.g/(unyt.s**2)*unyt.cm**5)  # or appropriate units
+
+    # Flatten and bin
+    k_flat = k_mag.flatten() #.to('1/cm')
+    Pk_flat = Pk.flatten() #.to(unyt.g/(unyt.s**2)*unyt.cm**5)  # this should be correct after unit reduction
+    Pk_div_flat = Pk_div.flatten()
+
+    # Bin in k-space
+    k_min_log = np.log10(np.min(k_flat.value[k_flat.value!=0]))
+    k_max_log = np.log10(np.max(k_flat.value))
+    k_bins = np.logspace(k_min_log,k_max_log, num=nbins) * k_flat.units  #*unyt.cm**-1
+
+    # exclude 0th mode:
+    k_bins = k_bins[1:]
+    k_flat = k_flat[1:]
+    Pk_flat = Pk_flat[1:]
+    Pk_div_flat = Pk_div_flat[1:]
+
+    # converting to Energy per unit wavevector
+    Ek_flat = 4*np.pi * k_flat**2 * Pk_flat
+    Ek_div_flat = 4*np.pi * k_flat**2 * Pk_div_flat
+
+    k_bin_centers = 0.5 * (k_bins[1:] + k_bins[:-1])
+
+    power_spectrum = np.zeros(len(k_bin_centers)) * Ek_flat.units
+    power_spectrum_div = np.zeros(len(k_bin_centers)) * Ek_div_flat.units
+    counts = np.zeros(len(k_bin_centers))
+   
+    for i in range(len(k_bin_centers)):
+        in_bin = (k_flat >= k_bins[i]) & (k_flat < k_bins[i+1])
+        power_spectrum[i] = Ek_flat[in_bin].sum()
+        power_spectrum_div[i] = Ek_div_flat[in_bin].sum()
+        counts[i] = in_bin.sum()
+
+    # Normalize per mode (optional)
+    power_spectrum = np.where(counts > 0, power_spectrum / counts, 0 * power_spectrum.units)
+    power_spectrum_div = np.where(counts > 0, power_spectrum_div / counts, 0 * power_spectrum_div.units)
+
+    # mask non-zero
+    mask_zeros = power_spectrum==0
+    k_bin_centers = k_bin_centers[~mask_zeros]
+    power_spectrum = power_spectrum[~mask_zeros]
+    power_spectrum_div = power_spectrum_div[~mask_zeros]
+
+    return k_bin_centers, power_spectrum, power_spectrum_div
+
+dx = 2*Lslice.to(unit_length)/(res)
+
+# plot magnetic field spectrum
+ks, Eb, Eb_div = compute_power_spectrum_vec(Bx_cube,By_cube,Bz_cube, dx = dx, nbins=res-1 )
+# plot velocity spectrum
+ks, Ev, _ = compute_power_spectrum_vec(vx_cube,vy_cube,vz_cube, dx = dx, nbins=res-1 )
+# plot divergence error spectrum
+#ks, Perr = compute_power_spectrum_scal(error_cube, dx = dx, nbins=res-1 )
+
+Eb.convert_to_units(unyt.erg*(1e3*unyt.pc))
+Eb_div.convert_to_units(unyt.erg*(1e3*unyt.pc))
+
+Ev.convert_to_units(unyt.erg*(1e3*unyt.pc))
+ks.convert_to_units(1e-3/unyt.pc)
+
+
+fig, ax = plt.subplots(figsize=(10, 6.2))
+
+ax.plot(ks,Ev.value,color='blue',label='$E_v(k)$')
+ax.plot(ks,Eb.value,color='red',linestyle='solid',label='$E_B(k)$')
+ax.plot(ks,Eb_div.value,color='purple',linestyle='solid',label='$E_{B_{mon}}(k)$')
+#ax.plot(ks,Perr,color='purple',label='$P_{R_{0}}(k)$')
+
+# resolution line
+ax.axvline(x=k_res, color='brown',linestyle='solid',label = r'$k_{\mathrm{res}}$')
+
+# self gravity softening line
+ksoft = 2*np.pi / (0.2 * 1e3 * unyt.pc)
+ksoft.convert_to_units(1e-3/unyt.pc)
+ax.axvline(x=ksoft, color='brown',linestyle='dashdot',label = r'$k_{\mathrm{soft}}$')
+
+# plot spectral lines
+ksmock = np.logspace(np.log10(ksoft.value)-1,np.log10(ksoft.value)-0.5,10)*ksoft.units
+p = -5/3
+Eright = 1e57 * unyt.erg*(1e3*unyt.pc)
+kright = ksoft
+kright.convert_to_units(1e-3/unyt.pc)
+Emock = Eright*(ksmock/kright)**(p)
+Emock.convert_to_units(unyt.erg*(1e3*unyt.pc))
+ax.plot(ksmock,Emock,color='black',linestyle='dashed')#,label = '$k^{-5/3}$')
+
+klabel = ksoft/10**0.45
+klabel.convert_to_units(1e-3/unyt.pc)
+Elabel = Eright*(klabel/kright)**(p)
+Elabel.convert_to_units(unyt.erg*(1e3*unyt.pc))
+ax.text(klabel,Elabel,r'$k^{-5/3}$')
+
+# plot spectral lines
+ksmock = np.logspace(np.log10(k_slice.value),np.log10(k_slice.value)+0.5,10)*k_slice.units
+p = 3/2
+Eleft = 1e57 * unyt.erg*(1e3*unyt.pc)
+kleft = k_slice
+kleft.convert_to_units(1e-3/unyt.pc)
+Emock = Eleft*(ksmock/kleft)**(p)
+Emock.convert_to_units(unyt.erg*(1e3*unyt.pc))
+ax.plot(ksmock,Emock,color='black',linestyle='dashed')#,label = '$k^{-5/3}$')
+
+klabel = k_slice/10**0.15
+klabel.convert_to_units(1e-3/unyt.pc)
+Elabel = Eleft*(klabel/kleft)**(p)
+Elabel.convert_to_units(unyt.erg*(1e3*unyt.pc))
+ax.text(klabel,Elabel,r'$k^{3/2}$')
+
+ax.set_yscale('log')
+ax.set_xscale('log')
+ax.set_xlabel(r'$\mathrm{k}$ $[\mathrm{kpc}^{-1}]$', fontsize=30)
+ax.set_ylabel(r'$\mathrm{P}(\mathrm{k})$ $[\mathrm{erg}\cdot\mathrm{kpc}]$', fontsize=30)
+ax.tick_params(axis='both', labelsize=20)
+#ax.grid()
+ax.legend()
+fig.tight_layout()
+plt.savefig(args.output)
+
diff --git a/examples/MHDTests/CoolingHaloWithSpin_MHD/run.sh b/examples/MHDTests/CoolingHaloWithSpin_MHD/run.sh
index cfbfb42dd8e7aa3e123e13aa97f276c129d16802..c159430636127e86c78c62cf86189b1b76a7cc4e 100755
--- a/examples/MHDTests/CoolingHaloWithSpin_MHD/run.sh
+++ b/examples/MHDTests/CoolingHaloWithSpin_MHD/run.sh
@@ -2,7 +2,13 @@
 
 # Generate the initial conditions if they are not present.
 echo "Generating initial conditions for the MHD isothermal potential box example..."
-python3 makeIC_MWsize.py 45000 
+python3 makeIC.py 39500 
 
-# Run SWIFT with external potential, SPH and cooling
-../../../swift --external-gravity --self-gravity --hydro --cooling --threads=4 cooling_halo.yml 2>&1 | tee output.log
+# Run SWIFT with external potential, cooling
+#../../../swift --external-gravity --self-gravity --hydro --cooling --stars --star-formation --threads=4 cooling_halo.yml 2>&1 | tee output.log
+
+# Run SWIFT with external potential, cooling, self-gravity and star formation
+#../../../swift --external-gravity --self-gravity --hydro --cooling --stars --star-formation --threads=4 cooling_halo.yml 2>&1 | tee output.log
+
+# Run SWIFT with external potential, cooling, self-gravity, star formation and feedback
+../../../swift --external-gravity --self-gravity --hydro --cooling --stars --star-formation --feedback --sync --threads=4 cooling_halo.yml 2>&1 | tee output.log