diff --git a/Makefile.am b/Makefile.am index fb4eb5f6d6b63a7d0e034e0a3202ac61066e6e25..f92c9f27b046ec067cbc0d9b89861d4bf78b0f07 100644 --- a/Makefile.am +++ b/Makefile.am @@ -19,7 +19,7 @@ ACLOCAL_AMFLAGS = -I m4 # Show the way... -SUBDIRS = src examples doc tests +SUBDIRS = src examples doc tests examples/CoolingTest_Alexei # Non-standard files that should be part of the distribution. EXTRA_DIST = INSTALL.swift .clang-format format.sh diff --git a/configure.ac b/configure.ac index 24afb459d06cd71b855ac5598e10b8885c57bc36..bfab239722a1a97be78744f8ce6fb558facce5f4 100644 --- a/configure.ac +++ b/configure.ac @@ -1556,7 +1556,7 @@ DX_INIT_DOXYGEN(libswift,doc/Doxyfile,doc/) AM_CONDITIONAL([HAVE_DOXYGEN], [test "$ac_cv_path_ac_pt_DX_DOXYGEN" != ""]) # Handle .in files. -AC_CONFIG_FILES([Makefile src/Makefile examples/Makefile doc/Makefile doc/Doxyfile tests/Makefile]) +AC_CONFIG_FILES([Makefile src/Makefile examples/Makefile examples/CoolingTest_Alexei/Makefile doc/Makefile doc/Doxyfile tests/Makefile]) AC_CONFIG_FILES([tests/testReading.sh], [chmod +x tests/testReading.sh]) AC_CONFIG_FILES([tests/testActivePair.sh], [chmod +x tests/testActivePair.sh]) AC_CONFIG_FILES([tests/test27cells.sh], [chmod +x tests/test27cells.sh]) diff --git a/examples/CoolingBox/analytical_test.py b/examples/CoolingBox/analytical_test.py index 281de2b9b90f65e4c7e483778c197f71261b923f..62c33d0d87cf7af8beee92d6f6955befc3f53973 100644 --- a/examples/CoolingBox/analytical_test.py +++ b/examples/CoolingBox/analytical_test.py @@ -46,8 +46,10 @@ def convert_u_to_temp_sol(u,rho): k_b = 1.38E-16 #boltzmann m_p = 1.67e-24 #proton mass gamma = 5.0/3.0 + n = 2.0*0.752*rho/m_p + 0.248*rho/(4.0*m_p) pressure = u*rho*(gamma - 1.0) - temp = pressure/(k_b*rho/(0.59*m_p)) + temp = pressure/(k_b*n) + #temp = pressure/(k_b*rho/(0.59*m_p)) return temp # File containing the total energy @@ -55,6 +57,7 @@ stats_filename = "./energy.txt" # First snapshot snap_filename = "coolingBox_0000.hdf5" +snap_filename_mat = "../../../swiftsim_matthieu_cooling_v2/examples/CoolingBox/coolingBox_0000.hdf5" # Some constants in cgs units k_b = 1.38E-16 #boltzmann @@ -65,7 +68,9 @@ T_init = 1.0e7 # Read the initial state of the gas f = h5.File(snap_filename,'r') +f_mat = h5.File(snap_filename_mat,'r') rho = np.mean(f["/PartType0/Density"]) +rho_mat = np.mean(f["/PartType0/Density"]) pressure = np.mean(f["/PartType0/Pressure"]) # Read the units parameters from the snapshot @@ -84,9 +89,10 @@ yHe = 0.28 temp_0 = 1.0e7 rho = rho*unit_mass/(unit_length**3) +rho_mat = rho_mat*unit_mass/(unit_length**3) # Read snapshots -nsnap = 110 +nsnap = 501 npart = 4096 u_snapshots_cgs = zeros(nsnap) u_part_snapshots_cgs = zeros((nsnap,npart)) @@ -96,6 +102,17 @@ for i in range(nsnap): u_part_snapshots_cgs[i][:] = snap["/PartType0/InternalEnergy"][:]*unit_length**2/(unit_time**2) t_snapshots_cgs[i] = snap["/Header"].attrs["Time"] * unit_time +# Read snapshots +#nsnap_mat = 25 +#npart = 4096 +#u_snapshots_cgs_mat = zeros(nsnap_mat) +#u_part_snapshots_cgs_mat = zeros((nsnap_mat,npart)) +#t_snapshots_cgs_mat = zeros(nsnap_mat) +#for i in range(nsnap_mat): +# snap = h5.File("../../../swiftsim_matthieu_cooling_v2/examples/CoolingBox/coolingBox_%0.4d.hdf5"%i,'r') +# u_part_snapshots_cgs_mat[i][:] = snap["/PartType0/InternalEnergy"][:]*unit_length**2/(unit_time**2) +# t_snapshots_cgs_mat[i] = snap["/Header"].attrs["Time"] * unit_time + # calculate analytic solution. Since cooling rate is constant, # temperature decrease in linear in time. # read Lambda and temperatures from table @@ -108,44 +125,49 @@ for line in file_in: cooling_rate.append(-float(data[1])) tfinal = t_snapshots_cgs[nsnap-1] -nt = 1e4 +nt = 1e5 dt = tfinal/nt t_sol = np.zeros(int(nt)) temp_sol = np.zeros(int(nt)) +u_sol = np.zeros(int(nt)) lambda_sol = np.zeros(int(nt)) u = np.mean(u_part_snapshots_cgs[0,:]) temp_sol[0] = convert_u_to_temp_sol(u,rho) #print(u,temp_sol[0]) +u_sol[0] = u for j in range(int(nt-1)): t_sol[j+1] = t_sol[j] + dt - Lambda_net = interpol_lambda(temperature,cooling_rate,temp_sol[j]) - #u_next = (u*m_p - Lambda_net*rho/(0.59*m_p)*dt)/m_p - nH = 0.7*rho/(m_p) - #nH = 9.125e-5 + Lambda_net = interpol_lambda(temperature,cooling_rate,u_sol[j]) + nH = 0.702*rho/(m_p) + #nH = 1.0e-4 u_next = u - Lambda_net*nH**2/rho*dt - #print(u_next, u, Lambda_net,rho/(0.59*m_p),dt) - #print(nH**2/rho*Lambda_net, dt) temp_sol[j+1] = convert_u_to_temp_sol(u_next,rho) - lambda_sol[j] = Lambda_net + u_sol[j+1] = u_next + #lambda_sol[j] = Lambda_net u = u_next + +print(u, Lambda_net) mean_temp = np.zeros(nsnap) +mean_u = np.zeros(nsnap) for j in range(nsnap): mean_temp[j] = convert_u_to_temp_sol(np.mean(u_part_snapshots_cgs[j,:]),rho) -p = figure() -p1, = plot(t_sol,temp_sol,linewidth = 0.5,color = 'k',label = 'analytical') -p2, = plot(t_snapshots_cgs,mean_temp,linewidth = 0.5,color = 'r',label = 'swift mean') + mean_u[j] = np.mean(u_part_snapshots_cgs[j,:]) +#mean_temp_mat = np.zeros(nsnap_mat) +#for j in range(nsnap_mat): +# mean_temp_mat[j] = convert_u_to_temp_sol(np.mean(u_part_snapshots_cgs_mat[j,:]),rho_mat) + +p = plt.figure(figsize = (6,6)) +p1, = plt.loglog(t_sol,u_sol,linewidth = 0.5,color = 'k', marker = '*', markersize = 1.5,label = 'explicit ODE') +p2, = plt.loglog(t_snapshots_cgs,mean_u,linewidth = 0.5,color = 'r', marker = '*', markersize = 1.5,label = 'swift mean') l = legend(handles = [p1,p2]) -plt.ticklabel_format(style='sci', axis='y', scilimits=(0,0)) -xlabel("${\\rm{Time~[s]}}$", labelpad=0) -ylabel("${\\rm{Temperature~[K]}}$") +xlabel("${\\rm{Time~[s]}}$", labelpad=0, fontsize = 14) +ylabel("Internal energy ${\\rm{[erg \cdot g^{-1}]}}$", fontsize = 14) +title('$n_h = 1 \\rm{cm}^{-3}, z = 0$, zero metallicity,\n relative error: ' + "{0:.4f}".format( (u_sol[int(nt)-1] - mean_u[nsnap-1])/(u_sol[int(nt)-1])), fontsize = 16) +#plt.ylim([8.0e11,3.0e12]) savefig("energy.png", dpi=200) -#p = figure() -#p1, = loglog(temp_sol,lambda_sol,linewidth = 0.5,color = 'k',label = 'analytical') -#xlabel("${\\rm{Temperature~[K]}}$") -#ylabel("${\\rm{Cooling~rate}}$") - -#savefig("cooling.png", dpi=200) +print('Final internal energy ode, swift, error ' + str(u_sol[int(nt)-1]) + ' ' + str(mean_u[nsnap-1]) + ' ' + str( (u_sol[int(nt)-1] - mean_u[nsnap-1])/(u_sol[int(nt)-1]))) +#print(u_sol[int(nt)-1], mean_u[nsnap-1], (u_sol[int(nt)-1] - mean_u[nsnap-1])/(u_sol[int(nt)-1])) diff --git a/examples/CoolingBox/makeIC.py b/examples/CoolingBox/makeIC.py index 4c376663bf1987203334d1199295e04c65c7c13d..aa0597c05fecabf007af0b4cda84bbf4f324c2b0 100644 --- a/examples/CoolingBox/makeIC.py +++ b/examples/CoolingBox/makeIC.py @@ -27,8 +27,8 @@ from numpy import * # Parameters periodic= 1 # 1 For periodic box boxSize = 1 # 1 kiloparsec -rho = 3.2e6 # Density in code units (3.2e6 is 0.1 hydrogen atoms per cm^3) -P = 4.5e7 # Pressure in code units (at 10^6K) +rho = 3.271e7 # Density in code units (3.2e6 is 0.1 hydrogen atoms per cm^3) +P = 4.5e9 # Pressure in code units (at 10^6K) gamma = 5./3. # Gas adiabatic index eta = 1.2349 # 48 ngbs with cubic spline kernel fileName = "coolingBox.hdf5" diff --git a/examples/CoolingTest_Alexei/Makefile.am b/examples/CoolingTest_Alexei/Makefile.am new file mode 100644 index 0000000000000000000000000000000000000000..e878a3792a84f7ace5f3b60fcc5875169145731b --- /dev/null +++ b/examples/CoolingTest_Alexei/Makefile.am @@ -0,0 +1,32 @@ +# 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 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 General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# Add the source directory and the non-standard paths to the included library headers to CFLAGS +AM_CFLAGS = -I$(top_srcdir)/src $(HDF5_CPPFLAGS) + +AM_LDFLAGS = $(HDF5_LDFLAGS) $(HDF5_LIBS) $(FFTW_LIBS) $(TCMALLOC_LIBS) $(JEMALLOC_LIBS) $(TBBMALLOC_LIBS) $(GRACKLE_LIBS) $(GSL_LIBS) $(PROFILER_LIBS) + +# Extra libraries. +EXTRA_LIBS = $(HDF5_LIBS) + +# Programs. +bin_PROGRAMS = testCooling + +# Sources +testCooling_SOURCES = testCooling.c +testCooling_CFLAGS = $(MYFLAGS) $(AM_CFLAGS) +testCooling_LDADD = ../../src/.libs/libswiftsim.a $(EXTRA_LIBS) + diff --git a/examples/CoolingTest_Alexei/plots.py b/examples/CoolingTest_Alexei/plots.py new file mode 100644 index 0000000000000000000000000000000000000000..969e6de713a4c421cc14d5f88ef68bafaab59a41 --- /dev/null +++ b/examples/CoolingTest_Alexei/plots.py @@ -0,0 +1,58 @@ +import matplotlib.pyplot as plt + +elements = 11 +temperature = [] +cooling_rate = [[] for i in range(elements+1)] +u = [] +fu = [] +length = 0 +file_in = open('cooling_output.dat', 'r') +for line in file_in: + data = line.split() + temperature.append(float(data[0])) + cooling_rate[0].append(-float(data[1])) + +file_in.close() + +for elem in range(elements): + file_in = open('cooling_element_'+str(elem)+'.dat','r') + for line in file_in: + data = line.split() + cooling_rate[elem+1].append(-float(data[0])) + file_in.close() + +#file_in = open('newton_output.dat', 'r') +#for line in file_in: +# data = line.split() +# u.append(float(data[0])) +# fu.append(float(data[1])) +# +#file_in.close() + +#p0, = plt.plot(u,fu, color = 'k') +#p1, = plt.plot(u,[0 for x in u], color = 'r') +#p1, = plt.loglog(u,[-x for x in fu], color = 'r') +#plt.xlim([1e13,2.0e14]) +#plt.ylim([0e13,2e14]) +#plt.xlabel('u') +#plt.ylabel('f(u)') +#plt.show() + +p0, = plt.loglog(temperature, cooling_rate[0], linewidth = 0.5, color = 'k', label = 'Total') +p1, = plt.loglog(temperature, cooling_rate[1], linewidth = 0.5, color = 'k', linestyle = '--', label = 'H + He') +p2, = plt.loglog(temperature, cooling_rate[3], linewidth = 0.5, color = 'b', label = 'Carbon') +p3, = plt.loglog(temperature, cooling_rate[4], linewidth = 0.5, color = 'g', label = 'Nitrogen') +p4, = plt.loglog(temperature, cooling_rate[5], linewidth = 0.5, color = 'r', label = 'Oxygen') +p5, = plt.loglog(temperature, cooling_rate[6], linewidth = 0.5, color = 'c', label = 'Neon') +p6, = plt.loglog(temperature, cooling_rate[7], linewidth = 0.5, color = 'm', label = 'Magnesium') +p7, = plt.loglog(temperature, cooling_rate[8], linewidth = 0.5, color = 'y', label = 'Silicon') +p8, = plt.loglog(temperature, cooling_rate[9], linewidth = 0.5, color = 'lightgray', label = 'Sulphur') +p9, = plt.loglog(temperature, cooling_rate[10], linewidth = 0.5, color = 'olive', label = 'Calcium') +p10, = plt.loglog(temperature, cooling_rate[11], linewidth = 0.5, color = 'saddlebrown', label = 'Iron') +#plt.ylim([1e-24,1e-21]) +#plt.xlim([1e2,1e8]) +plt.xlabel('Temperature (K)') +plt.ylabel('Cooling rate (eagle units...)') +plt.legend(handles = [p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10]) +#plt.legend(handles = [p0,p2,p3,p4,p5,p6,p7,p8,p9]) +plt.show() diff --git a/examples/CoolingTest_Alexei/plots_nh.py b/examples/CoolingTest_Alexei/plots_nh.py new file mode 100644 index 0000000000000000000000000000000000000000..ab3300750e2497ec8026dbe2d5c6c7d358f87831 --- /dev/null +++ b/examples/CoolingTest_Alexei/plots_nh.py @@ -0,0 +1,47 @@ +import matplotlib.pyplot as plt + +elements = 6 +temperature = [[] for i in range(elements+1)] +cooling_rate = [[] for i in range(elements+1)] +u = [] +fu = [] +length = 0 + +for elem in range(elements): + file_in = open('cooling_output_'+str(elem)+'.dat','r') + for line in file_in: + data = line.split() + temperature[elem+1].append(float(data[0])) + cooling_rate[elem+1].append(-float(data[1])) + file_in.close() + +#file_in = open('newton_output.dat', 'r') +#for line in file_in: +# data = line.split() +# u.append(float(data[0])) +# fu.append(float(data[1])) +# +#file_in.close() + +#p0, = plt.plot(u,fu, color = 'k') +#p1, = plt.plot(u,[0 for x in u], color = 'r') +#p1, = plt.loglog(u,[-x for x in fu], color = 'r') +#plt.xlim([1e13,2.0e14]) +#plt.ylim([0e13,2e14]) +#plt.xlabel('u') +#plt.ylabel('f(u)') +#plt.show() + +#p0, = plt.loglog(temperature[0], cooling_rate[0], linewidth = 0.5, color = 'k', label = 'Total') +p1, = plt.loglog(temperature[1], cooling_rate[1], linewidth = 0.5, color = 'k', label = 'nh = 10^0') +p2, = plt.loglog(temperature[2], cooling_rate[2], linewidth = 0.5, color = 'b', label = 'nh = 10^-1') +p3, = plt.loglog(temperature[3], cooling_rate[3], linewidth = 0.5, color = 'g', label = 'nh = 10^-2') +p4, = plt.loglog(temperature[4], cooling_rate[4], linewidth = 0.5, color = 'r', label = 'nh = 10^-3') +p5, = plt.loglog(temperature[5], cooling_rate[5], linewidth = 0.5, color = 'c', label = 'nh = 10^-4') +p6, = plt.loglog(temperature[6], cooling_rate[6], linewidth = 0.5, color = 'm', label = 'nh = 10^-5') +plt.ylim([1e-24,1e-21]) +plt.xlim([1e4,1e8]) +plt.legend(handles = [p1,p2,p3,p4,p5,p6]) +plt.xlabel('Temperature (K)') +plt.ylabel('Cooling rate (eagle units...)') +plt.show() diff --git a/examples/CoolingTest_Alexei/testCooling b/examples/CoolingTest_Alexei/testCooling new file mode 100755 index 0000000000000000000000000000000000000000..20183de27bda2a0ecb577a27ab1c103024e98178 Binary files /dev/null and b/examples/CoolingTest_Alexei/testCooling differ diff --git a/examples/CoolingTest_Alexei/testCooling.c b/examples/CoolingTest_Alexei/testCooling.c new file mode 100644 index 0000000000000000000000000000000000000000..273f7a26812d7d898f010c3a2eeea38a289b362b --- /dev/null +++ b/examples/CoolingTest_Alexei/testCooling.c @@ -0,0 +1,416 @@ +/******************************************************************************* + * 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 "cooling.h" +#include "hydro.h" +#include "physical_constants.h" +#include "swift.h" +#include "units.h" + +enum table_index { + EAGLE_Hydrogen = 0, + EAGLE_Helium, + EAGLE_Carbon, + EAGLE_Nitrogen, + EAGLE_Oxygen, + EAGLE_Neon, + EAGLE_Magnesium, + EAGLE_Silicon, + EAGLE_Iron +}; + +void set_quantities(struct part *restrict p, + const struct unit_system *restrict us, + const struct cooling_function_data *restrict cooling, + const struct cosmology *restrict cosmo, + const struct phys_const *restrict internal_const, + float nh, + double u){ + + const float gamma = 5.0/3.0; + double hydrogen_number_density = nh*pow(units_cgs_conversion_factor(us,UNIT_CONV_LENGTH),3)*(1.0/(pow(1.0+cosmo->z,3))); + p->rho = hydrogen_number_density*internal_const->const_proton_mass* + (1.0+p->chemistry_data.metal_mass_fraction[EAGLE_Helium]/p->chemistry_data.metal_mass_fraction[EAGLE_Hydrogen]); + + float scale_factor = 1.0/(1.0+cosmo->z); + float pressure = (u*pow(scale_factor,3))/cooling->internal_energy_scale*p->rho*(gamma -1.0); + p->entropy = pressure/(pow(p->rho,gamma)); +} + +void construct_1d_tables_test(const struct part *restrict p, + const struct cooling_function_data *restrict cooling, + const struct cosmology *restrict cosmo, + const struct phys_const *restrict internal_const, + double *temp_table, + double *H_plus_He_heat_table, + double *H_plus_He_electron_abundance_table, + double *element_electron_abundance_table, + double *element_print_cooling_table, + double *element_cooling_table, + float *abundance_ratio, + float *ub, float *lb){ + + float XH = p->chemistry_data.metal_mass_fraction[chemistry_element_H]; + float HeFrac = p->chemistry_data.metal_mass_fraction[chemistry_element_He] / + (XH + p->chemistry_data.metal_mass_fraction[chemistry_element_He]); + float inn_h = chemistry_get_number_density(p, cosmo, chemistry_element_H, + internal_const) * + cooling->number_density_scale; + + int z_index,He_i,n_h_i; + float dz,d_He,d_n_h; + + get_redshift_index(cosmo->z, &z_index, &dz, cooling); + get_index_1d(cooling->HeFrac, cooling->N_He, HeFrac, &He_i, &d_He); + get_index_1d(cooling->nH, cooling->N_nH, log10(inn_h), &n_h_i, &d_n_h); + printf("testCooling 1d z_index dz nh_i d_nh He_i d_He %d %.5e %d %.5e %d %.5e\n", z_index,dz, n_h_i, d_n_h, He_i, d_He); + + construct_1d_table_from_4d( + p, cooling, cosmo, internal_const, + cooling->table.element_cooling.temperature, + z_index, dz, cooling->N_Redshifts, n_h_i, d_n_h, + cooling->N_nH, He_i, d_He, cooling->N_He, cooling->N_Temp, temp_table, ub, lb); + construct_1d_table_from_4d( + p, cooling, cosmo, internal_const, + cooling->table.element_cooling.H_plus_He_heating, z_index, dz, cooling->N_Redshifts, n_h_i, d_n_h, + cooling->N_nH, He_i, d_He, cooling->N_He, cooling->N_Temp, H_plus_He_heat_table, ub, lb); + construct_1d_table_from_4d( + p, cooling, cosmo, internal_const, + cooling->table.element_cooling.H_plus_He_electron_abundance, z_index, + dz, cooling->N_Redshifts, n_h_i, d_n_h, cooling->N_nH, He_i, d_He, + cooling->N_He, cooling->N_Temp, H_plus_He_electron_abundance_table, ub, lb); + construct_1d_table_from_4d_elements( + p, cooling, cosmo, internal_const, + cooling->table.element_cooling.metal_heating, z_index, dz, cooling->N_Redshifts, + n_h_i, d_n_h, cooling->N_nH, cooling->N_Temp, element_cooling_table,abundance_ratio, ub, lb); + construct_1d_print_table_from_4d_elements( + p, cooling, cosmo, internal_const, + cooling->table.element_cooling.metal_heating, z_index, dz, cooling->N_Redshifts, + n_h_i, d_n_h, cooling->N_nH, cooling->N_Temp, element_print_cooling_table,abundance_ratio, ub, lb); + construct_1d_table_from_3d( + p, cooling, cosmo, internal_const, + cooling->table.element_cooling.electron_abundance, z_index, dz, cooling->N_Redshifts, + n_h_i, d_n_h, cooling->N_nH, cooling->N_Temp, element_electron_abundance_table, ub, lb); + +} + +void compare_dlambda_du( + const struct unit_system *restrict us, + struct part *restrict p, + const struct xpart *restrict xp, + const struct phys_const *restrict internal_const, + const struct cooling_function_data *restrict cooling, + const struct cosmology *restrict cosmo){ + + double H_plus_He_heat_table[176]; + double H_plus_He_electron_abundance_table[176]; + double temp_table[176]; + double element_cooling_table[176]; + double element_print_cooling_table[9 * 176]; + double element_electron_abundance_table[176]; + double rate_element_table[11]; + float *abundance_ratio, cooling_du_dt1, cooling_du_dt2; + double dlambda_du1, dlambda_du2; + + abundance_ratio = malloc((chemistry_element_count + 2)*sizeof(float)); + abundance_ratio_to_solar(p, cooling, abundance_ratio); + + float XH = p->chemistry_data.metal_mass_fraction[chemistry_element_H]; + float HeFrac = p->chemistry_data.metal_mass_fraction[chemistry_element_He] / + (XH + p->chemistry_data.metal_mass_fraction[chemistry_element_He]); + + int z_index,He_i,n_h_i; + float dz,d_He,d_n_h; + get_redshift_index(cosmo->z, &z_index, &dz, cooling); + get_index_1d(cooling->HeFrac, cooling->N_He, HeFrac, &He_i, &d_He); + + float nh = 1.0e-1, u = 1.0e9; + set_quantities(p, us, cooling, cosmo, internal_const, nh, u); + + const float log_10_e = 0.43429448190325182765; + float upper_bound = cooling->Temp[cooling->N_Temp-1]/log_10_e; + float lower_bound = cooling->Temp[0]/log_10_e; + construct_1d_tables_test(p, cooling, cosmo, internal_const, temp_table, + H_plus_He_heat_table, H_plus_He_electron_abundance_table, + element_electron_abundance_table, element_print_cooling_table, + element_cooling_table, abundance_ratio, &upper_bound, &lower_bound); + + float inn_h = chemistry_get_number_density(p, cosmo, chemistry_element_H, + internal_const) * + cooling->number_density_scale; + get_index_1d(cooling->nH, cooling->N_nH, log10(inn_h), &n_h_i, &d_n_h); + printf("testCooling.c 4d z_i dz nh_i d_nh He_i d_He %d %.5e %d %.5e %d %.5e \n", z_index, dz, n_h_i, d_n_h, He_i, d_He); + int nt = 10; + for(int i = 0; i < nt; i++){ + u = pow(10.0,9 + i); + set_quantities(p, us, cooling, cosmo, internal_const, nh, u); + cooling_du_dt1 = eagle_metal_cooling_rate_1d_table(log10(u),&dlambda_du1,H_plus_He_heat_table, + H_plus_He_electron_abundance_table, + element_print_cooling_table, + element_electron_abundance_table, + temp_table, + z_index, dz, n_h_i, d_n_h, He_i, d_He, + p,cooling,cosmo,internal_const,rate_element_table, + abundance_ratio); + cooling_du_dt2 = eagle_metal_cooling_rate(log10(u), + &dlambda_du2,z_index, dz, n_h_i, d_n_h, He_i, d_He, + p,cooling,cosmo,internal_const,NULL, + abundance_ratio); + printf("u du_dt_1d du_dt_4d dlambda_du_1d dlambda_du_4d %.5e %.5e %.5e %.5e %.5e\n",u,cooling_du_dt1,cooling_du_dt2,dlambda_du1,dlambda_du2); + } +} + +void compare_temp( + const struct unit_system *restrict us, + struct part *restrict p, + const struct xpart *restrict xp, + const struct phys_const *restrict internal_const, + const struct cooling_function_data *restrict cooling, + const struct cosmology *restrict cosmo){ + + double H_plus_He_heat_table[176]; + double H_plus_He_electron_abundance_table[176]; + double temp_table[176]; + double element_cooling_table[176]; + double element_print_cooling_table[9 * 176]; + double element_electron_abundance_table[176]; + float *abundance_ratio; + + abundance_ratio = malloc((chemistry_element_count + 2)*sizeof(float)); + abundance_ratio_to_solar(p, cooling, abundance_ratio); + + float XH = p->chemistry_data.metal_mass_fraction[chemistry_element_H]; + float HeFrac = p->chemistry_data.metal_mass_fraction[chemistry_element_He] / + (XH + p->chemistry_data.metal_mass_fraction[chemistry_element_He]); + + int z_index,He_i,n_h_i; + float dz,d_He,d_n_h; + get_redshift_index(cosmo->z, &z_index, &dz, cooling); + get_index_1d(cooling->HeFrac, cooling->N_He, HeFrac, &He_i, &d_He); + + float nh = 1.0e-1, u = 1.0e9; + set_quantities(p, us, cooling, cosmo, internal_const, nh, u); + const float log_10_e = 0.43429448190325182765; + float upper_bound = cooling->Temp[cooling->N_Temp-1]/log_10_e; + float lower_bound = cooling->Temp[0]/log_10_e; + + construct_1d_tables_test(p, cooling, cosmo, internal_const, temp_table, + H_plus_He_heat_table, H_plus_He_electron_abundance_table, + element_electron_abundance_table, element_print_cooling_table, + element_cooling_table, abundance_ratio, &upper_bound, &lower_bound); + float T1d, T4d, delta_u; + float inn_h = chemistry_get_number_density(p, cosmo, chemistry_element_H, + internal_const) * + cooling->number_density_scale; + get_index_1d(cooling->nH, cooling->N_nH, log10(inn_h), &n_h_i, &d_n_h); + printf("testCooling.c z_i dz nh_i d_nh He_i d_He %d %.5e %d %.5e %d %.5e \n", z_index, dz, n_h_i, d_n_h, He_i, d_He); + int nt = 10; + for(int i = 0; i < nt; i++){ + u = pow(10.0,9 + i); + set_quantities(p, us, cooling, cosmo, internal_const, nh, u); + T1d = eagle_convert_u_to_temp_1d_table(log10(u), &delta_u, temp_table, + p,cooling, cosmo, internal_const); + T4d = eagle_convert_u_to_temp(log10(u), &delta_u, z_index, n_h_i, He_i, + dz, d_n_h, d_He, p,cooling, cosmo, internal_const); + printf("u T1d T4d %.5e %.5e %.5e\n",u,pow(10.0,T1d),pow(10.0,T4d)); + } +} + +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 phys_const internal_const; + struct cooling_function_data cooling; + struct cosmology cosmo; + char *parametersFileName = "./testCooling.yml"; + + int tables = 0; + + /* 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); + + /* And dump the parameters as used. */ + parser_write_params_to_file(params, "used_parameters.yml"); + + /* Init units */ + units_init_from_params(&us, params, "InternalUnitSystem"); + phys_const_init(&us, params, &internal_const); + + /* Init chemistry */ + chemistry_init(params, &us, &internal_const, &chem_data); + chemistry_first_init_part(&internal_const, &us, &cosmo, &chem_data, &p, &xp); + chemistry_print(&chem_data); + + /* Init cosmology */ + cosmology_init(params, &us, &internal_const, &cosmo); + cosmology_print(&cosmo); + + /* Init cooling */ + cooling_init(params, &us, &internal_const, &cooling); + cooling_print(&cooling); + + /* Calculate abundance ratios */ + float *abundance_ratio; + abundance_ratio = malloc((chemistry_element_count + 2)*sizeof(float)); + abundance_ratio_to_solar(&p, &cooling, abundance_ratio); + + /* Declare 1D tables */ + double H_plus_He_heat_table[176]; + double H_plus_He_electron_abundance_table[176]; + double temp_table[176]; + double element_cooling_table[176]; + double element_print_cooling_table[9 * 176]; + double element_electron_abundance_table[176]; + + float nh; + + float XH = p.chemistry_data.metal_mass_fraction[chemistry_element_H]; + float HeFrac = p.chemistry_data.metal_mass_fraction[chemistry_element_He] / + (XH + p.chemistry_data.metal_mass_fraction[chemistry_element_He]); + int z_index,He_i,n_h_i; + float dz,d_He,d_n_h; + get_redshift_index(cosmo.z, &z_index, &dz, &cooling); + get_index_1d(cooling.HeFrac, cooling.N_He, HeFrac, &He_i, &d_He); + + const float log_10_e = 0.43429448190325182765; + float upper_bound = cooling.Temp[cooling.N_Temp-1]/log_10_e; + float lower_bound = cooling.Temp[0]/log_10_e; + + /* Loop over densities */ + int nt = 250, n_nh = 6; + double u = pow(10.0,10); + if (argc == 1 || strcmp(argv[1], "nh") == 0){ + for(int i = 0; i < n_nh; i++){ + /* Open files */ + char output_filename[21]; + sprintf(output_filename, "%s%d%s", "cooling_output_", i, ".dat"); + FILE *output_file = fopen(output_filename, "w"); + if (output_file == NULL) { + printf("Error opening file!\n"); + exit(1); + } + + nh = pow(10.0,-i); + set_quantities(&p, &us, &cooling, &cosmo, &internal_const, nh, u); + construct_1d_tables_test(&p, &cooling, &cosmo, &internal_const, + temp_table, H_plus_He_heat_table, + H_plus_He_electron_abundance_table, + element_electron_abundance_table, + element_print_cooling_table, + element_cooling_table, + abundance_ratio, &upper_bound, &lower_bound); + get_index_1d(cooling.nH, cooling.N_nH, log10(nh), &n_h_i, &d_n_h); + + for(int j = 0; j < nt; j++){ + set_quantities(&p, &us, &cooling, &cosmo, &internal_const, nh, pow(10.0,11.0 + j*8.0/nt)); + u = hydro_get_physical_internal_energy(&p,&cosmo)*cooling.internal_energy_scale; + double dlambda_du; + float delta_u, cooling_du_dt, logT; + if (tables == 1) { + cooling_du_dt = eagle_metal_cooling_rate_1d_table(log10(u),&dlambda_du,H_plus_He_heat_table, + H_plus_He_electron_abundance_table, + element_print_cooling_table, + element_electron_abundance_table, + temp_table, + z_index, dz, n_h_i, d_n_h, He_i, d_He, + &p,&cooling,&cosmo,&internal_const,NULL, + abundance_ratio); + logT = eagle_convert_u_to_temp_1d_table(log10(u), &delta_u, temp_table, + &p,&cooling, &cosmo, &internal_const); + } else { + cooling_du_dt = eagle_metal_cooling_rate(log10(u), + &dlambda_du,z_index, dz, n_h_i, d_n_h, He_i, d_He, + &p,&cooling,&cosmo,&internal_const,NULL, + abundance_ratio); + logT = eagle_convert_u_to_temp(log10(u), &delta_u, z_index, n_h_i, He_i, + dz, d_n_h, d_He, &p,&cooling, &cosmo, &internal_const); + } + float temperature_swift = pow(10.0,logT); + + fprintf(output_file,"%.5e %.5e\n", temperature_swift,cooling_du_dt); + } + fclose(output_file); + } + } + if (argc == 1 || strcmp(argv[1],"metals") == 0) { + printf("here \n"); + char output_filename[21]; + sprintf(output_filename, "%s", "cooling_output.dat"); + FILE *output_file = fopen(output_filename, "w"); + if (output_file == NULL) { + printf("Error opening file!\n"); + exit(1); + } + nh = pow(10.0,0); + u = pow(10.0,14.0); + set_quantities(&p, &us, &cooling, &cosmo, &internal_const, nh, u); + float nh_swift = chemistry_get_number_density(&p, &cosmo, chemistry_element_H, &internal_const)*cooling.number_density_scale; + printf("hydrogen number density %.5e\n", nh_swift); + construct_1d_tables_test(&p, &cooling, &cosmo, &internal_const, + temp_table, H_plus_He_heat_table, + H_plus_He_electron_abundance_table, + element_electron_abundance_table, + element_print_cooling_table, + element_cooling_table, + abundance_ratio, &upper_bound, &lower_bound); + float inn_h = chemistry_get_number_density(&p, &cosmo, chemistry_element_H, + &internal_const) * + cooling.number_density_scale; + get_index_1d(cooling.nH, cooling.N_nH, log10(inn_h), &n_h_i, &d_n_h); + printf("testcooling.c z_i dz nh_i d_nh He_i d_He %d %.5e %d %.5e %d %.5e\n",z_index, dz, n_h_i, d_n_h, He_i, d_He); + for(int j = 0; j < nt; j++){ + set_quantities(&p, &us, &cooling, &cosmo, &internal_const, nh, pow(10.0,10.0 + j*8.0/nt)); + u = hydro_get_physical_internal_energy(&p,&cosmo)*cooling.internal_energy_scale; + float delta_u, cooling_du_dt, logT; + if (tables == 1) { + cooling_du_dt = eagle_print_metal_cooling_rate_1d_table(H_plus_He_heat_table, + H_plus_He_electron_abundance_table, + element_print_cooling_table, + element_electron_abundance_table, + temp_table, + z_index, dz, n_h_i, d_n_h, He_i, d_He, + &p,&cooling,&cosmo,&internal_const, + abundance_ratio); + logT = eagle_convert_u_to_temp_1d_table(log10(u), &delta_u, temp_table, + &p,&cooling, &cosmo, &internal_const); + } else { + cooling_du_dt = eagle_print_metal_cooling_rate( + z_index, dz, n_h_i, d_n_h, He_i, d_He, + &p,&cooling,&cosmo,&internal_const, + abundance_ratio); + } + fprintf(output_file,"%.5e %.5e\n", u,cooling_du_dt); + } + fclose(output_file); + } + + if (argc == 1 || strcmp(argv[1],"compare_temp") == 0) compare_temp(&us, &p, &xp, &internal_const, &cooling, &cosmo); + if (argc == 1 || strcmp(argv[1],"compare_dlambda_du") == 0) compare_dlambda_du(&us, &p, &xp, &internal_const, &cooling, &cosmo); + + free(params); + return 0; +} + + diff --git a/examples/CoolingTest_Alexei/testCooling.yml b/examples/CoolingTest_Alexei/testCooling.yml new file mode 100644 index 0000000000000000000000000000000000000000..8426042ac7f2e7d18f9fc98b978bfcdad429be4a --- /dev/null +++ b/examples/CoolingTest_Alexei/testCooling.yml @@ -0,0 +1,94 @@ +# Define the system of units to use internally. +InternalUnitSystem: + UnitMass_in_cgs: 1.989e43 # 10^10 M_sun in grams + UnitLength_in_cgs: 3.085678e24 # 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.9090909 # Initial scale-factor of the simulation + a_begin: 1.0 # 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: 1e-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: 1e-4 # The maximal time-step size of the simulation (in internal units). + +Scheduler: + max_top_level_cells: 15 + +# Parameters governing the snapshots +Snapshots: + basename: eagle # Common part of the name of output files + scale_factor_first: 0.92 # Scale-factor of the first snaphot (cosmological run) + time_first: 0.01 # Time of the first output (non-cosmological run) (in internal units) + delta_time: 1.10 # Time difference between consecutive outputs (in internal units) + compression: 1 + +# Parameters governing the conserved quantities statistics +Statistics: + scale_factor_first: 0.92 # Scale-factor of the first stat dump (cosmological run) + time_first: 0.01 # Time of the first stat dump (non-cosmological run) (in internal units) + delta_time: 1.05 # Time between statistics output + +# Parameters for the self-gravity scheme +Gravity: + eta: 0.025 # Constant dimensionless multiplier for time integration. + theta: 0.85 # Opening angle (Multipole acceptance criterion) + comoving_softening: 0.0026994 # Comoving softening length (in internal units). + max_physical_softening: 0.0007 # Physical softening length (in internal units). + +# 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. + minimal_temperature: 100 # (internal units) + +# Parameters related to the initial conditions +InitialConditions: + file_name: ./EAGLE_ICs_12.hdf5 # The file to read + cleanup_h_factors: 1 # Remove the h-factors inherited from Gadget + +EAGLEChemistry: + InitMetallicity: 0.014 + InitAbundance_Hydrogen: 0.70649785 + InitAbundance_Helium: 0.28055534 + InitAbundance_Carbon: 2.0665436e-3 + InitAbundance_Nitrogen: 8.3562563e-4 + InitAbundance_Oxygen: 5.4926244e-3 + InitAbundance_Neon: 1.4144605e-3 + InitAbundance_Magnesium: 5.907064e-4 + InitAbundance_Silicon: 6.825874e-4 + InitAbundance_Iron: 1.1032152e-3 + CalciumOverSilicon: 0.0941736 + SulphurOverSilicon: 0.6054160 + #InitMetallicity: 0. + #InitAbundance_Hydrogen: 0.752 + #InitAbundance_Helium: 0.248 + #InitAbundance_Carbon: 0.000 + #InitAbundance_Nitrogen: 0.000 + #InitAbundance_Oxygen: 0.000 + #InitAbundance_Neon: 0.000 + #InitAbundance_Magnesium: 0.000 + #InitAbundance_Silicon: 0.000 + #InitAbundance_Iron: 0.000 + #CalciumOverSilicon: 0.0941736 + #SulphurOverSilicon: 0.6054160 + +EagleCooling: + filename: /cosma5/data/Eagle/BG_Tables/CoolingTables/ + reionisation_redshift: 8.898 + he_reion: 1 + he_reion_z_center: 3.5 + he_reion_z_sigma: 0.5 + he_reion_ev_pH: 2.0 + diff --git a/examples/CoolingTest_Alexei/testCooling_messy.c b/examples/CoolingTest_Alexei/testCooling_messy.c new file mode 100644 index 0000000000000000000000000000000000000000..b5c00e5625c43e57e46c5f8426640b9f511bc58a --- /dev/null +++ b/examples/CoolingTest_Alexei/testCooling_messy.c @@ -0,0 +1,354 @@ +/******************************************************************************* + * 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 "cooling.h" +#include "hydro.h" +#include "physical_constants.h" +#include "swift.h" +#include "units.h" + +int main(int argc, char **argv) { + + /* Read the parameter file */ + 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 phys_const internal_const; + struct cooling_function_data cooling; + struct cosmology cosmo; + char *parametersFileName = "./testCooling.yml"; + enum table_index { + EAGLE_Hydrogen = 0, + EAGLE_Helium, + EAGLE_Carbon, + EAGLE_Nitrogen, + EAGLE_Oxygen, + EAGLE_Neon, + EAGLE_Magnesium, + EAGLE_Silicon, + EAGLE_Iron + }; + + if (params == NULL) error("Error allocating memory for the parameter file."); + message("Reading runtime parameters from file '%s'", parametersFileName); + parser_read_file(parametersFileName, params); + + /* And dump the parameters as used. */ + parser_write_params_to_file(params, "used_parameters.yml"); + + double UnitMass_in_cgs = 1.989e43; + double UnitLength_in_cgs = 3.085678e24; + double UnitVelocity_in_cgs = 1e5; + double UnitCurrent_in_cgs = 1; + double UnitTemp_in_cgs = 1; + units_init(&us, UnitMass_in_cgs, UnitLength_in_cgs, UnitVelocity_in_cgs, UnitCurrent_in_cgs, UnitTemp_in_cgs); + phys_const_init(&us, params, &internal_const); + + double hydrogen_number_density_cgs = 1e-4; + double u, u_cgs, hydrogen_number_density, pressure, gamma, cooling_du_dt, + temperature_cgs, newton_func, u_ini_cgs, ratefact, dt_cgs; + u_cgs = 0; + cooling_du_dt = 0; + temperature_cgs = 0; + newton_func = 0; + // int n_t_i = 2000; + dt_cgs = 4.0e-8 * units_cgs_conversion_factor(&us, UNIT_CONV_TIME); + + char *output_filename = "cooling_output.dat"; + FILE *output_file = fopen(output_filename, "w"); + if (output_file == NULL) { + printf("Error opening file!\n"); + exit(1); + } + char *output_filename2 = "temperature_output.dat"; + FILE *output_file2 = fopen(output_filename2, "w"); + if (output_file2 == NULL) { + printf("Error opening file!\n"); + exit(1); + } + char *output_filename3 = "newton_output.dat"; + FILE *output_file3 = fopen(output_filename3, "w"); + if (output_file3 == NULL) { + printf("Error opening file!\n"); + exit(1); + } + + gamma = 5.0 / 3.0; + + chemistry_init(params, &us, &internal_const, &chem_data); + chemistry_first_init_part(&internal_const, &us, &cosmo, &chem_data, &p, &xp); + chemistry_print(&chem_data); + + cosmology_init(params, &us, &internal_const, &cosmo); + cosmology_print(&cosmo); + + u = 1.0 * pow(10.0, 11) / + (units_cgs_conversion_factor(&us, UNIT_CONV_ENERGY) / + units_cgs_conversion_factor(&us, UNIT_CONV_MASS)); + pressure = u * p.rho * (gamma - 1.0); + hydrogen_number_density = + hydrogen_number_density_cgs * + pow(units_cgs_conversion_factor(&us, UNIT_CONV_LENGTH), 3); + p.rho = hydrogen_number_density * internal_const.const_proton_mass * + (1.0 + + p.chemistry_data.metal_mass_fraction[EAGLE_Helium] / + p.chemistry_data.metal_mass_fraction[EAGLE_Hydrogen]); + p.entropy = pressure / (pow(p.rho, gamma)); + + cooling_init(params, &us, &internal_const, &cooling); + cooling_print(&cooling); + + float XH = p.chemistry_data.metal_mass_fraction[chemistry_element_H]; + float HeFrac = p.chemistry_data.metal_mass_fraction[chemistry_element_He] / + (XH + p.chemistry_data.metal_mass_fraction[chemistry_element_He]); + float inn_h = chemistry_get_number_density(&p, &cosmo, chemistry_element_H, + &internal_const) * + cooling.number_density_scale; + ratefact = inn_h * (XH / eagle_proton_mass_cgs); + + float *abundance_ratio; + abundance_ratio = malloc((chemistry_element_count + 2)*sizeof(float)); + abundance_ratio_to_solar(&p, &cooling, abundance_ratio); + + // construct 1d table of cooling rates wrt temperature + double H_plus_He_heat_table[176]; + double H_plus_He_electron_abundance_table[176]; + double temp_table[176]; + double element_cooling_table[176]; + double element_print_cooling_table[9 * 176]; + double element_electron_abundance_table[176]; + + int z_index,He_i,n_h_i; + float dz,d_He,d_n_h; + get_redshift_index(cosmo.z, &z_index, &dz, &cooling); + get_index_1d(cooling.HeFrac, cooling.N_He, HeFrac, &He_i, &d_He); + get_index_1d(cooling.nH, cooling.N_nH, log10(inn_h), &n_h_i, &d_n_h); + + construct_1d_table_from_4d( + &p, &cooling, &cosmo, &internal_const, + cooling.table.element_cooling.temperature, + z_index, dz, cooling.N_Redshifts, n_h_i, d_n_h, + cooling.N_nH, He_i, d_He, cooling.N_He, cooling.N_Temp, temp_table); + construct_1d_table_from_4d( + &p, &cooling, &cosmo, &internal_const, + cooling.table.element_cooling.H_plus_He_heating, z_index, dz, cooling.N_Redshifts, n_h_i, d_n_h, + cooling.N_nH, He_i, d_He, cooling.N_He, cooling.N_Temp, H_plus_He_heat_table); + construct_1d_table_from_4d( + &p, &cooling, &cosmo, &internal_const, + cooling.table.element_cooling.H_plus_He_electron_abundance, z_index, + dz, cooling.N_Redshifts, n_h_i, d_n_h, cooling.N_nH, He_i, d_He, + cooling.N_He, cooling.N_Temp, H_plus_He_electron_abundance_table); + construct_1d_table_from_4d_elements( + &p, &cooling, &cosmo, &internal_const, + cooling.table.element_cooling.metal_heating, z_index, dz, cooling.N_Redshifts, + n_h_i, d_n_h, cooling.N_nH, cooling.N_Temp, element_cooling_table,abundance_ratio); + construct_1d_print_table_from_4d_elements( + &p, &cooling, &cosmo, &internal_const, + cooling.table.element_cooling.metal_heating, z_index, dz, cooling.N_Redshifts, + n_h_i, d_n_h, cooling.N_nH, cooling.N_Temp, element_print_cooling_table,abundance_ratio); + construct_1d_table_from_3d( + &p, &cooling, &cosmo, &internal_const, + cooling.table.element_cooling.electron_abundance, z_index, dz, cooling.N_Redshifts, + n_h_i, d_n_h, cooling.N_nH, cooling.N_Temp, element_electron_abundance_table); + + + // + // printf("cooling table values \n"); + // for( int j=0; j < 176; j++) { + // printf(" %.5e", H_plus_He_heat_table[j]+element_cooling_table[j] + u_ini_cgs = pow(10.0, 14); + float delta_u; + + + //Compute contributions to cooling rate from different metals + // int n_t_i = 100; + // for(int t_i = 0; t_i < n_t_i; t_i++){ + // u_cgs = pow(10.0,11 + t_i*6.0/n_t_i); + // //u = u_cgs/(units_cgs_conversion_factor(&us,UNIT_CONV_ENERGY)/units_cgs_conversion_factor(&us,UNIT_CONV_MASS)); + // u = u_cgs/cooling.internal_energy_scale; + // hydrogen_number_density = + // hydrogen_number_density_cgs*pow(units_cgs_conversion_factor(&us,UNIT_CONV_LENGTH),3); + // p.rho = + // hydrogen_number_density*internal_const.const_proton_mass*(1.0+p.chemistry_data.metal_mass_fraction[EAGLE_Helium]/p.chemistry_data.metal_mass_fraction[EAGLE_Hydrogen]); + // pressure = u*p.rho*(gamma -1.0); + // p.entropy = pressure/(pow(p.rho,gamma)); + // double u_swift = hydro_get_physical_internal_energy(&p, &cosmo) * + // cooling.internal_energy_scale; + + // cooling_du_dt = eagle_print_metal_cooling_rate_1d_table(H_plus_He_heat_table, + // H_plus_He_electron_abundance_table, + // element_print_cooling_table, + // element_electron_abundance_table, + // temp_table, + // z_index, dz, n_h_i, d_n_h, He_i, d_He, + // &p,&cooling,&cosmo,&internal_const, + // abundance_ratio); + // float logT = eagle_convert_u_to_temp_1d_table(log10(u_swift), &delta_u, temp_table, + // &p,&cooling, &cosmo, &internal_const); + // float temperature_swift = pow(10.0,logT); + + // fprintf(output_file,"%.5e %.5e\n", temperature_swift,cooling_du_dt); + // fprintf(output_file2,"%.5e %.5e\n",u_swift*(units_cgs_conversion_factor(&us,UNIT_CONV_ENERGY)/units_cgs_conversion_factor(&us,UNIT_CONV_MASS)), + // temperature_cgs); + + // newton_func = u_cgs - u_ini_cgs - cooling_du_dt*ratefact*dt_cgs; + // fprintf(output_file3,"%.5e %.5e\n",u_cgs,newton_func); + // //printf("u,u_ini,cooling_du_dt,ratefact,dt %.5e %.5e %.5e %.5e %.5e + // // \n",u_cgs,u_ini_cgs,cooling_du_dt,ratefact,dt_cgs); + //} + + int n_t_i = 100; + for(int nh_i = 1; nh_i < 7; nh_i++){ + char output_filename4[21]; + sprintf(output_filename4, "%s%d%s", "cooling_output_", nh_i, ".dat"); + FILE *output_file4 = fopen(output_filename4, "w"); + if (output_file4 == NULL) { + printf("Error opening file!\n"); + exit(1); + } + hydrogen_number_density = pow(10.0,-nh_i)*pow(units_cgs_conversion_factor(&us,UNIT_CONV_LENGTH),3)*(1.0/(pow(1.0+cosmo.z,3))); + p.rho = + hydrogen_number_density*internal_const.const_proton_mass*(1.0+p.chemistry_data.metal_mass_fraction[EAGLE_Helium]/p.chemistry_data.metal_mass_fraction[EAGLE_Hydrogen]); + + XH = p.chemistry_data.metal_mass_fraction[chemistry_element_H]; + HeFrac = p.chemistry_data.metal_mass_fraction[chemistry_element_He] / + (XH + p.chemistry_data.metal_mass_fraction[chemistry_element_He]); + inn_h = chemistry_get_number_density(&p, &cosmo, chemistry_element_H, + &internal_const) * + cooling.number_density_scale; + ratefact = inn_h * (XH / eagle_proton_mass_cgs); + printf("test cooling hydrogen num dens inn_h %.5e %.5e\n", hydrogen_number_density*cooling.number_density_scale, inn_h); + + abundance_ratio = malloc((chemistry_element_count + 2)*sizeof(float)); + abundance_ratio_to_solar(&p, &cooling, abundance_ratio); + + get_redshift_index(cosmo.z, &z_index, &dz, &cooling); + get_index_1d(cooling.HeFrac, cooling.N_He, HeFrac, &He_i, &d_He); + get_index_1d(cooling.nH, cooling.N_nH, log10(inn_h), &n_h_i, &d_n_h); + + construct_1d_table_from_4d( + &p, &cooling, &cosmo, &internal_const, + cooling.table.element_cooling.temperature, + z_index, dz, cooling.N_Redshifts, n_h_i, d_n_h, + cooling.N_nH, He_i, d_He, cooling.N_He, cooling.N_Temp, temp_table); + construct_1d_table_from_4d( + &p, &cooling, &cosmo, &internal_const, + cooling.table.element_cooling.H_plus_He_heating, z_index, dz, cooling.N_Redshifts, n_h_i, d_n_h, + cooling.N_nH, He_i, d_He, cooling.N_He, cooling.N_Temp, H_plus_He_heat_table); + construct_1d_table_from_4d( + &p, &cooling, &cosmo, &internal_const, + cooling.table.element_cooling.H_plus_He_electron_abundance, z_index, + dz, cooling.N_Redshifts, n_h_i, d_n_h, cooling.N_nH, He_i, d_He, + cooling.N_He, cooling.N_Temp, H_plus_He_electron_abundance_table); + construct_1d_table_from_4d_elements( + &p, &cooling, &cosmo, &internal_const, + cooling.table.element_cooling.metal_heating, z_index, dz, cooling.N_Redshifts, + n_h_i, d_n_h, cooling.N_nH, cooling.N_Temp, element_cooling_table,abundance_ratio); + construct_1d_print_table_from_4d_elements( + &p, &cooling, &cosmo, &internal_const, + cooling.table.element_cooling.metal_heating, z_index, dz, cooling.N_Redshifts, + n_h_i, d_n_h, cooling.N_nH, cooling.N_Temp, element_print_cooling_table,abundance_ratio); + construct_1d_table_from_3d( + &p, &cooling, &cosmo, &internal_const, + cooling.table.element_cooling.electron_abundance, z_index, dz, cooling.N_Redshifts, + n_h_i, d_n_h, cooling.N_nH, cooling.N_Temp, element_electron_abundance_table); + for(int t_i = 0; t_i < n_t_i; t_i++){ + u_cgs = pow(10.0,11 + t_i*6.0/n_t_i); + u = u_cgs/cooling.internal_energy_scale; + pressure = u*p.rho*(gamma -1.0); + p.entropy = pressure/(pow(p.rho,gamma)); + double u_swift = hydro_get_physical_internal_energy(&p, &cosmo) * + cooling.internal_energy_scale; + + double dlambda_du; + cooling_du_dt = eagle_metal_cooling_rate_1d_table(log10(u_swift),&dlambda_du,H_plus_He_heat_table, + H_plus_He_electron_abundance_table, + element_print_cooling_table, + element_electron_abundance_table, + temp_table, + z_index, dz, n_h_i, d_n_h, He_i, d_He, + &p,&cooling,&cosmo,&internal_const,NULL, + abundance_ratio); + float logT = eagle_convert_u_to_temp_1d_table(log10(u_swift), &delta_u, temp_table, + &p,&cooling, &cosmo, &internal_const); + float temperature_swift = pow(10.0,logT); + + fprintf(output_file4,"%.5e %.5e\n", temperature_swift,cooling_du_dt); + fprintf(output_file2,"%.5e %.5e\n",u_swift*(units_cgs_conversion_factor(&us,UNIT_CONV_ENERGY)/units_cgs_conversion_factor(&us,UNIT_CONV_MASS)), + temperature_cgs); + + newton_func = u_cgs - u_ini_cgs - cooling_du_dt*ratefact*dt_cgs; + fprintf(output_file3,"%.5e %.5e\n",u_cgs,newton_func); + } + fclose(output_file4); + } + fclose(output_file); + fclose(output_file2); + fclose(output_file3); + + //double dLambdaNet_du, LambdaNet; //, LambdaNext; + //float x_init, u_eq = 2.0e12; + //for (int j = 5; j < 6; j++) { + // float u_ini = eagle_convert_temp_to_u_1d_table(pow(10.0, 0.5 * (j + 5)), + // temp_table, &p, &cooling, + // &cosmo, &internal_const), + // x, du; + // float dt = 2.0e-4 * units_cgs_conversion_factor(&us, UNIT_CONV_TIME); + // LambdaNet = eagle_cooling_rate_1d_table( + // u_ini, &dLambdaNet_du, H_plus_He_heat_table, + // H_plus_He_electron_abundance_table, element_cooling_table, + // element_electron_abundance_table, temp_table, &p, &cooling, &cosmo, + // &internal_const); + // float u_temp = u_ini + LambdaNet * ratefact * dt; + // /* RGB removed this ** + // if (u_temp > 0) LambdaNext = eagle_cooling_rate_1d_table(u_temp, + // &dLambdaNet_du, H_plus_He_heat_table, H_plus_He_electron_abundance_table, + // element_cooling_table, element_electron_abundance_table, temp_table, &p, + // &cooling, &cosmo, &internal_const); + // if (fabs(LambdaNet - LambdaNext)/LambdaNet < 0.5) { + // u_temp = u_ini; + // } else { + // u_temp = + // eagle_convert_temp_to_u_1d_table(1.0e4,temp_table,&p,&cooling,&cosmo,&internal_const); + // } */ + // if (u_temp > u_eq) { + // x_init = log(u_temp); + // } else { + // x_init = log(u_eq); + // } + // x = newton_iter(x_init, u_ini, H_plus_He_heat_table, + // H_plus_He_electron_abundance_table, element_cooling_table, + // element_electron_abundance_table, temp_table, &p, &cosmo, + // &cooling, &internal_const, dt); + // printf( + // "testing newton integration, u_ini, u %.5e %.5e, temperature initial, " + // "final %.5e %.5e\n", + // u_ini, exp(x), + // eagle_convert_u_to_temp_1d_table(u_ini, &du, temp_table, &p, &cooling, + // &cosmo, &internal_const), + // eagle_convert_u_to_temp_1d_table(exp(x), &du, temp_table, &p, &cooling, + // &cosmo, &internal_const)); + //} + + free(params); + + return 0; +} diff --git a/src/cooling/EAGLE/.cooling.h.swp b/src/cooling/EAGLE/.cooling.h.swp new file mode 100644 index 0000000000000000000000000000000000000000..dbf1ffd09a09fea79583fc056bc56c16c449684f Binary files /dev/null and b/src/cooling/EAGLE/.cooling.h.swp differ diff --git a/src/cooling/EAGLE/.eagle_cool_tables.h.swp b/src/cooling/EAGLE/.eagle_cool_tables.h.swp new file mode 100644 index 0000000000000000000000000000000000000000..8e230bda82187c4455ad6dcefc873ee472ddd69a Binary files /dev/null and b/src/cooling/EAGLE/.eagle_cool_tables.h.swp differ diff --git a/src/cooling/EAGLE/cooling.h b/src/cooling/EAGLE/cooling.h index b0530e517b6f68b0ac2c21e28ba6cd813c09a0ca..998bfdbc3230700ee4055ebe430f5a36be7daabb 100644 --- a/src/cooling/EAGLE/cooling.h +++ b/src/cooling/EAGLE/cooling.h @@ -528,6 +528,54 @@ __attribute__((always_inline)) INLINE float interpol_4d( return result; } +/* + * @brief Interpolates 2d EAGLE table in redshift and hydrogen + * number density. Produces 1d table depending only + * on log(temperature) + * + * @param p Particle structure + * @param cooling Cooling data structure + * @param cosmo Cosmology structure + * @param internal_const Physical constants structure + * @param table Pointer to table we are interpolating + * @param z_i Redshift index + * @param d_z Redshift offset + * @param n_h_i Hydrogen number density index + * @param d_n_h Hydrogen number density offset + * @param result_table Pointer to 1d interpolated table + */ +__attribute__((always_inline)) INLINE static void construct_1d_table_from_2d( + const struct part *restrict p, + const struct cooling_function_data *restrict cooling, + const struct cosmology *restrict cosmo, + const struct phys_const *internal_const, float *table, int x_i, float d_x, + int n_x, int array_size, double *result_table, float *ub, float *lb) { + + const double log_10 = 2.302585092994; + int index_low, index_high; + float d_high, d_low; + + get_index_1d(cooling->Temp, cooling->N_Temp,(*ub)/log_10,&index_high,&d_high); + get_index_1d(cooling->Temp, cooling->N_Temp,(*lb)/log_10,&index_low,&d_low); + if (index_high < array_size-1) { + index_high += 2; + } else { + index_high = array_size; + } + if (index_low > 0) index_low--; + + int index[2]; + for (int i = index_low; i < index_high; i++) { + index[0] = row_major_index_2d(x_i, i, n_x, + array_size); + index[1] = row_major_index_2d(x_i + 1, i, n_x, + array_size); + + result_table[i] = (1 - d_x) * table[index[0]] + + d_x * table[index[1]]; + } +} + /* * @brief Interpolates 3d EAGLE table in redshift and hydrogen * number density. Produces 1d table depending only @@ -548,24 +596,37 @@ __attribute__((always_inline)) INLINE static void construct_1d_table_from_3d( const struct part *restrict p, const struct cooling_function_data *restrict cooling, const struct cosmology *restrict cosmo, - const struct phys_const *internal_const, float *table, int z_i, float d_z, - int n_h_i, float d_n_h, double *result_table) { - int index[4]; + const struct phys_const *internal_const, float *table, int x_i, float d_x, + int n_x, int y_i, float d_y, int n_y, int array_size, double *result_table, float *ub, float *lb) { + + const double log_10 = 2.302585092994; + int index_low, index_high; + float d_high, d_low; + + get_index_1d(cooling->Temp, cooling->N_Temp,(*ub)/log_10,&index_high,&d_high); + get_index_1d(cooling->Temp, cooling->N_Temp,(*lb)/log_10,&index_low,&d_low); + if (index_high < array_size-1) { + index_high += 2; + } else { + index_high = array_size; + } + if (index_low > 0) index_low--; - for (int i = 0; i < cooling->N_Temp; i++) { - index[0] = row_major_index_3d(z_i, n_h_i, i, cooling->N_Redshifts, - cooling->N_nH, cooling->N_Temp); - index[1] = row_major_index_3d(z_i, n_h_i + 1, i, cooling->N_Redshifts, - cooling->N_nH, cooling->N_Temp); - index[2] = row_major_index_3d(z_i + 1, n_h_i, i, cooling->N_Redshifts, - cooling->N_nH, cooling->N_Temp); - index[3] = row_major_index_3d(z_i + 1, n_h_i + 1, i, cooling->N_Redshifts, - cooling->N_nH, cooling->N_Temp); - - result_table[i] = (1 - d_z) * (1 - d_n_h) * table[index[0]] + - (1 - d_z) * d_n_h * table[index[1]] + - d_z * (1 - d_n_h) * table[index[2]] + - d_z * d_n_h * table[index[3]]; + int index[4]; + for (int i = index_low; i < index_high; i++) { + index[0] = row_major_index_3d(x_i, y_i, i, n_x, + n_y, array_size); + index[1] = row_major_index_3d(x_i, y_i + 1, i, n_x, + n_y, array_size); + index[2] = row_major_index_3d(x_i + 1, y_i, i, n_x, + n_y, array_size); + index[3] = row_major_index_3d(x_i + 1, y_i + 1, i, n_x, + n_y, array_size); + + result_table[i] = (1 - d_x) * (1 - d_y) * table[index[0]] + + (1 - d_x) * d_y * table[index[1]] + + d_x * (1 - d_y) * table[index[2]] + + d_x * d_y * table[index[3]]; } } @@ -598,74 +659,67 @@ construct_1d_table_from_4d_H_He( const struct part *restrict p, const struct cooling_function_data *restrict cooling, const struct cosmology *restrict cosmo, - const struct phys_const *internal_const, float *table, int z_i, float d_z, - int He_i, float d_He, int n_h_i, float d_n_h, double *result_table, - double *x_max_grad, double u_ini, float dt) { - int index[8]; - float x0, x1, y0, y1, old_grad, new_grad; - float inn_h = chemistry_get_number_density(p, cosmo, chemistry_element_H, - internal_const) * - cooling->number_density_scale; - float XH = p->chemistry_data.metal_mass_fraction[chemistry_element_H]; - float ratefact = inn_h * (XH / eagle_proton_mass_cgs); - - old_grad = 0.0; + const struct phys_const *internal_const, float *table, int x_i, float d_x, int n_x, + int y_i, float d_y, int n_y, int w_i, float d_w, int n_w, int array_size, double *result_table, + double *x_max_grad, double u_ini, float dt, float *ub, float *lb) { + + const double log_10 = 2.302585092994; + int index_low, index_high; + float d_high, d_low; + + get_index_1d(cooling->Temp, cooling->N_Temp,(*ub)/log_10,&index_high,&d_high); + get_index_1d(cooling->Temp, cooling->N_Temp,(*lb)/log_10,&index_low,&d_low); + if (index_high < array_size-1) { + index_high += 2; + } else { + index_high = array_size; + } + if (index_low > 0) index_low--; - for (int i = 0; i < cooling->N_Temp; i++) { + int index[8]; + for (int i = index_low; i < index_high; i++) { index[0] = - row_major_index_4d(z_i, n_h_i, He_i, i, cooling->N_Redshifts, - cooling->N_nH, cooling->N_He, cooling->N_Temp); + row_major_index_4d(x_i, y_i, w_i, i, n_x, + n_y, n_w, array_size); index[1] = - row_major_index_4d(z_i, n_h_i, He_i + 1, i, cooling->N_Redshifts, - cooling->N_nH, cooling->N_He, cooling->N_Temp); + row_major_index_4d(x_i, y_i, w_i + 1, i, n_x, + n_y, n_w, array_size); index[2] = - row_major_index_4d(z_i, n_h_i + 1, He_i, i, cooling->N_Redshifts, - cooling->N_nH, cooling->N_He, cooling->N_Temp); + row_major_index_4d(x_i, y_i + 1, w_i, i, n_x, + n_y, n_w, array_size); index[3] = - row_major_index_4d(z_i, n_h_i + 1, He_i + 1, i, cooling->N_Redshifts, - cooling->N_nH, cooling->N_He, cooling->N_Temp); + row_major_index_4d(x_i, y_i + 1, w_i + 1, i, n_x, + n_y, n_w, array_size); index[4] = - row_major_index_4d(z_i + 1, n_h_i, He_i, i, cooling->N_Redshifts, - cooling->N_nH, cooling->N_He, cooling->N_Temp); + row_major_index_4d(x_i + 1, y_i, w_i, i, n_x, + n_y, n_w, array_size); index[5] = - row_major_index_4d(z_i + 1, n_h_i, He_i + 1, i, cooling->N_Redshifts, - cooling->N_nH, cooling->N_He, cooling->N_Temp); + row_major_index_4d(x_i + 1, y_i, w_i + 1, i, n_x, + n_y, n_w, array_size); index[6] = - row_major_index_4d(z_i + 1, n_h_i + 1, He_i, i, cooling->N_Redshifts, - cooling->N_nH, cooling->N_He, cooling->N_Temp); - index[7] = row_major_index_4d(z_i + 1, n_h_i + 1, He_i + 1, i, - cooling->N_Redshifts, cooling->N_nH, - cooling->N_He, cooling->N_Temp); - - result_table[i] = (1 - d_z) * (1 - d_n_h) * (1 - d_He) * table[index[0]] + - (1 - d_z) * (1 - d_n_h) * d_He * table[index[1]] + - (1 - d_z) * d_n_h * (1 - d_He) * table[index[2]] + - (1 - d_z) * d_n_h * d_He * table[index[3]] + - d_z * (1 - d_n_h) * (1 - d_He) * table[index[4]] + - d_z * (1 - d_n_h) * d_He * table[index[5]] + - d_z * d_n_h * (1 - d_He) * table[index[6]] + - d_z * d_n_h * d_He * table[index[7]]; + row_major_index_4d(x_i + 1, y_i + 1, w_i, i, n_x, + n_y, n_w, array_size); + index[7] = row_major_index_4d(x_i + 1, y_i + 1, w_i + 1, i, + n_x, n_y, + n_w, array_size); + + result_table[i] = (1 - d_x) * (1 - d_y) * (1 - d_w) * table[index[0]] + + (1 - d_x) * (1 - d_y) * d_w * table[index[1]] + + (1 - d_x) * d_y * (1 - d_w) * table[index[2]] + + (1 - d_x) * d_y * d_w * table[index[3]] + + d_x * (1 - d_y) * (1 - d_w) * table[index[4]] + + d_x * (1 - d_y) * d_w * table[index[5]] + + d_x * d_y * (1 - d_w) * table[index[6]] + + d_x * d_y * d_w * table[index[7]]; #if SWIFT_DEBUG_CHECKS if (isnan(result_table[i])) printf( "Eagle cooling.h 1 i dz dnh dHe table values %d %.5e %.5e %.5e %.5e " "%.5e %.5e %.5e %.5e %.5e %.5e %.5e \n", - i, d_z, d_n_h, d_He, table[index[0]], table[index[1]], + i, d_x, d_y, d_w, table[index[0]], table[index[1]], table[index[2]], table[index[3]], table[index[4]], table[index[5]], table[index[6]], table[index[7]]); #endif - if (i > 0 && dt > 0 && x_max_grad != NULL) { - x0 = pow(10.0, cooling->Therm[i - 1]); - x1 = pow(10.0, cooling->Therm[i]); - y0 = x0 - u_ini - result_table[i - 1] * ratefact * dt; - y1 = x1 - u_ini - result_table[i] * ratefact * dt; - new_grad = log10(y1 / y0) / log10(x1 / x0); - if (new_grad > old_grad) { - *x_max_grad = 0.5 * (x0 + x1); - old_grad = new_grad; - } - //printf("Eagle cooling.h id grad max_grad x_max_grad %llu %.5e %.5e %.5e\n", p->id, new_grad, old_grad, *x_max_grad); - } } } @@ -691,49 +745,63 @@ __attribute__((always_inline)) INLINE static void construct_1d_table_from_4d( const struct part *restrict p, const struct cooling_function_data *restrict cooling, const struct cosmology *restrict cosmo, - const struct phys_const *internal_const, float *table, int z_i, float d_z, - int He_i, float d_He, int n_h_i, float d_n_h, double *result_table) { + const struct phys_const *internal_const, float *table, int x_i, float d_x, int n_x, + int y_i, float d_y, int n_y, int w_i, float d_w, int n_w, int array_size, double *result_table, float *ub, float *lb) { + + const double log_10 = 2.302585092994; + int index_low, index_high; + float d_high, d_low; + + get_index_1d(cooling->Temp, cooling->N_Temp,(*ub)/log_10,&index_high,&d_high); + get_index_1d(cooling->Temp, cooling->N_Temp,(*lb)/log_10,&index_low,&d_low); + if (index_high < array_size-1) { + index_high += 2; + } else { + index_high = array_size; + } + if (index_low > 0) index_low--; + int index[8]; - for (int i = 0; i < cooling->N_Temp; i++) { + for (int i = index_low; i < index_high; i++) { index[0] = - row_major_index_4d(z_i, n_h_i, He_i, i, cooling->N_Redshifts, - cooling->N_nH, cooling->N_He, cooling->N_Temp); + row_major_index_4d(x_i, y_i, w_i, i, n_x, + n_y, n_w, array_size); index[1] = - row_major_index_4d(z_i, n_h_i, He_i + 1, i, cooling->N_Redshifts, - cooling->N_nH, cooling->N_He, cooling->N_Temp); + row_major_index_4d(x_i, y_i, w_i + 1, i, n_x, + n_y, n_w, array_size); index[2] = - row_major_index_4d(z_i, n_h_i + 1, He_i, i, cooling->N_Redshifts, - cooling->N_nH, cooling->N_He, cooling->N_Temp); + row_major_index_4d(x_i, y_i + 1, w_i, i, n_x, + n_y, n_w, array_size); index[3] = - row_major_index_4d(z_i, n_h_i + 1, He_i + 1, i, cooling->N_Redshifts, - cooling->N_nH, cooling->N_He, cooling->N_Temp); + row_major_index_4d(x_i, y_i + 1, w_i + 1, i, n_x, + n_y, n_w, array_size); index[4] = - row_major_index_4d(z_i + 1, n_h_i, He_i, i, cooling->N_Redshifts, - cooling->N_nH, cooling->N_He, cooling->N_Temp); + row_major_index_4d(x_i + 1, y_i, w_i, i, n_x, + n_y, n_w, array_size); index[5] = - row_major_index_4d(z_i + 1, n_h_i, He_i + 1, i, cooling->N_Redshifts, - cooling->N_nH, cooling->N_He, cooling->N_Temp); + row_major_index_4d(x_i + 1, y_i, w_i + 1, i, n_x, + n_y, n_w, array_size); index[6] = - row_major_index_4d(z_i + 1, n_h_i + 1, He_i, i, cooling->N_Redshifts, - cooling->N_nH, cooling->N_He, cooling->N_Temp); - index[7] = row_major_index_4d(z_i + 1, n_h_i + 1, He_i + 1, i, - cooling->N_Redshifts, cooling->N_nH, - cooling->N_He, cooling->N_Temp); - - result_table[i] = (1 - d_z) * (1 - d_n_h) * (1 - d_He) * table[index[0]] + - (1 - d_z) * (1 - d_n_h) * d_He * table[index[1]] + - (1 - d_z) * d_n_h * (1 - d_He) * table[index[2]] + - (1 - d_z) * d_n_h * d_He * table[index[3]] + - d_z * (1 - d_n_h) * (1 - d_He) * table[index[4]] + - d_z * (1 - d_n_h) * d_He * table[index[5]] + - d_z * d_n_h * (1 - d_He) * table[index[6]] + - d_z * d_n_h * d_He * table[index[7]]; + row_major_index_4d(x_i + 1, y_i + 1, w_i, i, n_x, + n_y, n_w, array_size); + index[7] = row_major_index_4d(x_i + 1, y_i + 1, w_i + 1, i, + n_x, n_y, + n_w, array_size); + + result_table[i] = (1 - d_x) * (1 - d_y) * (1 - d_w) * table[index[0]] + + (1 - d_x) * (1 - d_y) * d_w * table[index[1]] + + (1 - d_x) * d_y * (1 - d_w) * table[index[2]] + + (1 - d_x) * d_y * d_w * table[index[3]] + + d_x * (1 - d_y) * (1 - d_w) * table[index[4]] + + d_x * (1 - d_y) * d_w * table[index[5]] + + d_x * d_y * (1 - d_w) * table[index[6]] + + d_x * d_y * d_w * table[index[7]]; #if SWIFT_DEBUG_CHECKS if (isnan(result_table[i])) printf( "Eagle cooling.h 2 i dz dnh dHe table values %d %.5e %.5e %.5e %.5e " "%.5e %.5e %.5e %.5e %.5e %.5e %.5e \n", - i, d_z, d_n_h, d_He, table[index[0]], table[index[1]], + i, d_x, d_y, d_w, table[index[0]], table[index[1]], table[index[2]], table[index[3]], table[index[4]], table[index[5]], table[index[6]], table[index[7]]); #endif @@ -773,6 +841,88 @@ __attribute__((always_inline)) INLINE double eagle_helium_reionization_extraheat return extra_heating; } +/* + * @brief Interpolates 4d EAGLE metal cooling tables in redshift, + * helium fraction and hydrogen number density. + * Produces 1d table depending only on log(temperature) + * NOTE: Will need to be modified to incorporate particle to solar + * electron abundance ratio. + * + * @param p Particle structure + * @param cooling Cooling data structure + * @param cosmo Cosmology structure + * @param internal_const Physical constants structure + * @param table Pointer to table we are interpolating + * @param z_i Redshift index + * @param d_z Redshift offset + * @param He_i Helium fraction index + * @param d_He Helium fraction offset + * @param n_h_i Hydrogen number density index + * @param d_n_h Hydrogen number density offset + * @param result_table Pointer to 1d interpolated table + */ +__attribute__((always_inline)) INLINE static void +construct_1d_print_table_from_4d_elements( + const struct part *restrict p, + const struct cooling_function_data *restrict cooling, + const struct cosmology *restrict cosmo, + const struct phys_const *internal_const, float *table, int x_i, float d_x, + int n_x, int y_i, float d_y, int n_y, int array_size, double *result_table, float *abundance_ratio, float *ub, float *lb) { + + const double log_10 = 2.302585092994; + int index_low, index_high; + float d_high, d_low; + + get_index_1d(cooling->Temp, cooling->N_Temp,(*ub)/log_10,&index_high,&d_high); + get_index_1d(cooling->Temp, cooling->N_Temp,(*lb)/log_10,&index_low,&d_low); + if (index_high < array_size-1) { + index_high += 2; + } else { + index_high = array_size; + } + if (index_low > 0) index_low--; + + int index[4]; + + for (int j = 0; j < cooling->N_Elements; j++) { + for (int i = index_low; i < index_high; i++) { + if (j == 0) result_table[i] = 0.0; + index[0] = row_major_index_4d(x_i, j, y_i, i, n_x, + cooling->N_Elements, n_y, + array_size); + index[1] = row_major_index_4d(x_i, j, y_i + 1, i, n_x, + cooling->N_Elements, n_y, + array_size); + index[2] = row_major_index_4d(x_i + 1, j, y_i, i, n_x, + cooling->N_Elements, n_y, + array_size); + index[3] = row_major_index_4d(x_i + 1, j, y_i + 1, i, + n_x, cooling->N_Elements, + n_y, array_size); + + result_table[i+array_size*j] = ((1 - d_x) * (1 - d_y) * table[index[0]] + + (1 - d_x) * d_y * table[index[1]] + + d_x * (1 - d_y) * table[index[2]] + + d_x * d_y * table[index[3]]) * abundance_ratio[j+2]; +#if SWIFT_DEBUG_CHECKS + if (isnan(result_table[i])) + printf( + "Eagle cooling.h 3 i partial sums %d %.5e %.5e %.5e %.5e %.5e \n", + i, result_table[i], (1 - d_x) * (1 - d_y) * table[index[0]], + (1 - d_x) * (1 - d_y) * table[index[0]] + + (1 - d_x) * d_y * table[index[1]], + (1 - d_x) * (1 - d_y) * table[index[0]] + + (1 - d_x) * d_y * table[index[1]] + + d_x * (1 - d_y) * table[index[2]], + (1 - d_x) * (1 - d_y) * table[index[0]] + + (1 - d_x) * d_y * table[index[1]] + + d_x * (1 - d_y) * table[index[2]] + + d_x * d_y * table[index[3]]); +#endif + } + } +} + /* * @brief Interpolates 4d EAGLE metal cooling tables in redshift, * helium fraction and hydrogen number density. @@ -798,44 +948,123 @@ construct_1d_table_from_4d_elements( const struct part *restrict p, const struct cooling_function_data *restrict cooling, const struct cosmology *restrict cosmo, - const struct phys_const *internal_const, float *table, int z_i, float d_z, - int n_h_i, float d_n_h, double *result_table) { + const struct phys_const *internal_const, float *table, int x_i, float d_x, + int n_x, int y_i, float d_y, int n_y, int array_size, double *result_table, float *abundance_ratio, float *ub, float *lb) { int index[4]; + const double log_10 = 2.302585092994; + int index_low, index_high; + float d_high, d_low; + + get_index_1d(cooling->Temp, cooling->N_Temp,(*ub)/log_10,&index_high,&d_high); + get_index_1d(cooling->Temp, cooling->N_Temp,(*lb)/log_10,&index_low,&d_low); + if (index_high < array_size-1) { + index_high += 2; + } else { + index_high = array_size; + } + if (index_low > 0) index_low--; + for (int j = 0; j < cooling->N_Elements; j++) { - for (int i = 0; i < cooling->N_Temp; i++) { + for (int i = index_low; i < index_high; i++) { if (j == 0) result_table[i] = 0.0; - index[0] = row_major_index_4d(z_i, j, n_h_i, i, cooling->N_Redshifts, - cooling->N_Elements, cooling->N_nH, - cooling->N_Temp); - index[1] = row_major_index_4d(z_i, j, n_h_i + 1, i, cooling->N_Redshifts, - cooling->N_Elements, cooling->N_nH, - cooling->N_Temp); - index[2] = row_major_index_4d(z_i + 1, j, n_h_i, i, cooling->N_Redshifts, - cooling->N_Elements, cooling->N_nH, - cooling->N_Temp); - index[3] = row_major_index_4d(z_i + 1, j, n_h_i + 1, i, - cooling->N_Redshifts, cooling->N_Elements, - cooling->N_nH, cooling->N_Temp); - - result_table[i] += (1 - d_z) * (1 - d_n_h) * table[index[0]] + - (1 - d_z) * d_n_h * table[index[1]] + - d_z * (1 - d_n_h) * table[index[2]] + - d_z * d_n_h * table[index[3]]; + index[0] = row_major_index_4d(x_i, j, y_i, i, n_x, + cooling->N_Elements, n_y, + array_size); + index[1] = row_major_index_4d(x_i, j, y_i + 1, i, n_x, + cooling->N_Elements, n_y, + array_size); + index[2] = row_major_index_4d(x_i + 1, j, y_i, i, n_x, + cooling->N_Elements, n_y, + array_size); + index[3] = row_major_index_4d(x_i + 1, j, y_i + 1, i, + n_x, cooling->N_Elements, + n_y, array_size); + + result_table[i] += ((1 - d_x) * (1 - d_y) * table[index[0]] + + (1 - d_x) * d_y * table[index[1]] + + d_x * (1 - d_y) * table[index[2]] + + d_x * d_y * table[index[3]]) * abundance_ratio[j+2]; #if SWIFT_DEBUG_CHECKS if (isnan(result_table[i])) printf( "Eagle cooling.h 3 i partial sums %d %.5e %.5e %.5e %.5e %.5e \n", - i, result_table[i], (1 - d_z) * (1 - d_n_h) * table[index[0]], - (1 - d_z) * (1 - d_n_h) * table[index[0]] + - (1 - d_z) * d_n_h * table[index[1]], - (1 - d_z) * (1 - d_n_h) * table[index[0]] + - (1 - d_z) * d_n_h * table[index[1]] + - d_z * (1 - d_n_h) * table[index[2]], - (1 - d_z) * (1 - d_n_h) * table[index[0]] + - (1 - d_z) * d_n_h * table[index[1]] + - d_z * (1 - d_n_h) * table[index[2]] + - d_z * d_n_h * table[index[3]]); + i, result_table[i], (1 - d_x) * (1 - d_y) * table[index[0]], + (1 - d_x) * (1 - d_y) * table[index[0]] + + (1 - d_x) * d_y * table[index[1]], + (1 - d_x) * (1 - d_y) * table[index[0]] + + (1 - d_x) * d_y * table[index[1]] + + d_x * (1 - d_y) * table[index[2]], + (1 - d_x) * (1 - d_y) * table[index[0]] + + (1 - d_x) * d_y * table[index[1]] + + d_x * (1 - d_y) * table[index[2]] + + d_x * d_y * table[index[3]]); +#endif + } + } +} + +/* + * @brief Interpolates 3d EAGLE cooling tables in redshift, + * helium fraction and hydrogen number density. + * Produces 1d table depending only on log(temperature) + * NOTE: Will need to be modified to incorporate particle to solar + * electron abundance ratio. + * + * @param p Particle structure + * @param cooling Cooling data structure + * @param cosmo Cosmology structure + * @param internal_const Physical constants structure + * @param table Pointer to table we are interpolating + * @param z_i Redshift index + * @param d_z Redshift offset + * @param He_i Helium fraction index + * @param d_He Helium fraction offset + * @param n_h_i Hydrogen number density index + * @param d_n_h Hydrogen number density offset + * @param result_table Pointer to 1d interpolated table + */ +__attribute__((always_inline)) INLINE static void +construct_1d_table_from_3d_elements( + const struct part *restrict p, + const struct cooling_function_data *restrict cooling, + const struct cosmology *restrict cosmo, + const struct phys_const *internal_const, float *table, int x_i, float d_x, + int n_x, int array_size, double *result_table, float *abundance_ratio, float *ub, float *lb) { + int index[2]; + + const double log_10 = 2.302585092994; + int index_low, index_high; + float d_high, d_low; + + get_index_1d(cooling->Temp, cooling->N_Temp,(*ub)/log_10,&index_high,&d_high); + get_index_1d(cooling->Temp, cooling->N_Temp,(*lb)/log_10,&index_low,&d_low); + if (index_high < array_size-1) { + index_high += 2; + } else { + index_high = array_size; + } + if (index_low > 0) index_low--; + + for (int j = 0; j < cooling->N_Elements; j++) { + for (int i = index_low; i < index_high; i++) { + if (j == 0) result_table[i] = 0.0; + index[0] = row_major_index_3d(j, x_i, i, + cooling->N_Elements, n_x, + array_size); + index[1] = row_major_index_3d(j, x_i + 1, i, + cooling->N_Elements, n_x, + array_size); + + result_table[i] += ((1 - d_x) * table[index[0]] + + d_x * table[index[1]])*abundance_ratio[j+2]; +#if SWIFT_DEBUG_CHECKS + if (isnan(result_table[i])) + printf( + "Eagle cooling.h 3 i partial sums %d %.5e %.5e %.5e \n", + i, result_table[i], (1 - d_x) * table[index[0]], + (1 - d_x) * table[index[0]] + + d_x * table[index[1]]); #endif } } @@ -1003,6 +1232,41 @@ eagle_convert_temp_to_u_1d_table(double temp, float *temperature_table, return u; } +/* + * @brief Interpolates temperature from internal energy based on table and + * calculates the size of the internal energy cell for the specified + * temperature. + * + * @param u Internal energy + * @param delta_u Pointer to size of internal energy cell + * @param temperature_table Table of EAGLE temperature values + * @param cooling Cooling data structure + */ +__attribute__((always_inline)) INLINE static double +eagle_convert_u_to_temp( + double log_10_u, float *delta_u, + int z_i, int n_h_i, int He_i, + float d_z, float d_n_h, float d_He, + const struct part *restrict p, + const struct cooling_function_data *restrict cooling, + const struct cosmology *restrict cosmo, + const struct phys_const *internal_const) { + + int u_i; + float d_u, logT; + + get_index_1d(cooling->Therm, cooling->N_Temp, log_10_u, &u_i, &d_u); + + logT = interpol_4d(cooling->table.element_cooling.temperature, z_i,n_h_i,He_i,u_i,d_z,d_n_h,d_He,d_u, + cooling->N_Redshifts,cooling->N_nH,cooling->N_He,cooling->N_Temp); + + *delta_u = + pow(10.0, cooling->Therm[u_i + 1]) - pow(10.0, cooling->Therm[u_i]); + + return logT; +} + + /* * @brief Interpolates temperature from internal energy based on table and * calculates the size of the internal energy cell for the specified @@ -1015,7 +1279,7 @@ eagle_convert_temp_to_u_1d_table(double temp, float *temperature_table, */ __attribute__((always_inline)) INLINE static double eagle_convert_u_to_temp_1d_table( - double logu, float *delta_u, double *temperature_table, + double log_10_u, float *delta_u, double *temperature_table, const struct part *restrict p, const struct cooling_function_data *restrict cooling, const struct cosmology *restrict cosmo, @@ -1024,13 +1288,9 @@ eagle_convert_u_to_temp_1d_table( int u_i; float d_u, logT;//, T; - get_index_1d(cooling->Therm, cooling->N_Temp, logu, &u_i, &d_u); + get_index_1d(cooling->Therm, cooling->N_Temp, log_10_u, &u_i, &d_u); logT = interpol_1d_dbl(temperature_table, u_i, d_u); - //T = pow(10.0, logT); - - //if (u_i == 0 && d_u == 0) T *= u / pow(10.0, cooling->Therm[0]); - if (u_i == 0 && d_u == 0) logT += logu - cooling->Therm[0]; *delta_u = pow(10.0, cooling->Therm[u_i + 1]) - pow(10.0, cooling->Therm[u_i]); @@ -1057,29 +1317,34 @@ eagle_convert_u_to_temp_1d_table( * from each of the metals. */ __attribute__((always_inline)) INLINE static double eagle_metal_cooling_rate( - double logu, double *temp_table, int z_index, float dz, int n_h_i, float d_n_h, + double log_10_u, double *dlambda_du, int z_index, float dz, int n_h_i, float d_n_h, int He_i, float d_He, const struct part *restrict p, const struct cooling_function_data *restrict cooling, const struct cosmology *restrict cosmo, const struct phys_const *internal_const, double *element_lambda, - float *ratio_solar) { - double T_gam, solar_electron_abundance; + float *solar_ratio) { + double T_gam, solar_electron_abundance, solar_electron_abundance1, solar_electron_abundance2, elem_cool1, elem_cool2; double n_h = chemistry_get_number_density(p, cosmo, chemistry_element_H, internal_const) * cooling->number_density_scale; // chemistry_data double z = cosmo->z; - double cooling_rate = 0.0, temp_lambda; + double cooling_rate = 0.0, temp_lambda, temp_lambda1, temp_lambda2; float du; float h_plus_he_electron_abundance; + float h_plus_he_electron_abundance1; + float h_plus_he_electron_abundance2; int i; double temp; int temp_i; float d_temp; - temp = eagle_convert_u_to_temp_1d_table(logu, &du, temp_table, p, cooling, cosmo, - internal_const); + *dlambda_du = 0.0; + + temp = eagle_convert_u_to_temp(log_10_u, &du, z_index, n_h_i, He_i, + dz, d_n_h, d_He, p, + cooling, cosmo, internal_const); get_index_1d(cooling->Temp, cooling->N_Temp, temp, &temp_i, &d_temp); @@ -1113,11 +1378,29 @@ __attribute__((always_inline)) INLINE static double eagle_metal_cooling_rate( z_index, n_h_i, He_i, temp_i, dz, d_n_h, d_He, d_temp, cooling->N_Redshifts, cooling->N_nH, cooling->N_He, cooling->N_Temp); + temp_lambda1 = interpol_4d(cooling->table.element_cooling.H_plus_He_heating, + z_index, n_h_i, He_i, temp_i, dz, d_n_h, d_He, + 0.0, cooling->N_Redshifts, cooling->N_nH, + cooling->N_He, cooling->N_Temp); + temp_lambda2 = interpol_4d(cooling->table.element_cooling.H_plus_He_heating, + z_index, n_h_i, He_i, temp_i+1, dz, d_n_h, d_He, + 0.0, cooling->N_Redshifts, cooling->N_nH, + cooling->N_He, cooling->N_Temp); h_plus_he_electron_abundance = interpol_4d( cooling->table.element_cooling.H_plus_He_electron_abundance, z_index, n_h_i, He_i, temp_i, dz, d_n_h, d_He, d_temp, cooling->N_Redshifts, cooling->N_nH, cooling->N_He, cooling->N_Temp); + h_plus_he_electron_abundance1 = interpol_4d( + cooling->table.element_cooling.H_plus_He_electron_abundance, z_index, + n_h_i, He_i, temp_i, dz, d_n_h, d_He, 0.0, cooling->N_Redshifts, + cooling->N_nH, cooling->N_He, cooling->N_Temp); + h_plus_he_electron_abundance2 = interpol_4d( + cooling->table.element_cooling.H_plus_He_electron_abundance, z_index, + n_h_i, He_i, temp_i+1, dz, d_n_h, d_He, 0.0, cooling->N_Redshifts, + cooling->N_nH, cooling->N_He, cooling->N_Temp); cooling_rate += temp_lambda; + //printf("Eagle cooling.h 4d H_plus_He_cooling electron abundance %.5e %.5e\n", temp_lambda, h_plus_he_electron_abundance); + *dlambda_du += (temp_lambda2 - temp_lambda1)/du; if (element_lambda != NULL) element_lambda[0] = temp_lambda; /* ------------------ */ @@ -1181,18 +1464,37 @@ __attribute__((always_inline)) INLINE static double eagle_metal_cooling_rate( /* redshift tables */ solar_electron_abundance = interpol_3d(cooling->table.element_cooling.electron_abundance, z_index, - n_h_i, dz, temp_i, d_n_h, d_temp, cooling->N_Redshifts, + n_h_i, temp_i, dz, d_n_h, d_temp, cooling->N_Redshifts, + cooling->N_nH, cooling->N_Temp); + solar_electron_abundance1 = + interpol_3d(cooling->table.element_cooling.electron_abundance, z_index, + n_h_i, temp_i, dz, d_n_h, 0.0, cooling->N_Redshifts, + cooling->N_nH, cooling->N_Temp); + solar_electron_abundance2 = + interpol_3d(cooling->table.element_cooling.electron_abundance, z_index, + n_h_i, temp_i+1, dz, d_n_h, 0.0, cooling->N_Redshifts, cooling->N_nH, cooling->N_Temp); for (i = 0; i < cooling->N_Elements; i++) { - // WARNING: before doing proper runs need to - // multiply by ratio of particle abundances to solar temp_lambda = interpol_4d(cooling->table.element_cooling.metal_heating, z_index, i, n_h_i, temp_i, dz, 0.0, d_n_h, d_temp, cooling->N_Redshifts, cooling->N_Elements, cooling->N_nH, cooling->N_Temp) * - (h_plus_he_electron_abundance / solar_electron_abundance); + (h_plus_he_electron_abundance / solar_electron_abundance)* + solar_ratio[i+2]; + elem_cool1 = interpol_4d(cooling->table.element_cooling.metal_heating, z_index, i, + n_h_i, temp_i, dz, 0.0, d_n_h, 0.0, cooling->N_Redshifts, + cooling->N_Elements, cooling->N_nH, cooling->N_Temp); + elem_cool2 = interpol_4d(cooling->table.element_cooling.metal_heating, z_index, i, + n_h_i, temp_i+1, dz, 0.0, d_n_h, 0.0, cooling->N_Redshifts, + cooling->N_Elements, cooling->N_nH, cooling->N_Temp); cooling_rate += temp_lambda; + *dlambda_du += + (elem_cool2 * h_plus_he_electron_abundance2 / + solar_electron_abundance2 - + elem_cool1 * h_plus_he_electron_abundance1 / + solar_electron_abundance1) / du * solar_ratio[i+2]; + //printf("Eagle cooling.h 4d element cooling electron abundance, solar_ratio %d %.5e %.5e %.5e\n", i, temp_lambda, solar_electron_abundance, solar_ratio[i+2]); if (element_lambda != NULL) element_lambda[i + 2] = temp_lambda; } @@ -1256,6 +1558,7 @@ eagle_metal_cooling_rate_1d_table( internal_const); get_index_1d(cooling->Temp, cooling->N_Temp, temp, &temp_i, &d_temp); + //printf("Eagle cooling.h 1d log_10_u, temp, temp_i, d_temp %.5e %.5e %d %.5e\n", log_10_u, temp, temp_i, d_temp); /* ------------------ */ /* Metal-free cooling */ @@ -1290,6 +1593,7 @@ eagle_metal_cooling_rate_1d_table( *dlambda_du += (((double)H_plus_He_heat_table[temp_i + 1]) - ((double)H_plus_He_heat_table[temp_i])) / ((double)du); + //printf("Eagle cooling.h 1d H_plus_He_cooling electron abundance %.5e %.5e\n", temp_lambda, h_plus_he_electron_abundance); if (element_lambda != NULL) element_lambda[0] = temp_lambda; /* ------------------ */ @@ -1354,27 +1658,97 @@ eagle_metal_cooling_rate_1d_table( solar_electron_abundance = interpol_1d_dbl(element_electron_abundance_table, temp_i, d_temp); - for (i = 0; i < cooling->N_Elements; i++) { - temp_lambda = interpol_1d_dbl(element_cooling_table, temp_i, d_temp) * - (h_plus_he_electron_abundance / solar_electron_abundance) * - solar_ratio[i+2]; // hydrogen and helium aren't included here. - cooling_rate += temp_lambda; - *dlambda_du += - (((double)element_cooling_table[temp_i + 1]) * - ((double)H_plus_He_electron_abundance_table[temp_i + 1]) / - ((double)element_electron_abundance_table[temp_i + 1]) - - ((double)element_cooling_table[temp_i]) * - ((double)H_plus_He_electron_abundance_table[temp_i]) / - ((double)element_electron_abundance_table[temp_i])) / - ((double)du); - if (element_lambda != NULL) element_lambda[i + 2] = temp_lambda; - } + //if (element_lambda == NULL) { + // temp_lambda = interpol_1d_dbl(element_cooling_table, temp_i, d_temp) * + // (h_plus_he_electron_abundance / solar_electron_abundance); // hydrogen and helium aren't included here. + // *dlambda_du = + // (((double)element_cooling_table[temp_i + 1]) * + // ((double)H_plus_He_electron_abundance_table[temp_i + 1]) / + // ((double)element_electron_abundance_table[temp_i + 1]) - + // ((double)element_cooling_table[temp_i]) * + // ((double)H_plus_He_electron_abundance_table[temp_i]) / + // ((double)element_electron_abundance_table[temp_i])) / + // ((double)du); + //} else { + for (i = 0; i < cooling->N_Elements; i++) { + temp_lambda = interpol_1d_dbl(element_cooling_table + i*cooling->N_Temp, temp_i, d_temp) * + (h_plus_he_electron_abundance / solar_electron_abundance); // hydrogen and helium aren't included here. + cooling_rate += temp_lambda; + *dlambda_du += + (((double)element_cooling_table[i*cooling->N_Temp + temp_i + 1]) * + ((double)H_plus_He_electron_abundance_table[temp_i + 1]) / + ((double)element_electron_abundance_table[temp_i + 1]) - + ((double)element_cooling_table[i*cooling->N_Temp + temp_i]) * + ((double)H_plus_He_electron_abundance_table[temp_i]) / + ((double)element_electron_abundance_table[temp_i])) / + ((double)du); + if (element_lambda != NULL) element_lambda[i + 2] = temp_lambda; + //printf("Eagle cooling.h 1d element cooling electron abundance, solar_ratio %d %.5e %.5e %.5e\n", i, temp_lambda, solar_electron_abundance, solar_ratio[i+2]); + } + //} //printf("Eagle cooling.h dlambda_du du %.5e %.5e\n", *dlambda_du, du); return cooling_rate; } +/* + * @brief Wrapper function previously used to calculate cooling rate and + * dLambda_du + * Can be used to check whether calculation of dLambda_du is done correctly. + * Should be removed when finished + * + * @param u Internal energy + * @param dlambda_du Pointer to gradient of cooling rate + * @param H_plus_He_heat_table 1D table of heating rates due to H, He + * @param H_plus_He_electron_abundance_table 1D table of electron abundances due + * to H,He + * @param element_cooling_table 1D table of heating rates due to metals + * @param element_electron_abundance_table 1D table of electron abundances due + * to metals + * @param temp_table 1D table of temperatures + * @param z_index Redshift index of particle + * @param dz Redshift offset of particle + * @param n_h_i Particle hydrogen number density index + * @param d_n_h Particle hydrogen number density offset + * @param He_i Particle helium fraction index + * @param d_He Particle helium fraction offset + * @param p Particle structure + * @param cooling Cooling data structure + * @param cosmo Cosmology structure + * @param internal_const Physical constants structure + */ +__attribute__((always_inline)) INLINE static double eagle_cooling_rate( + double logu, double *dLambdaNet_du, int z_index, + float dz, int n_h_i, float d_n_h, int He_i, float d_He, + const struct part *restrict p, + const struct cooling_function_data *restrict cooling, + const struct cosmology *restrict cosmo, + const struct phys_const *internal_const, + float *abundance_ratio) { + double *element_lambda = NULL, lambda_net = 0.0;//, lambda_net1 = 0.0, lambda_net2 = 0.0; + const double log_10 = 2.30258509299404; + + lambda_net = eagle_metal_cooling_rate( + logu/log_10, dLambdaNet_du, z_index, dz, n_h_i, d_n_h, + He_i, d_He, p, cooling, cosmo, internal_const, element_lambda, abundance_ratio); + + //int u_i; + //float du; + //get_index_1d(cooling->Therm, cooling->N_Temp, logu/log_10, &u_i, &du); + //float u1 = pow(10.0,cooling->Therm[u_i]); + //float u2 = pow(10.0,cooling->Therm[u_i+1]); + //lambda_net1 = eagle_metal_cooling_rate( + // log10(u1), z_index, dz, n_h_i, d_n_h, + // He_i, d_He, p, cooling, cosmo, internal_const, element_lambda, abundance_ratio); + //lambda_net2 = eagle_metal_cooling_rate( + // log10(u2), z_index, dz, n_h_i, d_n_h, + // He_i, d_He, p, cooling, cosmo, internal_const, element_lambda, abundance_ratio); + //*dLambdaNet_du = (lambda_net2 - lambda_net1)/(u2 - u1); + + return lambda_net; +} + /* * @brief Wrapper function previously used to calculate cooling rate and * dLambda_du @@ -1423,6 +1797,66 @@ __attribute__((always_inline)) INLINE static double eagle_cooling_rate_1d_table( return lambda_net; } +/* + * @brief Calculates cooling rate from 1d tables, used to print cooling rates + * to files for checking against Wiersma et al 2009 idl scripts. + * + * @param H_plus_He_heat_table 1D table of heating rates due to H, He + * @param H_plus_He_electron_abundance_table 1D table of electron abundances due + * to H,He + * @param element_cooling_table 1D table of heating rates due to metals + * @param element_electron_abundance_table 1D table of electron abundances due + * to metals + * @param temp_table 1D table of temperatures + * @param z_index Redshift index of particle + * @param dz Redshift offset of particle + * @param n_h_i Particle hydrogen number density index + * @param d_n_h Particle hydrogen number density offset + * @param He_i Particle helium fraction index + * @param d_He Particle helium fraction offset + * @param p Particle structure + * @param cooling Cooling data structure + * @param cosmo Cosmology structure + * @param internal_const Physical constants structure + */ +__attribute__((always_inline)) INLINE static double +eagle_print_metal_cooling_rate( + int z_index, float dz, int n_h_i, float d_n_h, int He_i, + float d_He, const struct part *restrict p, + const struct cooling_function_data *restrict cooling, + const struct cosmology *restrict cosmo, + const struct phys_const *internal_const, + float *abundance_ratio) { + double *element_lambda, lambda_net = 0.0, dLambdaNet_du; + //const double log_10 = 2.30258509299404; + element_lambda = malloc((cooling->N_Elements + 2) * sizeof(double)); + double u = hydro_get_physical_internal_energy(p, cosmo) * + cooling->internal_energy_scale; + + char output_filename[25]; + FILE **output_file = malloc((cooling->N_Elements + 2) * sizeof(FILE *)); + for (int element = 0; element < cooling->N_Elements + 2; element++) { + sprintf(output_filename, "%s%d%s", "cooling_element_", element, ".dat"); + output_file[element] = fopen(output_filename, "a"); + if (output_file == NULL) { + printf("Error opening file!\n"); + exit(1); + } + } + + for (int j = 0; j < cooling->N_Elements + 2; j++) element_lambda[j] = 0.0; + lambda_net = eagle_metal_cooling_rate( + log10(u), &dLambdaNet_du, z_index, dz, n_h_i, d_n_h, + He_i, d_He, p, cooling, cosmo, internal_const, element_lambda, abundance_ratio); + for (int j = 0; j < cooling->N_Elements + 2; j++) { + fprintf(output_file[j], "%.5e\n", element_lambda[j]); + } + + for (int i = 0; i < cooling->N_Elements + 2; i++) fclose(output_file[i]); + + return lambda_net; +} + /* * @brief Calculates cooling rate from 1d tables, used to print cooling rates * to files for checking against Wiersma et al 2009 idl scripts. @@ -1448,7 +1882,7 @@ __attribute__((always_inline)) INLINE static double eagle_cooling_rate_1d_table( __attribute__((always_inline)) INLINE static double eagle_print_metal_cooling_rate_1d_table( double *H_plus_He_heat_table, double *H_plus_He_electron_abundance_table, - double *element_cooling_table, double *element_electron_abundance_table, + double *element_print_cooling_table, double *element_electron_abundance_table, double *temp_table, int z_index, float dz, int n_h_i, float d_n_h, int He_i, float d_He, const struct part *restrict p, const struct cooling_function_data *restrict cooling, @@ -1456,15 +1890,16 @@ eagle_print_metal_cooling_rate_1d_table( const struct phys_const *internal_const, float *abundance_ratio) { double *element_lambda, lambda_net = 0.0; + //const double log_10 = 2.30258509299404; element_lambda = malloc((cooling->N_Elements + 2) * sizeof(double)); double u = hydro_get_physical_internal_energy(p, cosmo) * cooling->internal_energy_scale; double dLambdaNet_du; - char output_filename[21]; + char output_filename[25]; FILE **output_file = malloc((cooling->N_Elements + 2) * sizeof(FILE *)); for (int element = 0; element < cooling->N_Elements + 2; element++) { - sprintf(output_filename, "%s%d%s", "cooling_output_", element, ".dat"); + sprintf(output_filename, "%s%d%s", "cooling_element_", element, ".dat"); output_file[element] = fopen(output_filename, "a"); if (output_file == NULL) { printf("Error opening file!\n"); @@ -1474,8 +1909,8 @@ eagle_print_metal_cooling_rate_1d_table( for (int j = 0; j < cooling->N_Elements + 2; j++) element_lambda[j] = 0.0; lambda_net = eagle_metal_cooling_rate_1d_table( - log(u), &dLambdaNet_du, H_plus_He_heat_table, - H_plus_He_electron_abundance_table, element_cooling_table, + log10(u), &dLambdaNet_du, H_plus_He_heat_table, + H_plus_He_electron_abundance_table, element_print_cooling_table, element_electron_abundance_table, temp_table, z_index, dz, n_h_i, d_n_h, He_i, d_He, p, cooling, cosmo, internal_const, element_lambda, abundance_ratio); for (int j = 0; j < cooling->N_Elements + 2; j++) { @@ -1520,11 +1955,12 @@ __attribute__((always_inline)) INLINE static float bisection_iter( struct part *restrict p, const struct cosmology *restrict cosmo, const struct cooling_function_data *restrict cooling, const struct phys_const *restrict phys_const, - float *abundance_ratio, float dt) { + float *abundance_ratio, float dt, float *ub, float *lb) { double x_a, x_b, x_next, f_a, f_b, f_next, dLambdaNet_du; int i = 0; - float shift = 0.3; - double log10_e = 0.4342944819032518; + //float shift = 0.3; + //const double log10_e = 0.4342944819032518; + const float bisection_tolerance = 1.0e-8; float XH = p->chemistry_data.metal_mass_fraction[chemistry_element_H]; @@ -1539,10 +1975,10 @@ __attribute__((always_inline)) INLINE static float bisection_iter( /* set helium and hydrogen reheating term */ double LambdaTune = 0.0; - if (cooling -> he_reion == 1) LambdaTune = eagle_helium_reionization_extraheat(z_index, dz, cooling); + if (cooling->he_reion == 1) LambdaTune = eagle_helium_reionization_extraheat(z_index, dz, cooling); - x_a = x_init; - x_b = cooling->Therm[0] / log10_e; + x_a = *ub; + x_b = *lb; f_a = (LambdaTune / (dt * ratefact)) + eagle_cooling_rate_1d_table( x_a, &dLambdaNet_du, H_plus_He_heat_table, H_plus_He_electron_abundance_table, element_cooling_table, @@ -1554,17 +1990,17 @@ __attribute__((always_inline)) INLINE static float bisection_iter( element_electron_abundance_table, temp_table, z_index, dz, n_h_i, d_n_h, He_i, d_He, p, cooling, cosmo, phys_const, abundance_ratio); - while (f_a * f_b >= 0 & i < 10 * eagle_max_iterations) { - if ((x_a + shift) / log(10) < cooling->Therm[cooling->N_Temp - 1]) { - x_a += shift; - f_a = (LambdaTune / (dt * ratefact)) + eagle_cooling_rate_1d_table( - x_a, &dLambdaNet_du, H_plus_He_heat_table, - H_plus_He_electron_abundance_table, element_cooling_table, - element_electron_abundance_table, temp_table, z_index, dz, n_h_i, - d_n_h, He_i, d_He, p, cooling, cosmo, phys_const, abundance_ratio); - } - i++; - } + //while (f_a * f_b >= 0 & i < 10 * eagle_max_iterations) { + // if ((x_a + shift) / log(10) < cooling->Therm[cooling->N_Temp - 1]) { + // x_a += shift; + // f_a = (LambdaTune / (dt * ratefact)) + eagle_cooling_rate_1d_table( + // x_a, &dLambdaNet_du, H_plus_He_heat_table, + // H_plus_He_electron_abundance_table, element_cooling_table, + // element_electron_abundance_table, temp_table, z_index, dz, n_h_i, + // d_n_h, He_i, d_He, p, cooling, cosmo, phys_const, abundance_ratio); + // } + // i++; + //} #if SWIFT_DEBUG_CHECKS assert(f_a * f_b < 0); #endif @@ -1585,190 +2021,13 @@ __attribute__((always_inline)) INLINE static float bisection_iter( f_a = f_next; } i++; - } while (fabs(x_a - x_b) > 1.0e-2 && i < 50*eagle_max_iterations); + } while (fabs(x_a - x_b) > bisection_tolerance && i < 50*eagle_max_iterations); if (i >= 50*eagle_max_iterations) n_eagle_cooling_rate_calls_4++; return x_b; } -/* - * @brief Work in progress more stable integration scheme (brent-dekker) - * that may be used for particles which do not - * converge using newton_iter (may be faster than bisection_iter) - * - * @param x_init Initial guess for log(internal energy) - * @param u_ini Internal energy at beginning of hydro step - * @param H_plus_He_heat_table 1D table of heating rates due to H, He - * @param H_plus_He_electron_abundance_table 1D table of electron abundances due - * to H,He - * @param element_cooling_table 1D table of heating rates due to metals - * @param element_electron_abundance_table 1D table of electron abundances due - * to metals - * @param temp_table 1D table of temperatures - * @param z_index Redshift index of particle - * @param dz Redshift offset of particle - * @param n_h_i Particle hydrogen number density index - * @param d_n_h Particle hydrogen number density offset - * @param He_i Particle helium fraction index - * @param d_He Particle helium fraction offset - * @param p Particle structure - * @param cosmo Cosmology structure - * @param cooling Cooling data structure - * @param phys_const Physical constants structure - * @param dt Hydro timestep - */ -__attribute__((always_inline)) INLINE static float brent_iter( - float x_init, double u_ini, double *H_plus_He_heat_table, - double *H_plus_He_electron_abundance_table, double *element_cooling_table, - double *element_electron_abundance_table, double *temp_table, int z_index, - float dz, int n_h_i, float d_n_h, int He_i, float d_He, - struct part *restrict p, const struct cosmology *restrict cosmo, - const struct cooling_function_data *restrict cooling, - const struct phys_const *restrict phys_const, - float *abundance_ratio, float dt) { - /* this routine does the iteration scheme, call one and it iterates to - * convergence */ - - double x_a, x_b, x_c, x_d, x_s, x_temp, delta = 1.0e-2; - double dLambdaNet_du, Lambda_a, Lambda_b, Lambda_c, Lambda_s; - double f_a, f_b, f_c, f_s, f_temp; - float XH = p->chemistry_data.metal_mass_fraction[chemistry_element_H]; - - /* convert Hydrogen mass fraction in Hydrogen number density */ - double inn_h = - chemistry_get_number_density(p, cosmo, chemistry_element_H, phys_const) * - cooling->number_density_scale; - - /* ratefact = inn_h * inn_h / rho; Might lead to round-off error: replaced by - * equivalent expression below */ - double ratefact = inn_h * (XH / eagle_proton_mass_cgs); - - /* set helium and hydrogen reheating term */ - float LambdaTune = eagle_helium_reionization_extraheat(z_index, dz, cooling); - static double zold = 100; - if (zold > z_index) { - float LambdaCumul = 0.0; - LambdaCumul += LambdaTune; - printf(" EagleDoCooling %d %g %g %g\n", z_index, dz, LambdaTune, LambdaCumul); - zold = z_index; - } - - int i = 0; - x_a = x_init; - // x_b = cooling->Therm[0]*log(10); - x_b = 0.5 * x_init; - x_c = x_a; - x_d = 0.0; - Lambda_a = eagle_cooling_rate_1d_table( - x_a, &dLambdaNet_du, H_plus_He_heat_table, - H_plus_He_electron_abundance_table, element_cooling_table, - element_electron_abundance_table, temp_table, z_index, dz, n_h_i, d_n_h, - He_i, d_He, p, cooling, cosmo, phys_const, abundance_ratio); - Lambda_b = eagle_cooling_rate_1d_table( - x_b, &dLambdaNet_du, H_plus_He_heat_table, - H_plus_He_electron_abundance_table, element_cooling_table, - element_electron_abundance_table, temp_table, z_index, dz, n_h_i, d_n_h, - He_i, d_He, p, cooling, cosmo, phys_const, abundance_ratio); - f_a = exp(x_a) - exp(x_init) - Lambda_a * ratefact * dt; - f_b = exp(x_b) - exp(x_init) - Lambda_b * ratefact * dt; - assert(f_a * f_b < 0); - if (f_a < f_b) { - x_temp = x_a; - x_a = x_b; - x_b = x_temp; - f_temp = f_a; - f_a = f_b; - f_b = f_temp; - } - int mflag = 1; - - do /* iterate to convergence */ - { - Lambda_c = eagle_cooling_rate_1d_table( - x_c, &dLambdaNet_du, H_plus_He_heat_table, - H_plus_He_electron_abundance_table, element_cooling_table, - element_electron_abundance_table, temp_table, z_index, dz, n_h_i, d_n_h, - He_i, d_He, p, cooling, cosmo, phys_const, abundance_ratio); - f_c = exp(x_c) - exp(x_init) - Lambda_c * ratefact * dt; - - if ((f_a != f_c) && (f_b != f_c)) { - x_s = x_a * f_b * f_c / ((f_a - f_b) * (f_a - f_c)) + - x_b * f_a * f_c / ((f_b - f_a) * (f_b - f_c)) + - x_c * f_b * f_a / ((f_c - f_b) * (f_c - f_a)); - printf("Eagle cooling.h 1 id x_s, u_s, error, %llu %.5e %.5e %.5e %d\n", - p->id, x_s, exp(x_s), x_a - x_b, i); - printf( - "Eagle cooling.h 1 id u_a, u_b, u_c, f_a, f_b, f_c, %llu %.5e %.5e " - "%.5e %.5e %.5e %.5e %.5e %d\n", - p->id, exp(x_a), exp(x_b), exp(x_c), f_a, f_b, f_c, x_a - x_b, i); - } else { - x_s = x_b - f_b * (x_b - x_a) / (f_b - f_a); - printf("Eagle cooling.h 2 id x_s, u_s, error, %llu %.5e %.5e %.5e %d\n", - p->id, x_s, exp(x_s), x_a - x_b, i); - } - - if ((x_s < (3.0 * x_a + x_b) / 4.0 || x_s > x_b) || - (mflag == 1 && fabs(x_s - x_b) >= 0.5 * fabs(x_b - x_c)) || - (mflag != 1 && fabs(x_s - x_b) >= 0.5 * fabs(x_c - x_d)) || - (mflag == 1 && fabs(x_b - x_c) < delta) || - (mflag != 1 && fabs(x_c - x_d) < delta)) { - x_s = 0.5 * (x_a + x_b); - printf("Eagle cooling.h 3 id x_s, u_s, error, %llu %.5e %.5e %.5e %d\n", - p->id, x_s, exp(x_s), x_a - x_b, i); - mflag = 1; - } else { - mflag = 0; - } - x_d = x_c; - x_c = x_b; - printf("Eagle cooling.h 4 id x_s, u_s, error, %llu %.5e %.5e %.5e %d\n", - p->id, x_s, exp(x_s), x_a - x_b, i); - Lambda_s = eagle_cooling_rate_1d_table( - x_s, &dLambdaNet_du, H_plus_He_heat_table, - H_plus_He_electron_abundance_table, element_cooling_table, - element_electron_abundance_table, temp_table, z_index, dz, n_h_i, d_n_h, - He_i, d_He, p, cooling, cosmo, phys_const, abundance_ratio); - f_s = exp(x_s) - exp(x_init) - Lambda_s * ratefact * dt; - if (f_s * f_a < 0) { - x_b = x_s; - } else { - x_a = x_s; - } - Lambda_a = eagle_cooling_rate_1d_table( - x_a, &dLambdaNet_du, H_plus_He_heat_table, - H_plus_He_electron_abundance_table, element_cooling_table, - element_electron_abundance_table, temp_table, z_index, dz, n_h_i, d_n_h, - He_i, d_He, p, cooling, cosmo, phys_const, abundance_ratio); - Lambda_b = eagle_cooling_rate_1d_table( - x_b, &dLambdaNet_du, H_plus_He_heat_table, - H_plus_He_electron_abundance_table, element_cooling_table, - element_electron_abundance_table, temp_table, z_index, dz, n_h_i, d_n_h, - He_i, d_He, p, cooling, cosmo, phys_const, abundance_ratio); - f_a = exp(x_a) - exp(x_init) - Lambda_a * ratefact * dt; - f_b = exp(x_b) - exp(x_init) - Lambda_b * ratefact * dt; - if (f_a < f_b) { - x_temp = x_a; - x_a = x_b; - x_b = x_temp; - f_temp = f_a; - f_a = f_b; - f_b = f_temp; - } - i++; - - } while (fabs(x_b - x_a) > delta && i < eagle_max_iterations); - - if (i >= eagle_max_iterations) { - n_eagle_cooling_rate_calls_3++; - printf( - "Eagle cooling.h particle %llu with density %.5e, initial energy, %.5e " - "and redshift %.5e not converged \n", - p->id, inn_h, exp(x_init), cosmo->z); - } - - return x_s; -} /* * @brief Newton Raphson integration scheme to calculate particle cooling over @@ -1795,21 +2054,21 @@ __attribute__((always_inline)) INLINE static float brent_iter( * @param phys_const Physical constants structure * @param dt Hydro timestep * @param printflag Flag to identify if scheme failed to converge - * @param relax_factor Factor to increase stability + * @param lb lower bound to be used by bisection scheme + * @param ub upper bound to be used by bisection scheme */ __attribute__((always_inline)) INLINE static float newton_iter( - float x_init, double u_ini, double *H_plus_He_heat_table, - double *H_plus_He_electron_abundance_table, double *element_cooling_table, - double *element_electron_abundance_table, double *temp_table, int z_index, + float x_init, double u_ini, int z_index, float dz, int n_h_i, float d_n_h, int He_i, float d_He, struct part *restrict p, const struct cosmology *restrict cosmo, const struct cooling_function_data *restrict cooling, const struct phys_const *restrict phys_const, float *abundance_ratio, float dt, int *printflag, - float relax_factor) { + float *lb, float *ub) { /* this routine does the iteration scheme, call one and it iterates to * convergence */ + const float newton_tolerance = 1.0e-2; double x, x_old; double dLambdaNet_du, LambdaNet; float XH = p->chemistry_data.metal_mass_fraction[chemistry_element_H]; @@ -1836,51 +2095,44 @@ __attribute__((always_inline)) INLINE static float newton_iter( x_old = x_init; x = x_old; int i = 0; + float relax = 1.0;//, relax_factor = 0.5; + float log_table_bound_high = 43.749, log_table_bound_low = 20.723; do /* iterate to convergence */ { - x_old = x; + if (relax == 1.0) x_old = x; LambdaNet = (LambdaTune / (dt * ratefact)) + - eagle_cooling_rate_1d_table( - x_old, &dLambdaNet_du, H_plus_He_heat_table, - H_plus_He_electron_abundance_table, element_cooling_table, - element_electron_abundance_table, temp_table, z_index, dz, n_h_i, d_n_h, + eagle_cooling_rate( + x_old, &dLambdaNet_du, z_index, dz, n_h_i, d_n_h, He_i, d_He, p, cooling, cosmo, phys_const, abundance_ratio); + if (LambdaNet < 0) { + *ub = fmin(*ub,x_old); + } else if (LambdaNet > 0) { + *lb = fmax(*lb,x_old); + } + n_eagle_cooling_rate_calls_1++; - // Newton iterate the variable. + // Newton iteration. x = x_old - - relax_factor * (1.0 - u_ini * exp(-x_old) - + relax * (1.0 - u_ini * exp(-x_old) - LambdaNet * ratefact * dt * exp(-x_old)) / (1.0 - dLambdaNet_du * ratefact * dt); - // try limiting how far iterations can jump by - if (*printflag == 1 && x < 0.3 * x_old) { - x = 0.3 * x_old; - } else if (*printflag == 1 && x > 1.3 * x_old) { - x = 1.3 * x_old; - } // check whether iterations go out of bounds of table, - // can be used to try to prevent runaway - // Remove hardcoded bounds (log(1e19) = 43.749, log(1e9) = 20.723)! - int table_out_of_bounds = 0; - if (x > 43.749) { - // x = log(u_ini); - table_out_of_bounds = 1; - } - if (x < 20.723) { - // x = log(u_ini); - table_out_of_bounds = 1; - } - - //residual = exp(x_old) - u_ini - LambdaNet * ratefact * dt; - if (dt > 0 && *printflag == 1) { - table_out_of_bounds = 0; + // if out of bounds, try again with smaller newton step + if (x > log_table_bound_high) { + x = (log_table_bound_high + x_old)/2.0; + } else if (x < log_table_bound_low) { + x = (log_table_bound_low + x_old)/2.0; } + // relax = relax_factor; + //} else { + // relax = 1.0; + //} i++; - if (table_out_of_bounds == 1) i = eagle_max_iterations; - } while (fabs(x - x_old) > 1.0e-2 && i < eagle_max_iterations); + } while (fabs(x - x_old) > newton_tolerance && i < eagle_max_iterations); if (i >= eagle_max_iterations) { n_eagle_cooling_rate_calls_3++; // failed to converge the first time @@ -1918,6 +2170,80 @@ __attribute__((always_inline)) INLINE static void abundance_ratio_to_solar( cooling->SolarAbundances[chemistry_element_count]; // NOTE: solar abundances have iron last with calcium and sulphur directly before } +/** + * @brief construct all 1d tables + * + * @param + */ +__attribute__((always_inline)) INLINE void static construct_1d_tables( + int z_index, float dz, int n_h_i, float d_n_h, + int He_i, float d_He, + const struct phys_const *restrict phys_const, + const struct unit_system *restrict us, + const struct cosmology *restrict cosmo, + const struct cooling_function_data *restrict cooling, + const struct part *restrict p, + float *abundance_ratio, + double *H_plus_He_heat_table, + double *H_plus_He_electron_abundance_table, + double *element_cooling_table, + double *element_cooling_print_table, + double *element_electron_abundance_table, + double *temp_table, + float *ub, float *lb) { + + construct_1d_table_from_4d(p, cooling, cosmo, phys_const, + cooling->table.element_cooling.temperature, + z_index, dz, cooling->N_Redshifts, n_h_i, d_n_h, + cooling->N_nH, He_i, d_He, cooling->N_He, cooling->N_Temp, temp_table, ub, lb); + //construct_1d_table_from_3d(p, cooling, cosmo, phys_const, + // cooling->table.photodissociation_cooling.temperature, + // n_h_i, d_n_h, cooling->N_nH, He_i, d_He, cooling->N_He, + // cooling->N_Temp, temp_table); + + // element cooling + construct_1d_table_from_4d( + p, cooling, cosmo, phys_const, + cooling->table.element_cooling.H_plus_He_heating, z_index, dz, cooling->N_Redshifts, n_h_i, d_n_h, + cooling->N_nH, He_i, d_He, cooling->N_He, cooling->N_Temp, H_plus_He_heat_table, ub, lb); + construct_1d_table_from_4d( + p, cooling, cosmo, phys_const, + cooling->table.element_cooling.H_plus_He_electron_abundance, z_index, + dz, cooling->N_Redshifts, n_h_i, d_n_h, cooling->N_nH, He_i, d_He, + cooling->N_He, cooling->N_Temp, H_plus_He_electron_abundance_table, ub, lb); + construct_1d_table_from_4d_elements( + p, cooling, cosmo, phys_const, + cooling->table.element_cooling.metal_heating, z_index, dz, cooling->N_Redshifts, + n_h_i, d_n_h, cooling->N_nH, cooling->N_Temp, element_cooling_table, abundance_ratio, ub, lb); + construct_1d_print_table_from_4d_elements( + p, cooling, cosmo, phys_const, + cooling->table.element_cooling.metal_heating, z_index, dz, cooling->N_Redshifts, + n_h_i, d_n_h, cooling->N_nH, cooling->N_Temp, element_cooling_print_table, abundance_ratio, ub, lb); + construct_1d_table_from_3d( + p, cooling, cosmo, phys_const, + cooling->table.element_cooling.electron_abundance, z_index, dz, cooling->N_Redshifts, + n_h_i, d_n_h, cooling->N_nH, cooling->N_Temp, element_electron_abundance_table, ub, lb); + + // photodissociation cooling + //construct_1d_table_from_3d( + // p, cooling, cosmo, phys_const, + // cooling->table.photodissociation_cooling.H_plus_He_heating, n_h_i, d_n_h, cooling->N_nH, + // He_i, d_He, cooling->N_He, cooling->N_Temp, H_plus_He_heat_table, ub, lb); + //construct_1d_table_from_3d( + // p, cooling, cosmo, phys_const, + // cooling->table.photodissociation_cooling.H_plus_He_electron_abundance, + // n_h_i, d_n_h, cooling->N_nH, He_i, d_He, cooling->N_He, + // cooling->N_Temp, H_plus_He_electron_abundance_table, ub, lb); + //construct_1d_table_from_3d_elements( + // p, cooling, cosmo, phys_const, + // cooling->table.photodissociation_cooling.metal_heating, + // n_h_i, d_n_h, cooling->N_nH, cooling->N_Temp, element_cooling_table, abundance_ratio, ub, lb); + //construct_1d_table_from_2d( + // p, cooling, cosmo, phys_const, + // cooling->table.photodissociation_cooling.electron_abundance, + // n_h_i, d_n_h, cooling->N_nH, cooling->N_Temp, element_electron_abundance_table, ub, lb); +} + /** * @brief Apply the cooling function to a particle. * @@ -1936,6 +2262,8 @@ __attribute__((always_inline)) INLINE static void cooling_cool_part( const struct cooling_function_data *restrict cooling, struct part *restrict p, struct xpart *restrict xp, float dt) { + const float exp_factor = 0.05; + const double log_10_e = 0.43429448190325182765; double u_old = hydro_get_physical_internal_energy(p, cosmo) * cooling->internal_energy_scale; float dz; @@ -1945,7 +2273,7 @@ __attribute__((always_inline)) INLINE static void cooling_cool_part( float XH, HeFrac; double inn_h; - double ratefact, u, LambdaNet, LambdaTune = 0, dLambdaNet_du; + double ratefact, u, LambdaNet, LambdaNet_eq, LambdaTune = 0, dLambdaNet_du; static double zold = 100, LambdaCumul = 0; dt *= units_cgs_conversion_factor(us, UNIT_CONV_TIME); @@ -1953,8 +2281,7 @@ __attribute__((always_inline)) INLINE static void cooling_cool_part( u = u_old; double u_ini = u_old, u_temp; - float *abundance_ratio; - abundance_ratio = malloc((chemistry_element_count + 2)*sizeof(float)); + float abundance_ratio[chemistry_element_count + 2]; abundance_ratio_to_solar(p, cooling, abundance_ratio); XH = p->chemistry_data.metal_mass_fraction[chemistry_element_H]; @@ -1981,86 +2308,82 @@ __attribute__((always_inline)) INLINE static void cooling_cool_part( float d_He, d_n_h; get_index_1d(cooling->HeFrac, cooling->N_He, HeFrac, &He_i, &d_He); get_index_1d(cooling->nH, cooling->N_nH, log10(inn_h), &n_h_i, &d_n_h); + - double temp_table[176]; // WARNING sort out how it is declared/allocated - construct_1d_table_from_4d(p, cooling, cosmo, phys_const, - cooling->table.element_cooling.temperature, - z_index, dz, He_i, d_He, n_h_i, d_n_h, temp_table); - - // To be used when amount of cooling is small, put back in when ready - LambdaNet = - eagle_metal_cooling_rate(log(u_ini), temp_table, z_index, dz, n_h_i, d_n_h, - He_i, d_He, p, cooling, cosmo, phys_const, NULL, abundance_ratio); - if (fabs(ratefact * LambdaNet * dt) < 0.05 * u_old) { - /* cooling rate is small, take the explicit solution */ - u = u_old + ratefact * LambdaNet * dt; + LambdaNet = LambdaTune/(dt*ratefact) + eagle_cooling_rate( + log(u_ini), &dLambdaNet_du, z_index, dz, n_h_i, d_n_h, + He_i, d_He, p, cooling, cosmo, phys_const, abundance_ratio); + + if (fabs(ratefact * LambdaNet * dt) < exp_factor * u_old) { + /* cooling rate is small, take the explicit solution */ + u = u_old + ratefact * LambdaNet * dt; } else { - // construct 1d table of cooling rates wrt temperature - double H_plus_He_heat_table[176]; - double H_plus_He_electron_abundance_table[176]; - double element_cooling_table[176]; - double element_electron_abundance_table[176]; - - // element cooling - construct_1d_table_from_4d_H_He( - p, cooling, cosmo, phys_const, - cooling->table.element_cooling.H_plus_He_heating, z_index, dz, He_i, - d_He, n_h_i, d_n_h, H_plus_He_heat_table, &u_temp, u_ini, dt); - construct_1d_table_from_4d( - p, cooling, cosmo, phys_const, - cooling->table.element_cooling.H_plus_He_electron_abundance, z_index, - dz, He_i, d_He, n_h_i, d_n_h, H_plus_He_electron_abundance_table); - construct_1d_table_from_4d_elements( - p, cooling, cosmo, phys_const, - cooling->table.element_cooling.metal_heating, z_index, dz, n_h_i, d_n_h, - element_cooling_table); - construct_1d_table_from_3d( - p, cooling, cosmo, phys_const, - cooling->table.element_cooling.electron_abundance, z_index, dz, n_h_i, - d_n_h, element_electron_abundance_table); - - n_eagle_cooling_rate_calls_2++; - - LambdaNet = eagle_cooling_rate_1d_table( - log(u_ini), &dLambdaNet_du, H_plus_He_heat_table, - H_plus_He_electron_abundance_table, element_cooling_table, - element_electron_abundance_table, temp_table, z_index, dz, n_h_i, d_n_h, - He_i, d_He, p, cooling, cosmo, phys_const, abundance_ratio); - - double u_eq = 5.0e12; - - if (dt > 0) { - float u_temp_guess = u_ini + LambdaNet * ratefact * dt; - // printf("Eagle cooling.h id u_temp_guess, u_ini, LambdaNet, ratefact, dt - // %llu %.5e %.5e %.5e %.5e %.5e \n", p->id,u_temp_guess, u_ini, - // LambdaNet, ratefact, dt); - // if ((LambdaNet < 0 && u_temp < u_temp_guess) || - // (LambdaNet >= 0 && u_temp > u_temp_guess)) - // u_temp = u_temp_guess; - u_temp = u_temp_guess; - if ((LambdaNet < 0 && u_temp < u_eq) || (LambdaNet >= 0 && u_temp > u_eq)) - u_temp = u_eq; - if (isnan(u_temp)) u_temp = u_eq; - double log_u_temp = log(u_temp); - - int printflag = 0; - float relax_factor = 1.0; - float x = - newton_iter(log_u_temp, u_ini, H_plus_He_heat_table, - H_plus_He_electron_abundance_table, element_cooling_table, - element_electron_abundance_table, temp_table, z_index, dz, - n_h_i, d_n_h, He_i, d_He, p, cosmo, cooling, phys_const, - abundance_ratio, dt, &printflag, relax_factor); - if (printflag == 1) { - // newton method didn't work, so revert to bisection - x = - bisection_iter(log_u_temp,u_ini,H_plus_He_heat_table,H_plus_He_electron_abundance_table,element_cooling_table,element_electron_abundance_table,temp_table,z_index,dz,n_h_i,d_n_h,He_i,d_He,p,cosmo,cooling,phys_const,abundance_ratio,dt); - //n_eagle_cooling_rate_calls_4++; - printflag = 2; - } - u = exp(x); - } - } + n_eagle_cooling_rate_calls_2++; + float x, lower_bound = cooling->Therm[0]/log_10_e, upper_bound = cooling->Therm[cooling->N_Temp-1]/log_10_e; + + double u_eq = 1.0e12;//, u_max = pow(10.0,cooling->Therm[cooling->N_Temp-1]); + //do { + u_eq = u_ini; + LambdaNet_eq = LambdaTune/(dt*ratefact) + eagle_cooling_rate( + log(u_eq), &dLambdaNet_du, z_index, dz, n_h_i, d_n_h, + He_i, d_He, p, cooling, cosmo, phys_const, abundance_ratio); + //} while (LambdaNet_eq > 0 && u_eq < u_max); + + if (LambdaNet_eq < 0 && LambdaNet < 0) { + upper_bound = fmin(log(u_eq), log(u_ini)); + } else if (LambdaNet_eq*LambdaNet < 0) { + upper_bound = fmax(log(u_eq), log(u_ini)); + lower_bound = fmin(log(u_eq), log(u_ini)); + } else { + upper_bound = fmax(log(u_eq), log(u_ini)); + } + + if (dt > 0) { + u_temp = u_ini + LambdaNet * ratefact * dt; + if ((LambdaNet < 0 && u_temp < u_eq) || (LambdaNet >= 0 && u_temp > u_eq)) + u_temp = u_eq; + if (isnan(u_temp)) u_temp = u_eq; + double log_u_temp = log(u_temp); + + int printflag = 0; + x = newton_iter(log_u_temp, u_ini, z_index, dz, + n_h_i, d_n_h, He_i, d_He, p, cosmo, cooling, phys_const, + abundance_ratio, dt, &printflag, &lower_bound, &upper_bound); + if (printflag == 1) { + //double Lambda_upper = LambdaTune/(dt*ratefact) + eagle_cooling_rate( + // upper_bound, &dLambdaNet_du, z_index, dz, n_h_i, d_n_h, + // He_i, d_He, p, cooling, cosmo, phys_const, abundance_ratio); + //double Lambda_lower = LambdaTune/(dt*ratefact) + eagle_cooling_rate( + // lower_bound, &dLambdaNet_du, z_index, dz, n_h_i, d_n_h, + // He_i, d_He, p, cooling, cosmo, phys_const, abundance_ratio); + //printf("Eagle cooling.h id upper lower lambda_upper lambda_lower %llu %.5e %.5e %.5e %.5e\n", p->id, exp(upper_bound), exp(lower_bound), Lambda_upper, Lambda_lower); + // newton method didn't work, so revert to bisection + + // construct 1d table of cooling rates wrt temperature + double temp_table[176]; // WARNING sort out how it is declared/allocated + double H_plus_He_heat_table[176]; + double H_plus_He_electron_abundance_table[176]; + double element_cooling_table[176]; + double element_cooling_print_table[9*176]; + double element_electron_abundance_table[176]; + construct_1d_tables(z_index, dz, n_h_i, d_n_h, He_i, d_He, + phys_const, us, cosmo, cooling, p, + abundance_ratio, + H_plus_He_heat_table, + H_plus_He_electron_abundance_table, + element_cooling_table, + element_cooling_print_table, + element_electron_abundance_table, + temp_table, + &upper_bound, + &lower_bound); + x = bisection_iter(log_u_temp,u_ini,H_plus_He_heat_table,H_plus_He_electron_abundance_table,element_cooling_print_table,element_electron_abundance_table,temp_table,z_index,dz,n_h_i,d_n_h,He_i,d_He,p,cosmo,cooling,phys_const,abundance_ratio,dt,&upper_bound,&lower_bound); + + printflag = 2; + } + u = exp(x); + } + } const float hydro_du_dt = hydro_get_internal_energy_dt(p); @@ -2103,13 +2426,43 @@ __attribute__((always_inline)) INLINE static float cooling_timestep( const struct cooling_function_data *restrict cooling, const struct phys_const *restrict phys_const, const struct cosmology *restrict cosmo, - const struct unit_system *restrict us, const struct part *restrict p) { + const struct unit_system *restrict us, const struct part *restrict p, const struct xpart *restrict xp) { /* Remember to update when using an implicit integrator!!!*/ // const float cooling_rate = cooling->cooling_rate; // const float internal_energy = hydro_get_comoving_internal_energy(p); // return cooling->cooling_tstep_mult * internal_energy / fabsf(cooling_rate); + //const float internal_energy = hydro_get_physical_internal_energy(p,cosmo); + //if (fabs(xp->cooling_data.radiated_energy) > 1*internal_energy){ + // float logu = log(internal_energy*cooling->internal_energy_scale); + // double dLambdaNet_du; + // int z_index, He_i, n_h_i; + // float dz, d_He, d_n_h; + // float XH = p->chemistry_data.metal_mass_fraction[chemistry_element_H]; + // float HeFrac = p->chemistry_data.metal_mass_fraction[chemistry_element_He] / + // (XH + p->chemistry_data.metal_mass_fraction[chemistry_element_He]); + // float inn_h = chemistry_get_number_density(p, cosmo, chemistry_element_H, phys_const) * + // cooling->number_density_scale; + // double ratefact = inn_h * (XH / eagle_proton_mass_cgs); + + // get_redshift_index(cosmo->z, &z_index, &dz, cooling); + // get_index_1d(cooling->HeFrac, cooling->N_He, HeFrac, &He_i, &d_He); + // get_index_1d(cooling->nH, cooling->N_nH, log10(inn_h), &n_h_i, &d_n_h); + // + // float abundance_ratio[chemistry_element_count + 2]; + // abundance_ratio_to_solar(p, cooling, abundance_ratio); + + // float Lambda_net = eagle_cooling_rate(logu, &dLambdaNet_du, z_index, + // dz, n_h_i, d_n_h, He_i, d_He, + // p, cooling, cosmo, phys_const, abundance_ratio); + // float tstep = fabs(internal_energy*cooling->internal_energy_scale/(Lambda_net*ratefact)); + // //printf("Eagle cooling.h id tstep u lambda ratefact %llu %.5e %.5e %.5e %.5e\n", p->id, tstep, internal_energy*cooling->internal_energy_scale, Lambda_net, ratefact); + // return max(1.0e3*tstep,2.0e-9); + //} else { + // return FLT_MAX; + //} + return FLT_MAX; } diff --git a/src/cooling/EAGLE/eagle_cool_tables.h b/src/cooling/EAGLE/eagle_cool_tables.h index aa1019b940e93461c929e146d91f9a916ba66df8..0d1805058baf2e8732654afe0581ffaaf4cef87b 100644 --- a/src/cooling/EAGLE/eagle_cool_tables.h +++ b/src/cooling/EAGLE/eagle_cool_tables.h @@ -538,8 +538,8 @@ inline struct cooling_tables_redshift_invariant get_photodis_table( for (k = 0; k < cooling->N_nH; k++) { table_index = row_major_index_2d(j, k, cooling->N_Temp, cooling->N_nH); cooling_index = row_major_index_3d( - specs, j, k, cooling->N_Elements, cooling->N_Temp, - cooling->N_nH); // Redshift invariant table!!! + specs, k, j, cooling->N_Elements, cooling->N_nH, + cooling->N_Temp); // Redshift invariant table!!! cooling_table.metal_heating[cooling_index] = -net_cooling_rate[table_index]; } @@ -571,8 +571,8 @@ inline struct cooling_tables_redshift_invariant get_photodis_table( table_index = row_major_index_3d(i, j, k, cooling->N_He, cooling->N_Temp, cooling->N_nH); cooling_index = - row_major_index_3d(i, j, k, cooling->N_He, cooling->N_Temp, - cooling->N_nH); // Redshift invariant table!!! + row_major_index_3d(k, i, j, cooling->N_nH, cooling->N_He, + cooling->N_Temp); // Redshift invariant table!!! cooling_table.H_plus_He_heating[cooling_index] = -he_net_cooling_rate[table_index]; cooling_table.H_plus_He_electron_abundance[cooling_index] = @@ -687,8 +687,6 @@ inline struct cooling_tables get_cooling_table( cooling_index = row_major_index_4d( z_index, specs, i, j, cooling->N_Redshifts, cooling->N_Elements, cooling->N_nH, cooling->N_Temp); - // cooling_index = - // row_major_index_3d(specs,j,i,cooling->N_Elements,cooling->N_Temp,cooling->N_nH); cooling_table.metal_heating[cooling_index] = -net_cooling_rate[table_index]; } @@ -722,8 +720,6 @@ inline struct cooling_tables get_cooling_table( cooling_index = row_major_index_4d(z_index, k, i, j, cooling->N_Redshifts, cooling->N_nH, cooling->N_He, cooling->N_Temp); - // cooling_index = - // row_major_index_3d(i,j,k,cooling->N_He,cooling->N_Temp,cooling->N_nH); cooling_table.H_plus_He_heating[cooling_index] = -he_net_cooling_rate[table_index]; cooling_table.H_plus_He_electron_abundance[cooling_index] = @@ -745,8 +741,6 @@ inline struct cooling_tables get_cooling_table( table_index = row_major_index_2d(i, j, cooling->N_Temp, cooling->N_nH); cooling_index = row_major_index_3d(z_index, j, i, cooling->N_Redshifts, cooling->N_nH, cooling->N_Temp); - // cooling_index = - // row_major_index_2d(i,j,cooling->N_Temp,cooling->N_nH); cooling_table.electron_abundance[cooling_index] = electron_abundance[table_index]; } diff --git a/src/hydro/Gadget2/hydro.h b/src/hydro/Gadget2/hydro.h index fed7e5dd19fef380d2f3e06f3f3fe58e792d497f..36db326cf9624a77e3f2b4d06b5f67542f1edc9e 100644 --- a/src/hydro/Gadget2/hydro.h +++ b/src/hydro/Gadget2/hydro.h @@ -312,7 +312,6 @@ __attribute__((always_inline)) INLINE static void hydro_set_comoving_internal_energy_dt(struct part *restrict p, float du_dt) { p->entropy_dt = gas_entropy_from_internal_energy(p->rho, du_dt); - //if (p->id == 5643798559995) printf("Gadget2 particle id entropy entropy_dt du_dt %llu %.5e %.5e %.5e\n", p->id, p->entropy, p->entropy_dt, du_dt); } /**