diff --git a/.gitignore b/.gitignore index 4f81f60dd7d2fd85074759e4fcc4f3e0ee21b187..80e8eafa6133ca7d183b3503f6171713a6df1b36 100644 --- a/.gitignore +++ b/.gitignore @@ -22,8 +22,6 @@ doc/Doxyfile examples/swift examples/swift_mpi -examples/swift_fixdt -examples/swift_fixdt_mpi examples/*.xmf examples/used_parameters.yml examples/energy.txt diff --git a/README b/README index 562a54f3104884b1bf4c5e607700279161fad4c9..9ef773cd85b408ff822b3652c3fd5507e6d95d01 100644 --- a/README +++ b/README @@ -13,8 +13,6 @@ See INSTALL.swift for install instructions. Usage: swift [OPTION]... PARAMFILE swift_mpi [OPTION]... PARAMFILE - swift_fixdt [OPTION]... PARAMFILE - swift_fixdt_mpi [OPTION]... PARAMFILE Valid options are: -a Pin runners using processor affinity diff --git a/configure.ac b/configure.ac index f6e2ea0db8e9829b719a0190eea7a1d891bfbbd6..8cb7fd1b3f09819b7c8b57ce5d70e3b38e32a637 100644 --- a/configure.ac +++ b/configure.ac @@ -170,6 +170,18 @@ if test "x$enable_debug" = "xyes"; then fi fi +# Check if task debugging is on. +AC_ARG_ENABLE([task-debugging], + [AS_HELP_STRING([--enable-task-debugging], + [Store task timing information and generate task dump files @<:@yes/no@:>@] + )], + [enable_task_debugging="$enableval"], + [enable_task_debugging="no"] +) +if test "$enable_task_debugging" = "yes"; then + AC_DEFINE([SWIFT_DEBUG_TASKS],1,[Enable task debugging]) +fi + # Define HAVE_POSIX_MEMALIGN if it works. AX_FUNC_POSIX_MEMALIGN @@ -533,6 +545,7 @@ AC_MSG_RESULT([ libNUMA enabled : $have_numa Using tcmalloc : $have_tcmalloc CPU profiler : $have_profiler + Task debugging : $enable_task_debugging ]) # Generate output. diff --git a/examples/CoolingBox/coolingBox.yml b/examples/CoolingBox/coolingBox.yml index e13de6095066836853d9e9068330938f6260f38e..b90ae61e5c862753227b82ebcec4cbf8f3083fab 100644 --- a/examples/CoolingBox/coolingBox.yml +++ b/examples/CoolingBox/coolingBox.yml @@ -1,7 +1,7 @@ # Define the system of units to use internally. InternalUnitSystem: UnitMass_in_cgs: 2.0e33 # Solar masses - UnitLength_in_cgs: 3.01e21 # Kilparsecs + UnitLength_in_cgs: 3.0857e21 # Kiloparsecs UnitVelocity_in_cgs: 1.0e5 # Time unit is cooling time UnitCurrent_in_cgs: 1 # Amperes UnitTemp_in_cgs: 1 # Kelvin @@ -9,9 +9,9 @@ InternalUnitSystem: # Parameters governing the time integration TimeIntegration: time_begin: 0. # The starting time of the simulation (in internal units). - time_end: 1.0 # The end time of the simulation (in internal units). - dt_min: 1e-6 # The minimal time-step size of the simulation (in internal units). - dt_max: 1e-2 # The maximal time-step size of the simulation (in internal units). + time_end: 4. # The end time of the simulation (in internal units). + dt_min: 1e-4 # 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). # Parameters governing the snapshots Snapshots: @@ -27,7 +27,6 @@ Statistics: SPH: resolution_eta: 1.2348 # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel). delta_neighbours: 0.1 # The tolerance for the targetted number of neighbours. - max_smoothing_length: 0.1 # Maximal smoothing length allowed (in internal units). CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. # Parameters related to the initial conditions @@ -36,9 +35,8 @@ InitialConditions: # Dimensionless pre-factor for the time-step condition LambdaCooling: - lambda: 0.0 # Cooling rate (in cgs units) + lambda_cgs: 1.0e-22 # Cooling rate (in cgs units) minimum_temperature: 1.0e4 # Minimal temperature (Kelvin) mean_molecular_weight: 0.59 # Mean molecular weight hydrogen_mass_abundance: 0.75 # Hydrogen mass abundance (dimensionless) cooling_tstep_mult: 1.0 # Dimensionless pre-factor for the time-step condition - diff --git a/examples/CoolingBox/energy_plot.py b/examples/CoolingBox/energy_plot.py index 28cf9ab64decb5b56e98118a407221fac2bd4f16..00e6fd1dfa0ee9bfbb9b5147282776f635b060f5 100644 --- a/examples/CoolingBox/energy_plot.py +++ b/examples/CoolingBox/energy_plot.py @@ -13,7 +13,7 @@ m_p = 1.67e-24 #proton mass #initial conditions set in makeIC.py rho = 3.2e3 P = 4.5e6 -n_H_cgs = 0.0001 +#n_H_cgs = 0.0001 gamma = 5./3. T_init = 1.0e5 @@ -24,7 +24,7 @@ unit_mass = units.attrs["Unit mass in cgs (U_M)"] unit_length = units.attrs["Unit length in cgs (U_L)"] unit_time = units.attrs["Unit time in cgs (U_t)"] parameters = f["Parameters"] -cooling_lambda = float(parameters.attrs["LambdaCooling:lambda"]) +cooling_lambda = float(parameters.attrs["LambdaCooling:lambda_cgs"]) min_T = float(parameters.attrs["LambdaCooling:minimum_temperature"]) mu = float(parameters.attrs["LambdaCooling:mean_molecular_weight"]) X_H = float(parameters.attrs["LambdaCooling:hydrogen_mass_abundance"]) @@ -32,50 +32,65 @@ X_H = float(parameters.attrs["LambdaCooling:hydrogen_mass_abundance"]) #get number of particles header = f["Header"] n_particles = header.attrs["NumPart_ThisFile"][0] + #read energy and time arrays array = np.genfromtxt(stats_filename,skip_header = 1) time = array[:,0] -total_energy = array[:,2] +kin_plus_therm = array[:,2] +radiated = array[:,6] total_mass = array[:,1] +#ignore first row where there are just zeros time = time[1:] -total_energy = total_energy[1:] +kin_plus_therm = kin_plus_therm[1:] +radiated = radiated[1:] total_mass = total_mass[1:] +total_energy = kin_plus_therm + radiated +initial_energy = total_energy[0] #conversions to cgs rho_cgs = rho * unit_mass / (unit_length)**3 time_cgs = time * unit_time -u_init_cgs = total_energy[0]/(total_mass[0]) * unit_length**2 / (unit_time)**2 +initial_energy_cgs = initial_energy/total_mass[0] * unit_length**2 / (unit_time)**2 +n_H_cgs = X_H * rho_cgs / m_p #find the energy floor -print min_T u_floor_cgs = k_b * min_T / (mu * m_p * (gamma - 1.)) + #find analytic solution -analytic_time = np.linspace(time_cgs[0],time_cgs[-1],1000) -print time_cgs[1] -print analytic_time[1] +analytic_time_cgs = np.linspace(0,time_cgs[-1],1000) du_dt_cgs = -cooling_lambda * n_H_cgs**2 / rho_cgs -u_analytic = du_dt_cgs*(analytic_time - analytic_time[0]) + u_init_cgs -cooling_time = u_init_cgs/(-du_dt_cgs) -#rescale energy to initial energy -total_energy /= total_energy[0] -u_analytic /= u_init_cgs -u_floor_cgs /= u_init_cgs -# plot_title = r"$\Lambda \, = \, %1.1g \mathrm{erg}\mathrm{cm^3}\mathrm{s^{-1}} \, \, T_{init} = %1.1g\mathrm{K} \, \, T_{floor} = %1.1g\mathrm{K} \, \, n_H = %1.1g\mathrm{cm^{-3}}$" %(cooling_lambda,T_init,T_floor,n_H) -# plot_filename = "energy_plot_creasey_no_cooling_T_init_1p0e5_n_H_0p1.png" -#analytic_solution = np.zeros(n_snaps-1) -for i in range(u_analytic.size): - if u_analytic[i]<u_floor_cgs: - u_analytic[i] = u_floor_cgs -plt.plot(time_cgs,total_energy,'k',label = "Numerical solution") -plt.plot(analytic_time,u_analytic,'--r',lw = 2.0,label = "Analytic Solution") -plt.plot((cooling_time,cooling_time),(0,1),'b',label = "Cooling time") -plt.plot((time_cgs[0],time_cgs[0]),(0,1),'m',label = "First output") -plt.title(r"$n_H = %1.1e \, \mathrm{cm}^{-3}$" %n_H_cgs) -plt.xlabel("Time (seconds)") -plt.ylabel("Energy/Initial energy") +u_analytic_cgs = du_dt_cgs*analytic_time_cgs + initial_energy_cgs +cooling_time_cgs = initial_energy_cgs/(-du_dt_cgs) + +for i in range(u_analytic_cgs.size): + if u_analytic_cgs[i]<u_floor_cgs: + u_analytic_cgs[i] = u_floor_cgs + +#rescale analytic solution +u_analytic = u_analytic_cgs/initial_energy_cgs + +#put time in units of cooling_time +time=time_cgs/cooling_time_cgs +analytic_time = analytic_time_cgs/cooling_time_cgs + +#rescale (numerical) energy by initial energy +radiated /= initial_energy +kin_plus_therm /= initial_energy +total_energy = kin_plus_therm + radiated +plt.plot(time,kin_plus_therm,'kd',label = "Kinetic + thermal energy") +plt.plot(time,radiated,'bo',label = "Radiated energy") +plt.plot(time,total_energy,'g',label = "Total energy") +plt.plot(analytic_time,u_analytic,'r',lw = 2.0,label = "Analytic Solution") +#plt.plot(analytic_time,1-u_analytic,'k',lw = 2.0) +#plt.plot((cooling_time,cooling_time),(0,1),'b',label = "Cooling time") +#plt.plot((time[1]-time_cgs[0],time_cgs[1]-time_cgs[0]),(0,1),'m',label = "First output") +#plt.title(r"$n_H = %1.1e \, \mathrm{cm}^{-3}$" %n_H_cgs) +plt.xlabel("Time / cooling time") +plt.ylabel("Energy / Initial energy") +#plt.ylim(0,1.1) plt.ylim(0.999,1.001) -plt.xlim(0,min(10.0*cooling_time,time_cgs[-1])) +#plt.xlim(0,min(10,time[-1])) plt.legend(loc = "upper right") if (int(sys.argv[1])==0): plt.show() diff --git a/examples/CoolingBox/makeIC.py b/examples/CoolingBox/makeIC.py index f35c9243d4fa71f872fd27520de14a23073c4b9d..5de012a17af4eef71e56548602e7956faef529f5 100644 --- a/examples/CoolingBox/makeIC.py +++ b/examples/CoolingBox/makeIC.py @@ -27,10 +27,10 @@ from numpy import * # Parameters periodic= 1 # 1 For periodic box -boxSize = 1 #1 kiloparsec +boxSize = 1 # 1 kiloparsec L = int(sys.argv[1]) # Number of particles along one axis -rho = 3.2e3 # Density in code units (0.01 hydrogen atoms per cm^3) -P = 4.5e6 # Pressure in code units (at 10^5K) +rho = 3.2e3 # Density in code units (3.2e6 is 0.1 hydrogen atoms per cm^3) +P = 4.5e6 # Pressure in code units (at 10^5K) gamma = 5./3. # Gas adiabatic index eta = 1.2349 # 48 ngbs with cubic spline kernel fileName = "coolingBox.hdf5" @@ -63,9 +63,9 @@ grp.attrs["PeriodicBoundariesOn"] = periodic #Units grp = file.create_group("/Units") -grp.attrs["Unit length in cgs (U_L)"] = 3.08e21 +grp.attrs["Unit length in cgs (U_L)"] = 3.0857e21 grp.attrs["Unit mass in cgs (U_M)"] = 2.0e33 -grp.attrs["Unit time in cgs (U_t)"] = 3.08e16 +grp.attrs["Unit time in cgs (U_t)"] = 3.0857e16 grp.attrs["Unit current in cgs (U_I)"] = 1. grp.attrs["Unit temperature in cgs (U_T)"] = 1. diff --git a/examples/CoolingBox/run.sh b/examples/CoolingBox/run.sh index c78eec9da6c486bc31a60ab7a8521ce6a6a63165..cb3264808d57b435c9f65bf5a684a94ff9f878fd 100755 --- a/examples/CoolingBox/run.sh +++ b/examples/CoolingBox/run.sh @@ -5,6 +5,10 @@ echo "Generating initial conditions for the cooling box example..." python makeIC.py 10 -../swift -s -t 1 coolingBox.yml -C 2>&1 | tee output.log +../swift -s -C -t 16 coolingBox.yml + +#-C 2>&1 | tee output.log python energy_plot.py 0 + +#python test_energy_conservation.py 0 diff --git a/examples/CoolingBox/test_energy_conservation.py b/examples/CoolingBox/test_energy_conservation.py new file mode 100644 index 0000000000000000000000000000000000000000..bb15071c0668d71580015351ce75ce18390c8cf0 --- /dev/null +++ b/examples/CoolingBox/test_energy_conservation.py @@ -0,0 +1,116 @@ +import numpy as np +import matplotlib.pyplot as plt +import h5py as h5 +import sys + +stats_filename = "./energy.txt" +snap_filename = "coolingBox_000.hdf5" +#plot_dir = "./" +n_snaps = 41 +time_end = 4.0 +dt_snap = 0.1 +#some constants in cgs units +k_b = 1.38E-16 #boltzmann +m_p = 1.67e-24 #proton mass +#initial conditions set in makeIC.py +rho = 4.8e3 +P = 4.5e6 +#n_H_cgs = 0.0001 +gamma = 5./3. +T_init = 1.0e5 + +#find the sound speed + +#Read the units parameters from the snapshot +f = h5.File(snap_filename,'r') +units = f["InternalCodeUnits"] +unit_mass = units.attrs["Unit mass in cgs (U_M)"] +unit_length = units.attrs["Unit length in cgs (U_L)"] +unit_time = units.attrs["Unit time in cgs (U_t)"] +parameters = f["Parameters"] +cooling_lambda = float(parameters.attrs["LambdaCooling:lambda_cgs"]) +min_T = float(parameters.attrs["LambdaCooling:minimum_temperature"]) +mu = float(parameters.attrs["LambdaCooling:mean_molecular_weight"]) +X_H = float(parameters.attrs["LambdaCooling:hydrogen_mass_abundance"]) + +#get number of particles +header = f["Header"] +n_particles = header.attrs["NumPart_ThisFile"][0] +#read energy and time arrays +array = np.genfromtxt(stats_filename,skip_header = 1) +time = array[:,0] +total_energy = array[:,2] +total_mass = array[:,1] + +time = time[1:] +total_energy = total_energy[1:] +total_mass = total_mass[1:] + +#conversions to cgs +rho_cgs = rho * unit_mass / (unit_length)**3 +time_cgs = time * unit_time +u_init_cgs = total_energy[0]/(total_mass[0]) * unit_length**2 / (unit_time)**2 +n_H_cgs = X_H * rho_cgs / m_p + +#find the sound speed in cgs +c_s = np.sqrt((gamma - 1.)*k_b*T_init/(mu*m_p)) +#assume box size is unit length +sound_crossing_time = unit_length/c_s + +print "Sound speed = %g cm/s" %c_s +print "Sound crossing time = %g s" %sound_crossing_time +#find the energy floor +u_floor_cgs = k_b * min_T / (mu * m_p * (gamma - 1.)) +#find analytic solution +analytic_time_cgs = np.linspace(time_cgs[0],time_cgs[-1],1000) +du_dt_cgs = -cooling_lambda * n_H_cgs**2 / rho_cgs +u_analytic = du_dt_cgs*(analytic_time_cgs - analytic_time_cgs[0]) + u_init_cgs +cooling_time = u_init_cgs/(-du_dt_cgs) + +#put time in units of sound crossing time +time=time_cgs/sound_crossing_time +analytic_time = analytic_time_cgs/sound_crossing_time +#rescale energy to initial energy +total_energy /= total_energy[0] +u_analytic /= u_init_cgs +u_floor_cgs /= u_init_cgs +# plot_title = r"$\Lambda \, = \, %1.1g \mathrm{erg}\mathrm{cm^3}\mathrm{s^{-1}} \, \, T_{init} = %1.1g\mathrm{K} \, \, T_{floor} = %1.1g\mathrm{K} \, \, n_H = %1.1g\mathrm{cm^{-3}}$" %(cooling_lambda,T_init,T_floor,n_H) +# plot_filename = "energy_plot_creasey_no_cooling_T_init_1p0e5_n_H_0p1.png" +#analytic_solution = np.zeros(n_snaps-1) +for i in range(u_analytic.size): + if u_analytic[i]<u_floor_cgs: + u_analytic[i] = u_floor_cgs +plt.plot(time-time[0],total_energy,'k',label = "Numerical solution from energy.txt") +plt.plot(analytic_time-analytic_time[0],u_analytic,'r',lw = 2.0,label = "Analytic Solution") + +#now get energies from the snapshots +snapshot_time = np.linspace(0,time_end,num = n_snaps) +snapshot_time = snapshot_time[1:] +snapshot_time_cgs = snapshot_time * unit_time +snapshot_time = snapshot_time_cgs/ sound_crossing_time +snapshot_time -= snapshot_time[0] +snapshot_energy = np.zeros(n_snaps) +for i in range(0,n_snaps): + snap_filename = "coolingBox_%03d.hdf5" %i + f = h5.File(snap_filename,'r') + snapshot_internal_energy_array = np.array(f["PartType0/InternalEnergy"]) + total_internal_energy = np.sum(snapshot_internal_energy_array) + velocity_array = np.array(f["PartType0/Velocities"]) + total_kinetic_energy = 0.5*np.sum(velocity_array**2) + snapshot_energy[i] = total_internal_energy + total_kinetic_energy +snapshot_energy/=snapshot_energy[0] +snapshot_energy = snapshot_energy[1:] + +plt.plot(snapshot_time,snapshot_energy,'bd',label = "Numerical solution from snapshots") + +#plt.title(r"$n_H = %1.1e \, \mathrm{cm}^{-3}$" %n_H_cgs) +plt.xlabel("Time (sound crossing time)") +plt.ylabel("Energy/Initial energy") +plt.ylim(0.99,1.01) +#plt.xlim(0,min(10,time[-1])) +plt.legend(loc = "upper right") +if (int(sys.argv[1])==0): + plt.show() +else: + plt.savefig(full_plot_filename,format = "png") + plt.close() diff --git a/examples/CoolingHalo/README b/examples/CoolingHalo/README new file mode 100644 index 0000000000000000000000000000000000000000..7ef3c5e0283a500856582b386300aad630c0a55a --- /dev/null +++ b/examples/CoolingHalo/README @@ -0,0 +1,25 @@ + +To make the initial conditions we distribute gas particles randomly in +a cube with a side length twice that of the virial radius. The density +profile of the gas is proportional to r^(-2) where r is the distance +from the centre of the cube. + +The parameter v_rot (in makeIC.py and cooling.yml) sets the circular +velocity of the halo, and by extension, the viral radius, viral mass, +and the internal energy of the gas such that hydrostatic equilibrium +is achieved. + +While the system is initially in hydrostatic equilibrium, the cooling +of the gas means that the halo will collapse. + +To run this example, make such that the code is compiled with either +the isothermal potential or softened isothermal potential, and +'const_lambda' cooling, set in src/const.h. In the latter case, a +(small) value of epsilon needs to be set in cooling.yml. 0.1 kpc +should work well. + +The plotting scripts produce a plot of the density, internal energy +and radial velocity profile for each +snapshot. test_energy_conservation.py shows the evolution of energy +with time. These can be used to check if the example has run properly. + diff --git a/examples/CoolingHalo/cooling_halo.yml b/examples/CoolingHalo/cooling_halo.yml new file mode 100644 index 0000000000000000000000000000000000000000..c06b099eb0dd06d39040e0ecc8e8f1320a89ac6b --- /dev/null +++ b/examples/CoolingHalo/cooling_halo.yml @@ -0,0 +1,54 @@ +# Define the system of units to use internally. +InternalUnitSystem: + UnitMass_in_cgs: 1.9885e39 # 10^6 solar masses + UnitLength_in_cgs: 3.0856776e21 # Kiloparsecs + UnitVelocity_in_cgs: 1e5 # Kilometres per second + UnitCurrent_in_cgs: 1 # Amperes + UnitTemp_in_cgs: 1 # Kelvin + +# Parameters governing the time integration +TimeIntegration: + time_begin: 0. # The starting time of the simulation (in internal units). + time_end: 10.0 # The end time of the simulation (in internal units). + dt_min: 1e-5 # The minimal time-step size of the simulation (in internal units). + dt_max: 1e-2 # The maximal time-step size of the simulation (in internal units). + +# Parameters governing the conserved quantities statistics +Statistics: + delta_time: 1e-2 # Time between statistics output + +# Parameters governing the snapshots +Snapshots: + basename: CoolingHalo # Common part of the name of output files + time_first: 0. # Time of the first output (in internal units) + delta_time: 0.1 # Time difference between consecutive outputs (in internal units) + +# Parameters for the hydrodynamics scheme +SPH: + resolution_eta: 1.2349 # Target smoothing length in units of the mean inter-particle separation (1.2349 == 48Ngbs with the cubic spline kernel). + delta_neighbours: 1. # The tolerance for the targetted number of neighbours. + CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. + +# Parameters related to the initial conditions +InitialConditions: + file_name: CoolingHalo.hdf5 # The file to read + shift_x: 0. # A shift to apply to all particles read from the ICs (in internal units). + shift_y: 0. + shift_z: 0. + +# External potential parameters +SoftenedIsothermalPotential: + position_x: 0. # location of centre of isothermal potential in internal units + position_y: 0. + position_z: 0. + vrot: 200. # rotation speed of isothermal potential in internal units + timestep_mult: 0.03 # controls time step + epsilon: 0.1 #softening for the isothermal potential + +# Cooling parameters +LambdaCooling: + lambda_cgs: 1.0e-22 # Cooling rate (in cgs units) + minimum_temperature: 1.0e4 # Minimal temperature (Kelvin) + mean_molecular_weight: 0.59 # Mean molecular weight + hydrogen_mass_abundance: 0.75 # Hydrogen mass abundance (dimensionless) + cooling_tstep_mult: 1.0 # Dimensionless pre-factor for the time-step condition diff --git a/examples/CoolingHalo/density_profile.py b/examples/CoolingHalo/density_profile.py new file mode 100644 index 0000000000000000000000000000000000000000..335f7089b6835b65cf37e1bcd312a17966c295a7 --- /dev/null +++ b/examples/CoolingHalo/density_profile.py @@ -0,0 +1,101 @@ +import numpy as np +import h5py as h5 +import matplotlib.pyplot as plt +import sys + +n_snaps = 11 + +#for the plotting +#n_radial_bins = int(sys.argv[1]) + +#some constants +OMEGA = 0.3 # Cosmological matter fraction at z = 0 +PARSEC_IN_CGS = 3.0856776e18 +KM_PER_SEC_IN_CGS = 1.0e5 +CONST_G_CGS = 6.672e-8 +h = 0.67777 # hubble parameter +gamma = 5./3. +eta = 1.2349 +H_0_cgs = 100. * h * KM_PER_SEC_IN_CGS / (1.0e6 * PARSEC_IN_CGS) + +#read some header/parameter information from the first snapshot + +filename = "Hydrostatic_000.hdf5" +f = h5.File(filename,'r') +params = f["Parameters"] +unit_mass_cgs = float(params.attrs["InternalUnitSystem:UnitMass_in_cgs"]) +unit_length_cgs = float(params.attrs["InternalUnitSystem:UnitLength_in_cgs"]) +unit_velocity_cgs = float(params.attrs["InternalUnitSystem:UnitVelocity_in_cgs"]) +unit_time_cgs = unit_length_cgs / unit_velocity_cgs +v_c = float(params.attrs["IsothermalPotential:vrot"]) +v_c_cgs = v_c * unit_velocity_cgs +header = f["Header"] +N = header.attrs["NumPart_Total"][0] +box_centre = np.array(header.attrs["BoxSize"]) + +#calculate r_vir and M_vir from v_c +r_vir_cgs = v_c_cgs / (10. * H_0_cgs * np.sqrt(OMEGA)) +M_vir_cgs = r_vir_cgs * v_c_cgs**2 / CONST_G_CGS + +for i in range(n_snaps): + + filename = "Hydrostatic_%03d.hdf5" %i + f = h5.File(filename,'r') + coords_dset = f["PartType0/Coordinates"] + coords = np.array(coords_dset) +#translate coords by centre of box + header = f["Header"] + snap_time = header.attrs["Time"] + snap_time_cgs = snap_time * unit_time_cgs + coords[:,0] -= box_centre[0]/2. + coords[:,1] -= box_centre[1]/2. + coords[:,2] -= box_centre[2]/2. + radius = np.sqrt(coords[:,0]**2 + coords[:,1]**2 + coords[:,2]**2) + radius_cgs = radius*unit_length_cgs + radius_over_virial_radius = radius_cgs / r_vir_cgs + + r = radius_over_virial_radius + + # bin_width = 1./n_radial_bins +# hist = np.histogram(r,bins = n_radial_bins)[0] # number of particles in each bin + +# #find the mass in each radial bin + +# mass_dset = f["PartType0/Masses"] +# #mass of each particles should be equal +# part_mass = np.array(mass_dset)[0] +# part_mass_cgs = part_mass * unit_mass_cgs +# part_mass_over_virial_mass = part_mass_cgs / M_vir_cgs + +# mass_hist = hist * part_mass_over_virial_mass +# radial_bin_mids = np.linspace(bin_width/2.,1 - bin_width/2.,n_radial_bins) +# #volume in each radial bin +# volume = 4.*np.pi * radial_bin_mids**2 * bin_width + +# #now divide hist by the volume so we have a density in each bin + +# density = mass_hist / volume + + # read the densities + + density_dset = f["PartType0/Density"] + density = np.array(density_dset) + density_cgs = density * unit_mass_cgs / unit_length_cgs**3 + rho = density_cgs * r_vir_cgs**3 / M_vir_cgs + + t = np.linspace(0.01,2.0,1000) + rho_analytic = t**(-2)/(4.*np.pi) + + plt.plot(r,rho,'x',label = "Numerical solution") + plt.plot(t,rho_analytic,label = "Analytic Solution") + plt.legend(loc = "upper right") + plt.xlabel(r"$r / r_{vir}$") + plt.ylabel(r"$\rho / (M_{vir} / r_{vir}^3)$") + plt.title(r"$\mathrm{Time}= %.3g \, s \, , \, %d \, \, \mathrm{particles} \,,\, v_c = %.1f \, \mathrm{km / s}$" %(snap_time_cgs,N,v_c)) + #plt.ylim((0.1,40)) + plt.xscale('log') + plt.yscale('log') + plot_filename = "density_profile_%03d.png" %i + plt.savefig(plot_filename,format = "png") + plt.close() + diff --git a/examples/CoolingHalo/internal_energy_profile.py b/examples/CoolingHalo/internal_energy_profile.py new file mode 100644 index 0000000000000000000000000000000000000000..854bdf223cfae75203a1924b4af6136b4b7aa6cd --- /dev/null +++ b/examples/CoolingHalo/internal_energy_profile.py @@ -0,0 +1,104 @@ +import numpy as np +import h5py as h5 +import matplotlib.pyplot as plt +import sys + +def do_binning(x,y,x_bin_edges): + + #x and y are arrays, where y = f(x) + #returns number of elements of x in each bin, and the total of the y elements corresponding to those x values + + n_bins = x_bin_edges.size - 1 + count = np.zeros(n_bins) + y_totals = np.zeros(n_bins) + + for i in range(n_bins): + ind = np.intersect1d(np.where(x > bin_edges[i])[0],np.where(x <= bin_edges[i+1])[0]) + count[i] = ind.size + binned_y = y[ind] + y_totals[i] = np.sum(binned_y) + + return(count,y_totals) + + +n_snaps = 100 + +#for the plotting +n_radial_bins = int(sys.argv[1]) + +#some constants +OMEGA = 0.3 # Cosmological matter fraction at z = 0 +PARSEC_IN_CGS = 3.0856776e18 +KM_PER_SEC_IN_CGS = 1.0e5 +CONST_G_CGS = 6.672e-8 +h = 0.67777 # hubble parameter +gamma = 5./3. +eta = 1.2349 +H_0_cgs = 100. * h * KM_PER_SEC_IN_CGS / (1.0e6 * PARSEC_IN_CGS) + +#read some header/parameter information from the first snapshot + +filename = "Hydrostatic_000.hdf5" +f = h5.File(filename,'r') +params = f["Parameters"] +unit_mass_cgs = float(params.attrs["InternalUnitSystem:UnitMass_in_cgs"]) +unit_length_cgs = float(params.attrs["InternalUnitSystem:UnitLength_in_cgs"]) +unit_velocity_cgs = float(params.attrs["InternalUnitSystem:UnitVelocity_in_cgs"]) +unit_time_cgs = unit_length_cgs / unit_velocity_cgs +v_c = float(params.attrs["IsothermalPotential:vrot"]) +v_c_cgs = v_c * unit_velocity_cgs +header = f["Header"] +N = header.attrs["NumPart_Total"][0] +box_centre = np.array(header.attrs["BoxSize"]) + +#calculate r_vir and M_vir from v_c +r_vir_cgs = v_c_cgs / (10. * H_0_cgs * np.sqrt(OMEGA)) +M_vir_cgs = r_vir_cgs * v_c_cgs**2 / CONST_G_CGS + +for i in range(n_snaps): + + filename = "Hydrostatic_%03d.hdf5" %i + f = h5.File(filename,'r') + coords_dset = f["PartType0/Coordinates"] + coords = np.array(coords_dset) +#translate coords by centre of box + header = f["Header"] + snap_time = header.attrs["Time"] + snap_time_cgs = snap_time * unit_time_cgs + coords[:,0] -= box_centre[0]/2. + coords[:,1] -= box_centre[1]/2. + coords[:,2] -= box_centre[2]/2. + radius = np.sqrt(coords[:,0]**2 + coords[:,1]**2 + coords[:,2]**2) + radius_cgs = radius*unit_length_cgs + radius_over_virial_radius = radius_cgs / r_vir_cgs + +#get the internal energies + u_dset = f["PartType0/InternalEnergy"] + u = np.array(u_dset) + +#make dimensionless + u /= v_c**2/(2. * (gamma - 1.)) + r = radius_over_virial_radius + + bin_edges = np.linspace(0,1,n_radial_bins + 1) + (hist,u_totals) = do_binning(r,u,bin_edges) + + bin_widths = 1. / n_radial_bins + radial_bin_mids = np.linspace(bin_widths / 2. , 1. - bin_widths / 2. , n_radial_bins) + binned_u = u_totals / hist + + + plt.plot(radial_bin_mids,binned_u,'ko',label = "Numerical solution") + plt.plot((0,1),(1,1),label = "Analytic Solution") + plt.legend(loc = "lower right") + plt.xlabel(r"$r / r_{vir}$") + plt.ylabel(r"$u / (v_c^2 / (2(\gamma - 1)) $") + plt.title(r"$\mathrm{Time}= %.3g \, s \, , \, %d \, \, \mathrm{particles} \,,\, v_c = %.1f \, \mathrm{km / s}$" %(snap_time_cgs,N,v_c)) + plt.ylim((0,1)) + plot_filename = "internal_energy_profile_%03d.png" %i + plt.savefig(plot_filename,format = "png") + plt.close() + + + + diff --git a/examples/CoolingHalo/makeIC.py b/examples/CoolingHalo/makeIC.py new file mode 100644 index 0000000000000000000000000000000000000000..0b542e200da709e2cc7f668ab8b62b94e0bf95ee --- /dev/null +++ b/examples/CoolingHalo/makeIC.py @@ -0,0 +1,234 @@ +############################################################################### + # This file is part of SWIFT. + # Copyright (c) 2016 Stefan Arridge (stefan.arridge@durham.ac.uk) + # + # This program is free software: you can redistribute it and/or modify + # it under the terms of the GNU Lesser General Public License as published + # by the Free Software Foundation, either version 3 of the License, or + # (at your option) any later version. + # + # This program is distributed in the hope that it will be useful, + # but WITHOUT ANY WARRANTY; without even the implied warranty of + # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + # GNU General Public License for more details. + # + # You should have received a copy of the GNU Lesser General Public License + # along with this program. If not, see <http://www.gnu.org/licenses/>. + # + ############################################################################## + +import h5py +import sys +import numpy as np +import math +import random + +# Generates N particles in a spherically symmetric distribution with density profile ~r^(-2) +# usage: python makeIC.py 1000: generate 1000 particles + +# Some constants + +OMEGA = 0.3 # Cosmological matter fraction at z = 0 +PARSEC_IN_CGS = 3.0856776e18 +KM_PER_SEC_IN_CGS = 1.0e5 +CONST_G_CGS = 6.672e-8 +h = 0.67777 # hubble parameter +gamma = 5./3. +eta = 1.2349 + +# First set unit velocity and then the circular velocity parameter for the isothermal potential +const_unit_velocity_in_cgs = 1.e5 #kms^-1 + +v_c = 200. +v_c_cgs = v_c * const_unit_velocity_in_cgs + +# Now we use this to get the virial mass and virial radius, which we will set to be the unit mass and radius + +# Find H_0, the inverse Hubble time, in cgs + +H_0_cgs = 100. * h * KM_PER_SEC_IN_CGS / (1.0e6 * PARSEC_IN_CGS) + +# From this we can find the virial radius, the radius within which the average density of the halo is +# 200. * the mean matter density + +r_vir_cgs = v_c_cgs / (10. * H_0_cgs * np.sqrt(OMEGA)) + +# Now get the virial mass + +M_vir_cgs = r_vir_cgs * v_c_cgs**2 / CONST_G_CGS + +# Now set the unit length and mass + +const_unit_mass_in_cgs = M_vir_cgs +const_unit_length_in_cgs = r_vir_cgs + +print "UnitMass_in_cgs: ", const_unit_mass_in_cgs +print "UnitLength_in_cgs: ", const_unit_length_in_cgs +print "UnitVelocity_in_cgs: ", const_unit_velocity_in_cgs + +#derived quantities +const_unit_time_in_cgs = (const_unit_length_in_cgs / const_unit_velocity_in_cgs) +print "UnitTime_in_cgs: ", const_unit_time_in_cgs +const_G = ((CONST_G_CGS*const_unit_mass_in_cgs*const_unit_time_in_cgs*const_unit_time_in_cgs/(const_unit_length_in_cgs*const_unit_length_in_cgs*const_unit_length_in_cgs))) +print 'G=', const_G + +# Parameters +periodic= 1 # 1 For periodic box +boxSize = 4. +G = const_G +N = int(sys.argv[1]) # Number of particles + +# Create the file +filename = "CoolingHalo.hdf5" +file = h5py.File(filename, 'w') + +#Units +grp = file.create_group("/Units") +grp.attrs["Unit length in cgs (U_L)"] = const_unit_length_in_cgs +grp.attrs["Unit mass in cgs (U_M)"] = const_unit_mass_in_cgs +grp.attrs["Unit time in cgs (U_t)"] = const_unit_length_in_cgs / const_unit_velocity_in_cgs +grp.attrs["Unit current in cgs (U_I)"] = 1. +grp.attrs["Unit temperature in cgs (U_T)"] = 1. + + +# Runtime parameters +grp = file.create_group("/RuntimePars") +grp.attrs["PeriodicBoundariesOn"] = periodic + +# set seed for random number +np.random.seed(1234) + + +# Positions +# r^(-2) distribution corresponds to uniform distribution in radius +radius = boxSize * np.sqrt(3.) / 2.* np.random.rand(N) #the diagonal extent of the cube +ctheta = -1. + 2 * np.random.rand(N) +stheta = np.sqrt(1.-ctheta**2) +phi = 2 * math.pi * np.random.rand(N) +coords = np.zeros((N, 3)) +coords[:,0] = radius * stheta * np.cos(phi) +coords[:,1] = radius * stheta * np.sin(phi) +coords[:,2] = radius * ctheta + +#shift to centre of box +coords += np.full((N,3),boxSize/2.) +print "x range = (%f,%f)" %(np.min(coords[:,0]),np.max(coords[:,0])) +print "y range = (%f,%f)" %(np.min(coords[:,1]),np.max(coords[:,1])) +print "z range = (%f,%f)" %(np.min(coords[:,2]),np.max(coords[:,2])) + +print np.mean(coords[:,0]) +print np.mean(coords[:,1]) +print np.mean(coords[:,2]) + +#now find the particles which are within the box + +x_coords = coords[:,0] +y_coords = coords[:,1] +z_coords = coords[:,2] + +ind = np.where(x_coords < boxSize)[0] +x_coords = x_coords[ind] +y_coords = y_coords[ind] +z_coords = z_coords[ind] + +ind = np.where(x_coords > 0.)[0] +x_coords = x_coords[ind] +y_coords = y_coords[ind] +z_coords = z_coords[ind] + +ind = np.where(y_coords < boxSize)[0] +x_coords = x_coords[ind] +y_coords = y_coords[ind] +z_coords = z_coords[ind] + +ind = np.where(y_coords > 0.)[0] +x_coords = x_coords[ind] +y_coords = y_coords[ind] +z_coords = z_coords[ind] + +ind = np.where(z_coords < boxSize)[0] +x_coords = x_coords[ind] +y_coords = y_coords[ind] +z_coords = z_coords[ind] + +ind = np.where(z_coords > 0.)[0] +x_coords = x_coords[ind] +y_coords = y_coords[ind] +z_coords = z_coords[ind] + +#count number of particles + +N = x_coords.size + +print "Number of particles in the box = " , N + +#make the coords and radius arrays again +coords_2 = np.zeros((N,3)) +coords_2[:,0] = x_coords +coords_2[:,1] = y_coords +coords_2[:,2] = z_coords + +radius = np.sqrt(coords_2[:,0]**2 + coords_2[:,1]**2 + coords_2[:,2]**2) + +#test we've done it right + +print "x range = (%f,%f)" %(np.min(coords_2[:,0]),np.max(coords_2[:,0])) +print "y range = (%f,%f)" %(np.min(coords_2[:,1]),np.max(coords_2[:,1])) +print "z range = (%f,%f)" %(np.min(coords_2[:,2]),np.max(coords_2[:,2])) + +print np.mean(coords_2[:,0]) +print np.mean(coords_2[:,1]) +print np.mean(coords_2[:,2]) + +# Header +grp = file.create_group("/Header") +grp.attrs["BoxSize"] = boxSize +grp.attrs["NumPart_Total"] = [N ,0, 0, 0, 0, 0] +grp.attrs["NumPart_Total_HighWord"] = [0, 0, 0, 0, 0, 0] +grp.attrs["NumPart_ThisFile"] = [N, 0, 0, 0, 0, 0] +grp.attrs["Time"] = 0.0 +grp.attrs["NumFilesPerSnapshot"] = 1 +grp.attrs["MassTable"] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] +grp.attrs["Flag_Entropy_ICs"] = [0, 0, 0, 0, 0, 0] +grp.attrs["Dimension"] = 3 + +# Particle group +grp = file.create_group("/PartType0") + +ds = grp.create_dataset('Coordinates', (N, 3), 'd') +ds[()] = coords_2 +coords_2 = np.zeros(1) + +# All velocities set to zero +v = np.zeros((N,3)) +ds = grp.create_dataset('Velocities', (N, 3), 'f') +ds[()] = v +v = np.zeros(1) + +# All particles of equal mass +mass = 1. / N +m = np.full((N,),mass) +ds = grp.create_dataset('Masses', (N, ), 'f') +ds[()] = m +m = np.zeros(1) + +# Smoothing lengths +l = (4. * np.pi * radius**2 / N)**(1./3.) #local mean inter-particle separation +h = np.full((N, ), eta * l) +ds = grp.create_dataset('SmoothingLength', (N,), 'f') +ds[()] = h +h = np.zeros(1) + +# Internal energies +u = v_c**2 / (2. * (gamma - 1.)) +u = np.full((N, ), u) +ds = grp.create_dataset('InternalEnergy', (N,), 'f') +ds[()] = u +u = np.zeros(1) + +# Particle IDs +ids = 1 + np.linspace(0, N, N, endpoint=False, dtype='L') +ds = grp.create_dataset('ParticleIDs', (N, ), 'L') +ds[()] = ids + +file.close() diff --git a/examples/CoolingHalo/makeIC_random_box.py b/examples/CoolingHalo/makeIC_random_box.py new file mode 100644 index 0000000000000000000000000000000000000000..4295cb135233f2d5a59405b44e6d8e9c80a1f6c0 --- /dev/null +++ b/examples/CoolingHalo/makeIC_random_box.py @@ -0,0 +1,168 @@ +############################################################################### + # This file is part of SWIFT. + # Copyright (c) 2016 Stefan Arridge (stefan.arridge@durham.ac.uk) + # + # This program is free software: you can redistribute it and/or modify + # it under the terms of the GNU Lesser General Public License as published + # by the Free Software Foundation, either version 3 of the License, or + # (at your option) any later version. + # + # This program is distributed in the hope that it will be useful, + # but WITHOUT ANY WARRANTY; without even the implied warranty of + # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + # GNU General Public License for more details. + # + # You should have received a copy of the GNU Lesser General Public License + # along with this program. If not, see <http://www.gnu.org/licenses/>. + # + ############################################################################## + +import h5py +import sys +import numpy as np +import math +import random + +# Generates N particles in a spherically symmetric distribution with density profile ~r^(-2) +# usage: python makeIC.py 1000: generate 1000 particles + +# Some constants + +OMEGA = 0.3 # Cosmological matter fraction at z = 0 +PARSEC_IN_CGS = 3.0856776e18 +KM_PER_SEC_IN_CGS = 1.0e5 +CONST_G_CGS = 6.672e-8 +h = 0.67777 # hubble parameter +gamma = 5./3. +eta = 1.2349 + +# First set unit velocity and then the circular velocity parameter for the isothermal potential +const_unit_velocity_in_cgs = 1.e5 #kms^-1 + +v_c = 200. +v_c_cgs = v_c * const_unit_velocity_in_cgs + +# Now we use this to get the virial mass and virial radius, which we will set to be the unit mass and radius + +# Find H_0, the inverse Hubble time, in cgs + +H_0_cgs = 100. * h * KM_PER_SEC_IN_CGS / (1.0e6 * PARSEC_IN_CGS) + +# From this we can find the virial radius, the radius within which the average density of the halo is +# 200. * the mean matter density + +r_vir_cgs = v_c_cgs / (10. * H_0_cgs * np.sqrt(OMEGA)) + +# Now get the virial mass + +M_vir_cgs = r_vir_cgs * v_c_cgs**2 / CONST_G_CGS + +# Now set the unit length and mass + +const_unit_mass_in_cgs = M_vir_cgs +const_unit_length_in_cgs = r_vir_cgs + +print "UnitMass_in_cgs: ", const_unit_mass_in_cgs +print "UnitLength_in_cgs: ", const_unit_length_in_cgs +print "UnitVelocity_in_cgs: ", const_unit_velocity_in_cgs + +#derived quantities +const_unit_time_in_cgs = (const_unit_length_in_cgs / const_unit_velocity_in_cgs) +print "UnitTime_in_cgs: ", const_unit_time_in_cgs +const_G = ((CONST_G_CGS*const_unit_mass_in_cgs*const_unit_time_in_cgs*const_unit_time_in_cgs/(const_unit_length_in_cgs*const_unit_length_in_cgs*const_unit_length_in_cgs))) +print 'G=', const_G + +# Parameters +periodic= 1 # 1 For periodic box +boxSize = 4. +G = const_G +N = int(sys.argv[1]) # Number of particles + +# Create the file +filename = "random_box.hdf5" +file = h5py.File(filename, 'w') + +#Units +grp = file.create_group("/Units") +grp.attrs["Unit length in cgs (U_L)"] = const_unit_length_in_cgs +grp.attrs["Unit mass in cgs (U_M)"] = const_unit_mass_in_cgs +grp.attrs["Unit time in cgs (U_t)"] = const_unit_length_in_cgs / const_unit_velocity_in_cgs +grp.attrs["Unit current in cgs (U_I)"] = 1. +grp.attrs["Unit temperature in cgs (U_T)"] = 1. + +# Header +grp = file.create_group("/Header") +grp.attrs["BoxSize"] = boxSize +grp.attrs["NumPart_Total"] = [N ,0, 0, 0, 0, 0] +grp.attrs["NumPart_Total_HighWord"] = [0, 0, 0, 0, 0, 0] +grp.attrs["NumPart_ThisFile"] = [N, 0, 0, 0, 0, 0] +grp.attrs["Time"] = 0.0 +grp.attrs["NumFilesPerSnapshot"] = 1 +grp.attrs["MassTable"] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] +grp.attrs["Flag_Entropy_ICs"] = [0, 0, 0, 0, 0, 0] +grp.attrs["Dimension"] = 3 + +# Runtime parameters +grp = file.create_group("/RuntimePars") +grp.attrs["PeriodicBoundariesOn"] = periodic + +# set seed for random number +np.random.seed(1234) + +# Particle group +grp = file.create_group("/PartType0") + +# Positions + +# distribute particles randomly in the box +coords = np.zeros((N, 3)) +coords[:,0] = boxSize * np.random.rand(N) +coords[:,1] = boxSize * np.random.rand(N) +coords[:,2] = boxSize * np.random.rand(N) +#shift to centre of box +#coords += np.full((N,3),boxSize/2.) +print "x range = (%f,%f)" %(np.min(coords[:,0]),np.max(coords[:,0])) +print "y range = (%f,%f)" %(np.min(coords[:,1]),np.max(coords[:,1])) +print "z range = (%f,%f)" %(np.min(coords[:,2]),np.max(coords[:,2])) + +print np.mean(coords[:,0]) +print np.mean(coords[:,1]) +print np.mean(coords[:,2]) + +ds = grp.create_dataset('Coordinates', (N, 3), 'd') +ds[()] = coords +coords = np.zeros(1) + +# All velocities set to zero +v = np.zeros((N,3)) +ds = grp.create_dataset('Velocities', (N, 3), 'f') +ds[()] = v +v = np.zeros(1) + +# All particles of equal mass +mass = 1. / N +m = np.full((N,),mass) +ds = grp.create_dataset('Masses', (N, ), 'f') +ds[()] = m +m = np.zeros(1) + +# Smoothing lengths +l = (boxSize**3 / N)**(1./3.) #local mean inter-particle separation +h = np.full((N, ), eta * l) +ds = grp.create_dataset('SmoothingLength', (N,), 'f') +ds[()] = h +h = np.zeros(1) + +# Internal energies +u = v_c**2 / (2. * (gamma - 1.)) +u = np.full((N, ), u) +ds = grp.create_dataset('InternalEnergy', (N,), 'f') +ds[()] = u +u = np.zeros(1) + +# Particle IDs +ids = 1 + np.linspace(0, N, N, endpoint=False, dtype='L') +ds = grp.create_dataset('ParticleIDs', (N, ), 'L') +ds[()] = ids + +file.close() diff --git a/examples/CoolingHalo/run.sh b/examples/CoolingHalo/run.sh new file mode 100755 index 0000000000000000000000000000000000000000..60ceae649d183dce3a7e5019a1ff94ce7bc4f08d --- /dev/null +++ b/examples/CoolingHalo/run.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +# Generate the initial conditions if they are not present. +echo "Generating initial conditions for the isothermal potential box example..." +python makeIC.py 10000 + +../swift -g -s -C -t 16 cooling_halo.yml 2>&1 | tee output.log + +python radial_profile.py 2. 200 100 + +python internal_energy_profile.py 2. 200 100 + +python test_energy_conservation.py 2. 200 100 diff --git a/examples/CoolingHalo/test_energy_conservation.py b/examples/CoolingHalo/test_energy_conservation.py new file mode 100644 index 0000000000000000000000000000000000000000..00374e905e8eeb66bfe8c7360ab37522bc93af32 --- /dev/null +++ b/examples/CoolingHalo/test_energy_conservation.py @@ -0,0 +1,96 @@ +import numpy as np +import h5py as h5 +import matplotlib.pyplot as plt +import sys + +n_snaps = 41 + +#some constants +OMEGA = 0.3 # Cosmological matter fraction at z = 0 +PARSEC_IN_CGS = 3.0856776e18 +KM_PER_SEC_IN_CGS = 1.0e5 +CONST_G_CGS = 6.672e-8 +h = 0.67777 # hubble parameter +gamma = 5./3. +eta = 1.2349 +H_0_cgs = 100. * h * KM_PER_SEC_IN_CGS / (1.0e6 * PARSEC_IN_CGS) + +#read some header/parameter information from the first snapshot + +filename = "CoolingHalo_000.hdf5" +f = h5.File(filename,'r') +params = f["Parameters"] +unit_mass_cgs = float(params.attrs["InternalUnitSystem:UnitMass_in_cgs"]) +unit_length_cgs = float(params.attrs["InternalUnitSystem:UnitLength_in_cgs"]) +unit_velocity_cgs = float(params.attrs["InternalUnitSystem:UnitVelocity_in_cgs"]) +unit_time_cgs = unit_length_cgs / unit_velocity_cgs +v_c = float(params.attrs["SoftenedIsothermalPotential:vrot"]) +v_c_cgs = v_c * unit_velocity_cgs +header = f["Header"] +N = header.attrs["NumPart_Total"][0] +box_centre = np.array(header.attrs["BoxSize"]) + +#calculate r_vir and M_vir from v_c +r_vir_cgs = v_c_cgs / (10. * H_0_cgs * np.sqrt(OMEGA)) +M_vir_cgs = r_vir_cgs * v_c_cgs**2 / CONST_G_CGS + +potential_energy_array = [] +internal_energy_array = [] +kinetic_energy_array = [] +time_array_cgs = [] + +for i in range(n_snaps): + + filename = "CoolingHalo_%03d.hdf5" %i + f = h5.File(filename,'r') + coords_dset = f["PartType0/Coordinates"] + coords = np.array(coords_dset) +#translate coords by centre of box + header = f["Header"] + snap_time = header.attrs["Time"] + snap_time_cgs = snap_time * unit_time_cgs + time_array_cgs = np.append(time_array_cgs,snap_time_cgs) + coords[:,0] -= box_centre[0]/2. + coords[:,1] -= box_centre[1]/2. + coords[:,2] -= box_centre[2]/2. + radius = np.sqrt(coords[:,0]**2 + coords[:,1]**2 + coords[:,2]**2) + radius_cgs = radius*unit_length_cgs + radius_over_virial_radius = radius_cgs / r_vir_cgs + + r = radius_over_virial_radius + total_potential_energy = np.sum(v_c**2*np.log(r)) + potential_energy_array = np.append(potential_energy_array,total_potential_energy) + + vels_dset = f["PartType0/Velocities"] + vels = np.array(vels_dset) + speed_squared = vels[:,0]**2 + vels[:,1]**2 + vels[:,2]**2 + total_kinetic_energy = 0.5 * np.sum(speed_squared) + kinetic_energy_array = np.append(kinetic_energy_array,total_kinetic_energy) + + u_dset = f["PartType0/InternalEnergy"] + u = np.array(u_dset) + total_internal_energy = np.sum(u) + internal_energy_array = np.append(internal_energy_array,total_internal_energy) + +#put energies in units of v_c^2 and rescale by number of particles + +pe = potential_energy_array / (N*v_c**2) +ke = kinetic_energy_array / (N*v_c**2) +ie = internal_energy_array / (N*v_c**2) +te = pe + ke + ie + +dyn_time_cgs = r_vir_cgs / v_c_cgs +time_array = time_array_cgs / dyn_time_cgs + +plt.plot(time_array,ke,label = "Kinetic Energy") +plt.plot(time_array,pe,label = "Potential Energy") +plt.plot(time_array,ie,label = "Internal Energy") +plt.plot(time_array,te,label = "Total Energy") +plt.legend(loc = "upper right") +plt.xlabel(r"$t / t_{dyn}$") +plt.ylabel(r"$E / v_c^2$") +plt.title(r"$%d \, \, \mathrm{particles} \,,\, v_c = %.1f \, \mathrm{km / s}$" %(N,v_c)) +plt.ylim((-4,2)) +#plot_filename = "density_profile_%03d.png" %i +plt.show() + diff --git a/examples/CoolingHalo/velocity_profile.py b/examples/CoolingHalo/velocity_profile.py new file mode 100644 index 0000000000000000000000000000000000000000..d64d255b18482bc26578f21f46199aa3540ae7b5 --- /dev/null +++ b/examples/CoolingHalo/velocity_profile.py @@ -0,0 +1,111 @@ +import numpy as np +import h5py as h5 +import matplotlib.pyplot as plt +import sys + +def do_binning(x,y,x_bin_edges): + + #x and y are arrays, where y = f(x) + #returns number of elements of x in each bin, and the total of the y elements corresponding to those x values + + n_bins = x_bin_edges.size - 1 + count = np.zeros(n_bins) + y_totals = np.zeros(n_bins) + + for i in range(n_bins): + ind = np.intersect1d(np.where(x > bin_edges[i])[0],np.where(x <= bin_edges[i+1])[0]) + count[i] = ind.size + binned_y = y[ind] + y_totals[i] = np.sum(binned_y) + + return(count,y_totals) + + +#for the plotting +max_r = float(sys.argv[1]) +n_radial_bins = int(sys.argv[2]) +n_snaps = int(sys.argv[3]) + +#some constants +OMEGA = 0.3 # Cosmological matter fraction at z = 0 +PARSEC_IN_CGS = 3.0856776e18 +KM_PER_SEC_IN_CGS = 1.0e5 +CONST_G_CGS = 6.672e-8 +CONST_m_H_CGS = 1.67e-24 +h = 0.67777 # hubble parameter +gamma = 5./3. +eta = 1.2349 +H_0_cgs = 100. * h * KM_PER_SEC_IN_CGS / (1.0e6 * PARSEC_IN_CGS) + +#read some header/parameter information from the first snapshot + +filename = "CoolingHalo_000.hdf5" +f = h5.File(filename,'r') +params = f["Parameters"] +unit_mass_cgs = float(params.attrs["InternalUnitSystem:UnitMass_in_cgs"]) +unit_length_cgs = float(params.attrs["InternalUnitSystem:UnitLength_in_cgs"]) +unit_velocity_cgs = float(params.attrs["InternalUnitSystem:UnitVelocity_in_cgs"]) +unit_time_cgs = unit_length_cgs / unit_velocity_cgs +v_c = float(params.attrs["SoftenedIsothermalPotential:vrot"]) +v_c_cgs = v_c * unit_velocity_cgs +header = f["Header"] +N = header.attrs["NumPart_Total"][0] +box_centre = np.array(header.attrs["BoxSize"]) + +#calculate r_vir and M_vir from v_c +r_vir_cgs = v_c_cgs / (10. * H_0_cgs * np.sqrt(OMEGA)) +M_vir_cgs = r_vir_cgs * v_c_cgs**2 / CONST_G_CGS + +for i in range(n_snaps): + + filename = "CoolingHalo_%03d.hdf5" %i + f = h5.File(filename,'r') + coords_dset = f["PartType0/Coordinates"] + coords = np.array(coords_dset) +#translate coords by centre of box + header = f["Header"] + snap_time = header.attrs["Time"] + snap_time_cgs = snap_time * unit_time_cgs + coords[:,0] -= box_centre[0]/2. + coords[:,1] -= box_centre[1]/2. + coords[:,2] -= box_centre[2]/2. + radius = np.sqrt(coords[:,0]**2 + coords[:,1]**2 + coords[:,2]**2) + radius_cgs = radius*unit_length_cgs + radius_over_virial_radius = radius_cgs / r_vir_cgs + +#get the internal energies + vel_dset = f["PartType0/Velocities"] + vel = np.array(vel_dset) + +#make dimensionless + vel /= v_c + r = radius_over_virial_radius + + #find radial component of velocity + + v_r = np.zeros(r.size) + for j in range(r.size): + v_r[j] = -np.dot(coords[j,:],vel[j,:])/radius[j] + + bin_edges = np.linspace(0,max_r,n_radial_bins + 1) + (hist,v_r_totals) = do_binning(r,v_r,bin_edges) + + bin_widths = bin_edges[1] - bin_edges[0] + radial_bin_mids = np.linspace(bin_widths / 2. , max_r - bin_widths / 2. , n_radial_bins) + binned_v_r = v_r_totals / hist + + #calculate cooling radius + + #r_cool_over_r_vir = np.sqrt((2.*(gamma - 1.)*lambda_cgs*M_vir_cgs*X_H**2)/(4.*np.pi*CONST_m_H_CGS**2*v_c_cgs**2*r_vir_cgs**3))*np.sqrt(snap_time_cgs) + + plt.plot(radial_bin_mids,binned_v_r,'ko',label = "Average radial velocity in shell") + #plt.plot((0,1),(1,1),label = "Analytic Solution") + #plt.plot((r_cool_over_r_vir,r_cool_over_r_vir),(0,2),'r',label = "Cooling radius") + plt.legend(loc = "upper right") + plt.xlabel(r"$r / r_{vir}$") + plt.ylabel(r"$v_r / v_c$") + plt.title(r"$\mathrm{Time}= %.3g \, s \, , \, %d \, \, \mathrm{particles} \,,\, v_c = %.1f \, \mathrm{km / s}$" %(snap_time_cgs,N,v_c)) + plt.ylim((0,2)) + plot_filename = "./plots/radial_velocity_profile/velocity_profile_%03d.png" %i + plt.savefig(plot_filename,format = "png") + plt.close() diff --git a/examples/CoolingHaloWithSpin/README b/examples/CoolingHaloWithSpin/README new file mode 100644 index 0000000000000000000000000000000000000000..53564036ca35dc0c4396a801cc4fa768d41875b5 --- /dev/null +++ b/examples/CoolingHaloWithSpin/README @@ -0,0 +1,29 @@ + +To make the initial conditions we distribute gas particles randomly in +a cube with a side length twice that of the virial radius. The density +profile of the gas is proportional to r^(-2) where r is the distance +from the centre of the cube. + +The parameter v_rot (in makeIC.py and cooling.yml) sets the circular +velocity of the halo, and by extension, the viral radius, viral mass, +and the internal energy of the gas such that hydrostatic equilibrium +is achieved. + +The gas is given some angular momentum about the z-axis. This is +defined by the 'spin_lambda' variable in makeIC.py + +While the system is initially in hydrostatic equilibrium, the cooling +of the gas and the non-zero angular momentum means that the halo will +collapse into a spinning disc. + +To run this example, make such that the code is compiled with either +the isothermal potential or softened isothermal potential, and +'const_lambda' cooling, set in src/const.h. In the latter case, a +(small) value of epsilon needs to be set in cooling.yml. 0.1 kpc +should work well. + +The plotting scripts produce a plot of the density, internal energy +and radial velocity profile for each +snapshot. test_energy_conservation.py shows the evolution of energy +with time. These can be used to check if the example has run properly. + diff --git a/examples/CoolingHaloWithSpin/cooling_halo.yml b/examples/CoolingHaloWithSpin/cooling_halo.yml new file mode 100644 index 0000000000000000000000000000000000000000..684dd11fcf7adc9477d199e599dfb5b76faa91f6 --- /dev/null +++ b/examples/CoolingHaloWithSpin/cooling_halo.yml @@ -0,0 +1,51 @@ +# Define the system of units to use internally. +InternalUnitSystem: + UnitMass_in_cgs: 1.9885e39 # 10^6 solar masses + UnitLength_in_cgs: 3.0856776e21 # Kiloparsecs + UnitVelocity_in_cgs: 1e5 # Kilometres per second + UnitCurrent_in_cgs: 1 # Amperes + UnitTemp_in_cgs: 1 # Kelvin + +# Parameters governing the time integration +TimeIntegration: + time_begin: 0. # The starting time of the simulation (in internal units). + time_end: 10. # The end time of the simulation (in internal units). + dt_min: 1e-7 # The minimal time-step size of the simulation (in internal units). + dt_max: 1e-1 # The maximal time-step size of the simulation (in internal units). + +# Parameters governing the conserved quantities statistics +Statistics: + delta_time: 1e-2 # Time between statistics output + +# Parameters governing the snapshots +Snapshots: + basename: CoolingHalo # Common part of the name of output files + time_first: 0. # Time of the first output (in internal units) + delta_time: 0.1 # Time difference between consecutive outputs (in internal units) + +# Parameters for the hydrodynamics scheme +SPH: + resolution_eta: 1.2349 # Target smoothing length in units of the mean inter-particle separation (1.2349 == 48Ngbs with the cubic spline kernel). + delta_neighbours: 1. # The tolerance for the targetted number of neighbours. + CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. + +# Parameters related to the initial conditions +InitialConditions: + file_name: CoolingHalo.hdf5 # The file to read + +# External potential parameters +SoftenedIsothermalPotential: + position_x: 0. # location of centre of isothermal potential in internal units + position_y: 0. + position_z: 0. + vrot: 200. # rotation speed of isothermal potential in internal units + timestep_mult: 0.03 # controls time step + epsilon: 1.0 #softening for the isothermal potential + +# Cooling parameters +LambdaCooling: + lambda_cgs: 1.0e-22 # Cooling rate (in cgs units) + minimum_temperature: 1.0e4 # Minimal temperature (Kelvin) + mean_molecular_weight: 0.59 # Mean molecular weight + hydrogen_mass_abundance: 0.75 # Hydrogen mass abundance (dimensionless) + cooling_tstep_mult: 0.1 # Dimensionless pre-factor for the time-step condition diff --git a/examples/CoolingHaloWithSpin/density_profile.py b/examples/CoolingHaloWithSpin/density_profile.py new file mode 100644 index 0000000000000000000000000000000000000000..ea282328e5b75530a128eab2dec5f065e46cf819 --- /dev/null +++ b/examples/CoolingHaloWithSpin/density_profile.py @@ -0,0 +1,120 @@ +import numpy as np +import h5py as h5 +import matplotlib.pyplot as plt +import sys + +#for the plotting +max_r = float(sys.argv[1]) #in units of the virial radius +n_radial_bins = int(sys.argv[2]) +n_snaps = int(sys.argv[3]) + +#some constants +OMEGA = 0.3 # Cosmological matter fraction at z = 0 +PARSEC_IN_CGS = 3.0856776e18 +KM_PER_SEC_IN_CGS = 1.0e5 +CONST_G_CGS = 6.672e-8 +CONST_m_H_CGS = 1.67e-24 +h = 0.67777 # hubble parameter +gamma = 5./3. +eta = 1.2349 +H_0_cgs = 100. * h * KM_PER_SEC_IN_CGS / (1.0e6 * PARSEC_IN_CGS) + +#read some header/parameter information from the first snapshot + +filename = "CoolingHalo_000.hdf5" +f = h5.File(filename,'r') +params = f["Parameters"] +unit_mass_cgs = float(params.attrs["InternalUnitSystem:UnitMass_in_cgs"]) +unit_length_cgs = float(params.attrs["InternalUnitSystem:UnitLength_in_cgs"]) +unit_velocity_cgs = float(params.attrs["InternalUnitSystem:UnitVelocity_in_cgs"]) +unit_time_cgs = unit_length_cgs / unit_velocity_cgs +v_c = float(params.attrs["SoftenedIsothermalPotential:vrot"]) +v_c_cgs = v_c * unit_velocity_cgs +lambda_cgs = float(params.attrs["LambdaCooling:lambda_cgs"]) +X_H = float(params.attrs["LambdaCooling:hydrogen_mass_abundance"]) +header = f["Header"] +N = header.attrs["NumPart_Total"][0] +box_centre = np.array(header.attrs["BoxSize"]) + +#calculate r_vir and M_vir from v_c +r_vir_cgs = v_c_cgs / (10. * H_0_cgs * np.sqrt(OMEGA)) +M_vir_cgs = r_vir_cgs * v_c_cgs**2 / CONST_G_CGS + +for i in range(n_snaps): + + filename = "CoolingHalo_%03d.hdf5" %i + f = h5.File(filename,'r') + coords_dset = f["PartType0/Coordinates"] + coords = np.array(coords_dset) +#translate coords by centre of box + header = f["Header"] + snap_time = header.attrs["Time"] + snap_time_cgs = snap_time * unit_time_cgs + coords[:,0] -= box_centre[0]/2. + coords[:,1] -= box_centre[1]/2. + coords[:,2] -= box_centre[2]/2. + radius = np.sqrt(coords[:,0]**2 + coords[:,1]**2 + coords[:,2]**2) + radius_cgs = radius*unit_length_cgs + radius_over_virial_radius = radius_cgs / r_vir_cgs + + r = radius_over_virial_radius + + bin_edges = np.linspace(0.,max_r,n_radial_bins+1) + bin_width = bin_edges[1] - bin_edges[0] + hist = np.histogram(r,bins = bin_edges)[0] # number of particles in each bin + +#find the mass in each radial bin + + mass_dset = f["PartType0/Masses"] +#mass of each particles should be equal + part_mass = np.array(mass_dset)[0] + part_mass_cgs = part_mass * unit_mass_cgs + part_mass_over_virial_mass = part_mass_cgs / M_vir_cgs + + mass_hist = hist * part_mass_over_virial_mass + radial_bin_mids = np.linspace(bin_width/2.,max_r - bin_width/2.,n_radial_bins) +#volume in each radial bin + volume = 4.*np.pi * radial_bin_mids**2 * bin_width + +#now divide hist by the volume so we have a density in each bin + + density = mass_hist / volume + + ##read the densities + + # density_dset = f["PartType0/Density"] + # density = np.array(density_dset) + # density_cgs = density * unit_mass_cgs / unit_length_cgs**3 + # rho = density_cgs * r_vir_cgs**3 / M_vir_cgs + + t = np.linspace(10./n_radial_bins,10.0,1000) + rho_analytic = t**(-2)/(4.*np.pi) + + #calculate cooling radius + + r_cool_over_r_vir = np.sqrt((2.*(gamma - 1.)*lambda_cgs*M_vir_cgs*X_H**2)/(4.*np.pi*CONST_m_H_CGS**2*v_c_cgs**2*r_vir_cgs**3))*np.sqrt(snap_time_cgs) + + #initial analytic density profile + + if (i == 0): + r_0 = radial_bin_mids[0] + rho_0 = density[0] + + rho_analytic_init = rho_0 * (radial_bin_mids/r_0)**(-2) + plt.plot(radial_bin_mids,density/rho_analytic_init,'ko',label = "Average density of shell") + #plt.plot(t,rho_analytic,label = "Initial analytic density profile" + plt.xlabel(r"$r / r_{vir}$") + plt.ylabel(r"$\rho / \rho_{init})$") + plt.title(r"$\mathrm{Time}= %.3g \, s \, , \, %d \, \, \mathrm{particles} \,,\, v_c = %.1f \, \mathrm{km / s}$" %(snap_time_cgs,N,v_c)) + #plt.ylim((1.e-2,1.e1)) + plt.plot((r_cool_over_r_vir,r_cool_over_r_vir),(0,20),'r',label = "Cooling radius") + plt.xlim((radial_bin_mids[0],max_r)) + plt.ylim((0,20)) + plt.plot((0,max_r),(1,1)) + #plt.xscale('log') + #plt.yscale('log') + plt.legend(loc = "upper right") + plot_filename = "density_profile_%03d.png" %i + plt.savefig(plot_filename,format = "png") + plt.close() + diff --git a/examples/CoolingHaloWithSpin/internal_energy_profile.py b/examples/CoolingHaloWithSpin/internal_energy_profile.py new file mode 100644 index 0000000000000000000000000000000000000000..a3e470cc24a939c9bc915371e927d9bd39196bff --- /dev/null +++ b/examples/CoolingHaloWithSpin/internal_energy_profile.py @@ -0,0 +1,111 @@ +import numpy as np +import h5py as h5 +import matplotlib.pyplot as plt +import sys + +def do_binning(x,y,x_bin_edges): + + #x and y are arrays, where y = f(x) + #returns number of elements of x in each bin, and the total of the y elements corresponding to those x values + + n_bins = x_bin_edges.size - 1 + count = np.zeros(n_bins) + y_totals = np.zeros(n_bins) + + for i in range(n_bins): + ind = np.intersect1d(np.where(x > bin_edges[i])[0],np.where(x <= bin_edges[i+1])[0]) + count[i] = ind.size + binned_y = y[ind] + y_totals[i] = np.sum(binned_y) + + return(count,y_totals) + + +#for the plotting +max_r = float(sys.argv[1]) +n_radial_bins = int(sys.argv[2]) +n_snaps = int(sys.argv[3]) + +#some constants +OMEGA = 0.3 # Cosmological matter fraction at z = 0 +PARSEC_IN_CGS = 3.0856776e18 +KM_PER_SEC_IN_CGS = 1.0e5 +CONST_G_CGS = 6.672e-8 +CONST_m_H_CGS = 1.67e-24 +h = 0.67777 # hubble parameter +gamma = 5./3. +eta = 1.2349 +H_0_cgs = 100. * h * KM_PER_SEC_IN_CGS / (1.0e6 * PARSEC_IN_CGS) + +#read some header/parameter information from the first snapshot + +filename = "CoolingHalo_000.hdf5" +f = h5.File(filename,'r') +params = f["Parameters"] +unit_mass_cgs = float(params.attrs["InternalUnitSystem:UnitMass_in_cgs"]) +unit_length_cgs = float(params.attrs["InternalUnitSystem:UnitLength_in_cgs"]) +unit_velocity_cgs = float(params.attrs["InternalUnitSystem:UnitVelocity_in_cgs"]) +unit_time_cgs = unit_length_cgs / unit_velocity_cgs +v_c = float(params.attrs["SoftenedIsothermalPotential:vrot"]) +v_c_cgs = v_c * unit_velocity_cgs +lambda_cgs = float(params.attrs["LambdaCooling:lambda_cgs"]) +X_H = float(params.attrs["LambdaCooling:hydrogen_mass_abundance"]) +header = f["Header"] +N = header.attrs["NumPart_Total"][0] +box_centre = np.array(header.attrs["BoxSize"]) + +#calculate r_vir and M_vir from v_c +r_vir_cgs = v_c_cgs / (10. * H_0_cgs * np.sqrt(OMEGA)) +M_vir_cgs = r_vir_cgs * v_c_cgs**2 / CONST_G_CGS + +for i in range(n_snaps): + + filename = "CoolingHalo_%03d.hdf5" %i + f = h5.File(filename,'r') + coords_dset = f["PartType0/Coordinates"] + coords = np.array(coords_dset) +#translate coords by centre of box + header = f["Header"] + snap_time = header.attrs["Time"] + snap_time_cgs = snap_time * unit_time_cgs + coords[:,0] -= box_centre[0]/2. + coords[:,1] -= box_centre[1]/2. + coords[:,2] -= box_centre[2]/2. + radius = np.sqrt(coords[:,0]**2 + coords[:,1]**2 + coords[:,2]**2) + radius_cgs = radius*unit_length_cgs + radius_over_virial_radius = radius_cgs / r_vir_cgs + +#get the internal energies + u_dset = f["PartType0/InternalEnergy"] + u = np.array(u_dset) + +#make dimensionless + u /= v_c**2/(2. * (gamma - 1.)) + r = radius_over_virial_radius + + bin_edges = np.linspace(0,max_r,n_radial_bins + 1) + (hist,u_totals) = do_binning(r,u,bin_edges) + + bin_widths = bin_edges[1] - bin_edges[0] + radial_bin_mids = np.linspace(bin_widths / 2. , max_r - bin_widths / 2. , n_radial_bins) + binned_u = u_totals / hist + + #calculate cooling radius + + r_cool_over_r_vir = np.sqrt((2.*(gamma - 1.)*lambda_cgs*M_vir_cgs*X_H**2)/(4.*np.pi*CONST_m_H_CGS**2*v_c_cgs**2*r_vir_cgs**3))*np.sqrt(snap_time_cgs) + + plt.plot(radial_bin_mids,binned_u,'ko',label = "Numerical solution") + #plt.plot((0,1),(1,1),label = "Analytic Solution") + plt.plot((r_cool_over_r_vir,r_cool_over_r_vir),(0,2),'r',label = "Cooling radius") + plt.legend(loc = "lower right") + plt.xlabel(r"$r / r_{vir}$") + plt.ylabel(r"$u / (v_c^2 / (2(\gamma - 1)) $") + plt.title(r"$\mathrm{Time}= %.3g \, s \, , \, %d \, \, \mathrm{particles} \,,\, v_c = %.1f \, \mathrm{km / s}$" %(snap_time_cgs,N,v_c)) + plt.ylim((0,2)) + plot_filename = "internal_energy_profile_%03d.png" %i + plt.savefig(plot_filename,format = "png") + plt.close() + + + + diff --git a/examples/CoolingHaloWithSpin/makeIC.py b/examples/CoolingHaloWithSpin/makeIC.py new file mode 100644 index 0000000000000000000000000000000000000000..8970fbaa70578532a4f41bab7a096d8fa3565d26 --- /dev/null +++ b/examples/CoolingHaloWithSpin/makeIC.py @@ -0,0 +1,238 @@ +############################################################################### + # This file is part of SWIFT. + # Copyright (c) 2016 Stefan Arridge (stefan.arridge@durham.ac.uk) + # + # This program is free software: you can redistribute it and/or modify + # it under the terms of the GNU Lesser General Public License as published + # by the Free Software Foundation, either version 3 of the License, or + # (at your option) any later version. + # + # This program is distributed in the hope that it will be useful, + # but WITHOUT ANY WARRANTY; without even the implied warranty of + # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + # GNU General Public License for more details. + # + # You should have received a copy of the GNU Lesser General Public License + # along with this program. If not, see <http://www.gnu.org/licenses/>. + # + ############################################################################## + +import h5py +import sys +import numpy as np +import math +import random + +# Generates N particles in a spherically symmetric distribution with density profile ~r^(-2) +# usage: python makeIC.py 1000: generate 1000 particles + +# Some constants + +OMEGA = 0.3 # Cosmological matter fraction at z = 0 +PARSEC_IN_CGS = 3.0856776e18 +KM_PER_SEC_IN_CGS = 1.0e5 +CONST_G_CGS = 6.672e-8 +h = 0.67777 # hubble parameter +gamma = 5./3. +eta = 1.2349 +spin_lambda = 0.05 #spin parameter + +# First set unit velocity and then the circular velocity parameter for the isothermal potential +const_unit_velocity_in_cgs = 1.e5 #kms^-1 + +v_c = 200. +v_c_cgs = v_c * const_unit_velocity_in_cgs + +# Now we use this to get the virial mass and virial radius, which we will set to be the unit mass and radius + +# Find H_0, the inverse Hubble time, in cgs + +H_0_cgs = 100. * h * KM_PER_SEC_IN_CGS / (1.0e6 * PARSEC_IN_CGS) + +# From this we can find the virial radius, the radius within which the average density of the halo is +# 200. * the mean matter density + +r_vir_cgs = v_c_cgs / (10. * H_0_cgs * np.sqrt(OMEGA)) + +# Now get the virial mass + +M_vir_cgs = r_vir_cgs * v_c_cgs**2 / CONST_G_CGS + +# Now set the unit length and mass + +const_unit_mass_in_cgs = M_vir_cgs +const_unit_length_in_cgs = r_vir_cgs + +print "UnitMass_in_cgs: ", const_unit_mass_in_cgs +print "UnitLength_in_cgs: ", const_unit_length_in_cgs +print "UnitVelocity_in_cgs: ", const_unit_velocity_in_cgs + +#derived quantities +const_unit_time_in_cgs = (const_unit_length_in_cgs / const_unit_velocity_in_cgs) +print "UnitTime_in_cgs: ", const_unit_time_in_cgs +const_G = ((CONST_G_CGS*const_unit_mass_in_cgs*const_unit_time_in_cgs*const_unit_time_in_cgs/(const_unit_length_in_cgs*const_unit_length_in_cgs*const_unit_length_in_cgs))) +print 'G=', const_G + +# Parameters +periodic= 1 # 1 For periodic box +boxSize = 4. +G = const_G +N = int(sys.argv[1]) # Number of particles + +# Create the file +filename = "CoolingHalo.hdf5" +file = h5py.File(filename, 'w') + +#Units +grp = file.create_group("/Units") +grp.attrs["Unit length in cgs (U_L)"] = const_unit_length_in_cgs +grp.attrs["Unit mass in cgs (U_M)"] = const_unit_mass_in_cgs +grp.attrs["Unit time in cgs (U_t)"] = const_unit_length_in_cgs / const_unit_velocity_in_cgs +grp.attrs["Unit current in cgs (U_I)"] = 1. +grp.attrs["Unit temperature in cgs (U_T)"] = 1. + + +# Runtime parameters +grp = file.create_group("/RuntimePars") +grp.attrs["PeriodicBoundariesOn"] = periodic + +# set seed for random number +np.random.seed(1234) + + +# Positions +# r^(-2) distribution corresponds to uniform distribution in radius +radius = boxSize * np.sqrt(3.) / 2.* np.random.rand(N) #the diagonal extent of the cube +ctheta = -1. + 2 * np.random.rand(N) +stheta = np.sqrt(1.-ctheta**2) +phi = 2 * math.pi * np.random.rand(N) +coords = np.zeros((N, 3)) +coords[:,0] = radius * stheta * np.cos(phi) +coords[:,1] = radius * stheta * np.sin(phi) +coords[:,2] = radius * ctheta + +#shift to centre of box +coords += np.full((N,3),boxSize/2.) +print "x range = (%f,%f)" %(np.min(coords[:,0]),np.max(coords[:,0])) +print "y range = (%f,%f)" %(np.min(coords[:,1]),np.max(coords[:,1])) +print "z range = (%f,%f)" %(np.min(coords[:,2]),np.max(coords[:,2])) + +print np.mean(coords[:,0]) +print np.mean(coords[:,1]) +print np.mean(coords[:,2]) + +#now find the particles which are within the box + +x_coords = coords[:,0] +y_coords = coords[:,1] +z_coords = coords[:,2] + +ind = np.where(x_coords < boxSize)[0] +x_coords = x_coords[ind] +y_coords = y_coords[ind] +z_coords = z_coords[ind] + +ind = np.where(x_coords > 0.)[0] +x_coords = x_coords[ind] +y_coords = y_coords[ind] +z_coords = z_coords[ind] + +ind = np.where(y_coords < boxSize)[0] +x_coords = x_coords[ind] +y_coords = y_coords[ind] +z_coords = z_coords[ind] + +ind = np.where(y_coords > 0.)[0] +x_coords = x_coords[ind] +y_coords = y_coords[ind] +z_coords = z_coords[ind] + +ind = np.where(z_coords < boxSize)[0] +x_coords = x_coords[ind] +y_coords = y_coords[ind] +z_coords = z_coords[ind] + +ind = np.where(z_coords > 0.)[0] +x_coords = x_coords[ind] +y_coords = y_coords[ind] +z_coords = z_coords[ind] + +#count number of particles + +N = x_coords.size + +print "Number of particles in the box = " , N + +#make the coords and radius arrays again +coords_2 = np.zeros((N,3)) +coords_2[:,0] = x_coords +coords_2[:,1] = y_coords +coords_2[:,2] = z_coords + +radius = np.sqrt((coords_2[:,0]-boxSize/2.)**2 + (coords_2[:,1]-boxSize/2.)**2 + (coords_2[:,2]-boxSize/2.)**2) + +#now give particle's velocities +v = np.zeros((N,3)) + +#first work out total angular momentum of the halo within the virial radius +#we work in units where r_vir = 1 and M_vir = 1 +Total_E = v_c**2 / 2.0 +J = spin_lambda * const_G / np.sqrt(Total_E) +print "J =", J +#all particles within the virial radius have omega parallel to the z-axis, magnitude +#is proportional to 1 over the radius +omega = np.zeros((N,3)) +for i in range(N): + omega[i,2] = 3.*J / radius[i] + v[i,:] = np.cross(omega[i,:],(coords_2[i,:]-boxSize/2.)) + +# Header +grp = file.create_group("/Header") +grp.attrs["BoxSize"] = boxSize +grp.attrs["NumPart_Total"] = [N ,0, 0, 0, 0, 0] +grp.attrs["NumPart_Total_HighWord"] = [0, 0, 0, 0, 0, 0] +grp.attrs["NumPart_ThisFile"] = [N, 0, 0, 0, 0, 0] +grp.attrs["Time"] = 0.0 +grp.attrs["NumFilesPerSnapshot"] = 1 +grp.attrs["MassTable"] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] +grp.attrs["Flag_Entropy_ICs"] = [0, 0, 0, 0, 0, 0] +grp.attrs["Dimension"] = 3 + +# Particle group +grp = file.create_group("/PartType0") + +ds = grp.create_dataset('Coordinates', (N, 3), 'd') +ds[()] = coords_2 +coords_2 = np.zeros(1) + +ds = grp.create_dataset('Velocities', (N, 3), 'f') +ds[()] = v +v = np.zeros(1) + +# All particles of equal mass +mass = 1. / N +m = np.full((N,),mass) +ds = grp.create_dataset('Masses', (N, ), 'f') +ds[()] = m +m = np.zeros(1) + +# Smoothing lengths +l = (4. * np.pi * radius**2 / N)**(1./3.) #local mean inter-particle separation +h = np.full((N, ), eta * l) +ds = grp.create_dataset('SmoothingLength', (N,), 'f') +ds[()] = h +h = np.zeros(1) + +# Internal energies +u = v_c**2 / (2. * (gamma - 1.)) +u = np.full((N, ), u) +ds = grp.create_dataset('InternalEnergy', (N,), 'f') +ds[()] = u +u = np.zeros(1) + +# Particle IDs +ids = 1 + np.linspace(0, N, N, endpoint=False, dtype='L') +ds = grp.create_dataset('ParticleIDs', (N, ), 'L') +ds[()] = ids + +file.close() diff --git a/examples/CoolingHaloWithSpin/makeIC_random_box.py b/examples/CoolingHaloWithSpin/makeIC_random_box.py new file mode 100644 index 0000000000000000000000000000000000000000..4295cb135233f2d5a59405b44e6d8e9c80a1f6c0 --- /dev/null +++ b/examples/CoolingHaloWithSpin/makeIC_random_box.py @@ -0,0 +1,168 @@ +############################################################################### + # This file is part of SWIFT. + # Copyright (c) 2016 Stefan Arridge (stefan.arridge@durham.ac.uk) + # + # This program is free software: you can redistribute it and/or modify + # it under the terms of the GNU Lesser General Public License as published + # by the Free Software Foundation, either version 3 of the License, or + # (at your option) any later version. + # + # This program is distributed in the hope that it will be useful, + # but WITHOUT ANY WARRANTY; without even the implied warranty of + # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + # GNU General Public License for more details. + # + # You should have received a copy of the GNU Lesser General Public License + # along with this program. If not, see <http://www.gnu.org/licenses/>. + # + ############################################################################## + +import h5py +import sys +import numpy as np +import math +import random + +# Generates N particles in a spherically symmetric distribution with density profile ~r^(-2) +# usage: python makeIC.py 1000: generate 1000 particles + +# Some constants + +OMEGA = 0.3 # Cosmological matter fraction at z = 0 +PARSEC_IN_CGS = 3.0856776e18 +KM_PER_SEC_IN_CGS = 1.0e5 +CONST_G_CGS = 6.672e-8 +h = 0.67777 # hubble parameter +gamma = 5./3. +eta = 1.2349 + +# First set unit velocity and then the circular velocity parameter for the isothermal potential +const_unit_velocity_in_cgs = 1.e5 #kms^-1 + +v_c = 200. +v_c_cgs = v_c * const_unit_velocity_in_cgs + +# Now we use this to get the virial mass and virial radius, which we will set to be the unit mass and radius + +# Find H_0, the inverse Hubble time, in cgs + +H_0_cgs = 100. * h * KM_PER_SEC_IN_CGS / (1.0e6 * PARSEC_IN_CGS) + +# From this we can find the virial radius, the radius within which the average density of the halo is +# 200. * the mean matter density + +r_vir_cgs = v_c_cgs / (10. * H_0_cgs * np.sqrt(OMEGA)) + +# Now get the virial mass + +M_vir_cgs = r_vir_cgs * v_c_cgs**2 / CONST_G_CGS + +# Now set the unit length and mass + +const_unit_mass_in_cgs = M_vir_cgs +const_unit_length_in_cgs = r_vir_cgs + +print "UnitMass_in_cgs: ", const_unit_mass_in_cgs +print "UnitLength_in_cgs: ", const_unit_length_in_cgs +print "UnitVelocity_in_cgs: ", const_unit_velocity_in_cgs + +#derived quantities +const_unit_time_in_cgs = (const_unit_length_in_cgs / const_unit_velocity_in_cgs) +print "UnitTime_in_cgs: ", const_unit_time_in_cgs +const_G = ((CONST_G_CGS*const_unit_mass_in_cgs*const_unit_time_in_cgs*const_unit_time_in_cgs/(const_unit_length_in_cgs*const_unit_length_in_cgs*const_unit_length_in_cgs))) +print 'G=', const_G + +# Parameters +periodic= 1 # 1 For periodic box +boxSize = 4. +G = const_G +N = int(sys.argv[1]) # Number of particles + +# Create the file +filename = "random_box.hdf5" +file = h5py.File(filename, 'w') + +#Units +grp = file.create_group("/Units") +grp.attrs["Unit length in cgs (U_L)"] = const_unit_length_in_cgs +grp.attrs["Unit mass in cgs (U_M)"] = const_unit_mass_in_cgs +grp.attrs["Unit time in cgs (U_t)"] = const_unit_length_in_cgs / const_unit_velocity_in_cgs +grp.attrs["Unit current in cgs (U_I)"] = 1. +grp.attrs["Unit temperature in cgs (U_T)"] = 1. + +# Header +grp = file.create_group("/Header") +grp.attrs["BoxSize"] = boxSize +grp.attrs["NumPart_Total"] = [N ,0, 0, 0, 0, 0] +grp.attrs["NumPart_Total_HighWord"] = [0, 0, 0, 0, 0, 0] +grp.attrs["NumPart_ThisFile"] = [N, 0, 0, 0, 0, 0] +grp.attrs["Time"] = 0.0 +grp.attrs["NumFilesPerSnapshot"] = 1 +grp.attrs["MassTable"] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] +grp.attrs["Flag_Entropy_ICs"] = [0, 0, 0, 0, 0, 0] +grp.attrs["Dimension"] = 3 + +# Runtime parameters +grp = file.create_group("/RuntimePars") +grp.attrs["PeriodicBoundariesOn"] = periodic + +# set seed for random number +np.random.seed(1234) + +# Particle group +grp = file.create_group("/PartType0") + +# Positions + +# distribute particles randomly in the box +coords = np.zeros((N, 3)) +coords[:,0] = boxSize * np.random.rand(N) +coords[:,1] = boxSize * np.random.rand(N) +coords[:,2] = boxSize * np.random.rand(N) +#shift to centre of box +#coords += np.full((N,3),boxSize/2.) +print "x range = (%f,%f)" %(np.min(coords[:,0]),np.max(coords[:,0])) +print "y range = (%f,%f)" %(np.min(coords[:,1]),np.max(coords[:,1])) +print "z range = (%f,%f)" %(np.min(coords[:,2]),np.max(coords[:,2])) + +print np.mean(coords[:,0]) +print np.mean(coords[:,1]) +print np.mean(coords[:,2]) + +ds = grp.create_dataset('Coordinates', (N, 3), 'd') +ds[()] = coords +coords = np.zeros(1) + +# All velocities set to zero +v = np.zeros((N,3)) +ds = grp.create_dataset('Velocities', (N, 3), 'f') +ds[()] = v +v = np.zeros(1) + +# All particles of equal mass +mass = 1. / N +m = np.full((N,),mass) +ds = grp.create_dataset('Masses', (N, ), 'f') +ds[()] = m +m = np.zeros(1) + +# Smoothing lengths +l = (boxSize**3 / N)**(1./3.) #local mean inter-particle separation +h = np.full((N, ), eta * l) +ds = grp.create_dataset('SmoothingLength', (N,), 'f') +ds[()] = h +h = np.zeros(1) + +# Internal energies +u = v_c**2 / (2. * (gamma - 1.)) +u = np.full((N, ), u) +ds = grp.create_dataset('InternalEnergy', (N,), 'f') +ds[()] = u +u = np.zeros(1) + +# Particle IDs +ids = 1 + np.linspace(0, N, N, endpoint=False, dtype='L') +ds = grp.create_dataset('ParticleIDs', (N, ), 'L') +ds[()] = ids + +file.close() diff --git a/examples/CoolingHaloWithSpin/run.sh b/examples/CoolingHaloWithSpin/run.sh new file mode 100755 index 0000000000000000000000000000000000000000..3a0d9c02000e760b030a96107038d3c6163f3227 --- /dev/null +++ b/examples/CoolingHaloWithSpin/run.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +# Generate the initial conditions if they are not present. +echo "Generating initial conditions for the isothermal potential box example..." +python makeIC.py 10000 + +../swift -g -s -C -t 16 cooling_halo.yml 2>&1 | tee output.log + +# python radial_profile.py 10 + +# python internal_energy_profile.py 10 + +# python test_energy_conservation.py diff --git a/examples/CoolingHaloWithSpin/test_energy_conservation.py b/examples/CoolingHaloWithSpin/test_energy_conservation.py new file mode 100644 index 0000000000000000000000000000000000000000..42a049f30ac1928b89bfff355ee6ff7c8185bbb7 --- /dev/null +++ b/examples/CoolingHaloWithSpin/test_energy_conservation.py @@ -0,0 +1,114 @@ +import numpy as np +import h5py as h5 +import matplotlib.pyplot as plt +import sys + +n_snaps = 101 + +#some constants +OMEGA = 0.3 # Cosmological matter fraction at z = 0 +PARSEC_IN_CGS = 3.0856776e18 +KM_PER_SEC_IN_CGS = 1.0e5 +CONST_G_CGS = 6.672e-8 +h = 0.67777 # hubble parameter +gamma = 5./3. +eta = 1.2349 +H_0_cgs = 100. * h * KM_PER_SEC_IN_CGS / (1.0e6 * PARSEC_IN_CGS) + +#read some header/parameter information from the first snapshot + +filename = "CoolingHalo_000.hdf5" +f = h5.File(filename,'r') +params = f["Parameters"] +unit_mass_cgs = float(params.attrs["InternalUnitSystem:UnitMass_in_cgs"]) +unit_length_cgs = float(params.attrs["InternalUnitSystem:UnitLength_in_cgs"]) +unit_velocity_cgs = float(params.attrs["InternalUnitSystem:UnitVelocity_in_cgs"]) +unit_time_cgs = unit_length_cgs / unit_velocity_cgs +v_c = float(params.attrs["SoftenedIsothermalPotential:vrot"]) +v_c_cgs = v_c * unit_velocity_cgs +header = f["Header"] +N = header.attrs["NumPart_Total"][0] +box_centre = np.array(header.attrs["BoxSize"]) + +#calculate r_vir and M_vir from v_c +r_vir_cgs = v_c_cgs / (10. * H_0_cgs * np.sqrt(OMEGA)) +M_vir_cgs = r_vir_cgs * v_c_cgs**2 / CONST_G_CGS + +potential_energy_array = [] +internal_energy_array = [] +kinetic_energy_array = [] +time_array_cgs = [] + +for i in range(n_snaps): + + filename = "CoolingHalo_%03d.hdf5" %i + f = h5.File(filename,'r') + coords_dset = f["PartType0/Coordinates"] + coords = np.array(coords_dset) +#translate coords by centre of box + header = f["Header"] + snap_time = header.attrs["Time"] + snap_time_cgs = snap_time * unit_time_cgs + time_array_cgs = np.append(time_array_cgs,snap_time_cgs) + coords[:,0] -= box_centre[0]/2. + coords[:,1] -= box_centre[1]/2. + coords[:,2] -= box_centre[2]/2. + radius = np.sqrt(coords[:,0]**2 + coords[:,1]**2 + coords[:,2]**2) + radius_cgs = radius*unit_length_cgs + radius_over_virial_radius = radius_cgs / r_vir_cgs + + r = radius_over_virial_radius + total_potential_energy = np.sum(v_c**2*np.log(r)) + potential_energy_array = np.append(potential_energy_array,total_potential_energy) + + vels_dset = f["PartType0/Velocities"] + vels = np.array(vels_dset) + speed_squared = vels[:,0]**2 + vels[:,1]**2 + vels[:,2]**2 + total_kinetic_energy = 0.5 * np.sum(speed_squared) + kinetic_energy_array = np.append(kinetic_energy_array,total_kinetic_energy) + + u_dset = f["PartType0/InternalEnergy"] + u = np.array(u_dset) + total_internal_energy = np.sum(u) + internal_energy_array = np.append(internal_energy_array,total_internal_energy) + +#get the radiated energy + +energy_array = np.genfromtxt("energy.txt",skip_header = 1) +#rad_energy_time = energy_array[:,0] +#rad_energy_time_cgs = rad_energy_time * unit_time_cgs +rad_energy_array = energy_array[:,6] + +#only use every 10th term in the rad_energy_array +rad_energy_array = rad_energy_array[0::10] + +#put energies in units of v_c^2 and rescale by number of particles + +pe = potential_energy_array / (N*v_c**2) +ke = kinetic_energy_array / (N*v_c**2) +ie = internal_energy_array / (N*v_c**2) +re = rad_energy_array / (N*v_c**2) +te = pe + ke + ie #+ re + +print pe +print ke +print ie +#print re +print te + +dyn_time_cgs = r_vir_cgs / v_c_cgs +time_array = time_array_cgs / dyn_time_cgs +#rad_time_array = rad_energy_time_cgs / dyn_time_cgs +plt.plot(time_array,ke,label = "Kinetic Energy") +plt.plot(time_array,pe,label = "Potential Energy") +plt.plot(time_array,ie,label = "Internal Energy") +#plt.plot(time_array,re,label = "Radiated Energy") +plt.plot(time_array,te,label = "Total Energy") +plt.legend(loc = "lower left") +plt.xlabel(r"$t / t_{dyn}$") +plt.ylabel(r"$E / v_c^2$") +plt.title(r"$%d \, \, \mathrm{particles} \,,\, v_c = %.1f \, \mathrm{km / s}$" %(N,v_c)) +#plt.ylim((-4,2)) +#plot_filename = "density_profile_%03d.png" %i +plt.show() + diff --git a/examples/CoolingHaloWithSpin/velocity_profile.py b/examples/CoolingHaloWithSpin/velocity_profile.py new file mode 100644 index 0000000000000000000000000000000000000000..d64d255b18482bc26578f21f46199aa3540ae7b5 --- /dev/null +++ b/examples/CoolingHaloWithSpin/velocity_profile.py @@ -0,0 +1,111 @@ +import numpy as np +import h5py as h5 +import matplotlib.pyplot as plt +import sys + +def do_binning(x,y,x_bin_edges): + + #x and y are arrays, where y = f(x) + #returns number of elements of x in each bin, and the total of the y elements corresponding to those x values + + n_bins = x_bin_edges.size - 1 + count = np.zeros(n_bins) + y_totals = np.zeros(n_bins) + + for i in range(n_bins): + ind = np.intersect1d(np.where(x > bin_edges[i])[0],np.where(x <= bin_edges[i+1])[0]) + count[i] = ind.size + binned_y = y[ind] + y_totals[i] = np.sum(binned_y) + + return(count,y_totals) + + +#for the plotting +max_r = float(sys.argv[1]) +n_radial_bins = int(sys.argv[2]) +n_snaps = int(sys.argv[3]) + +#some constants +OMEGA = 0.3 # Cosmological matter fraction at z = 0 +PARSEC_IN_CGS = 3.0856776e18 +KM_PER_SEC_IN_CGS = 1.0e5 +CONST_G_CGS = 6.672e-8 +CONST_m_H_CGS = 1.67e-24 +h = 0.67777 # hubble parameter +gamma = 5./3. +eta = 1.2349 +H_0_cgs = 100. * h * KM_PER_SEC_IN_CGS / (1.0e6 * PARSEC_IN_CGS) + +#read some header/parameter information from the first snapshot + +filename = "CoolingHalo_000.hdf5" +f = h5.File(filename,'r') +params = f["Parameters"] +unit_mass_cgs = float(params.attrs["InternalUnitSystem:UnitMass_in_cgs"]) +unit_length_cgs = float(params.attrs["InternalUnitSystem:UnitLength_in_cgs"]) +unit_velocity_cgs = float(params.attrs["InternalUnitSystem:UnitVelocity_in_cgs"]) +unit_time_cgs = unit_length_cgs / unit_velocity_cgs +v_c = float(params.attrs["SoftenedIsothermalPotential:vrot"]) +v_c_cgs = v_c * unit_velocity_cgs +header = f["Header"] +N = header.attrs["NumPart_Total"][0] +box_centre = np.array(header.attrs["BoxSize"]) + +#calculate r_vir and M_vir from v_c +r_vir_cgs = v_c_cgs / (10. * H_0_cgs * np.sqrt(OMEGA)) +M_vir_cgs = r_vir_cgs * v_c_cgs**2 / CONST_G_CGS + +for i in range(n_snaps): + + filename = "CoolingHalo_%03d.hdf5" %i + f = h5.File(filename,'r') + coords_dset = f["PartType0/Coordinates"] + coords = np.array(coords_dset) +#translate coords by centre of box + header = f["Header"] + snap_time = header.attrs["Time"] + snap_time_cgs = snap_time * unit_time_cgs + coords[:,0] -= box_centre[0]/2. + coords[:,1] -= box_centre[1]/2. + coords[:,2] -= box_centre[2]/2. + radius = np.sqrt(coords[:,0]**2 + coords[:,1]**2 + coords[:,2]**2) + radius_cgs = radius*unit_length_cgs + radius_over_virial_radius = radius_cgs / r_vir_cgs + +#get the internal energies + vel_dset = f["PartType0/Velocities"] + vel = np.array(vel_dset) + +#make dimensionless + vel /= v_c + r = radius_over_virial_radius + + #find radial component of velocity + + v_r = np.zeros(r.size) + for j in range(r.size): + v_r[j] = -np.dot(coords[j,:],vel[j,:])/radius[j] + + bin_edges = np.linspace(0,max_r,n_radial_bins + 1) + (hist,v_r_totals) = do_binning(r,v_r,bin_edges) + + bin_widths = bin_edges[1] - bin_edges[0] + radial_bin_mids = np.linspace(bin_widths / 2. , max_r - bin_widths / 2. , n_radial_bins) + binned_v_r = v_r_totals / hist + + #calculate cooling radius + + #r_cool_over_r_vir = np.sqrt((2.*(gamma - 1.)*lambda_cgs*M_vir_cgs*X_H**2)/(4.*np.pi*CONST_m_H_CGS**2*v_c_cgs**2*r_vir_cgs**3))*np.sqrt(snap_time_cgs) + + plt.plot(radial_bin_mids,binned_v_r,'ko',label = "Average radial velocity in shell") + #plt.plot((0,1),(1,1),label = "Analytic Solution") + #plt.plot((r_cool_over_r_vir,r_cool_over_r_vir),(0,2),'r',label = "Cooling radius") + plt.legend(loc = "upper right") + plt.xlabel(r"$r / r_{vir}$") + plt.ylabel(r"$v_r / v_c$") + plt.title(r"$\mathrm{Time}= %.3g \, s \, , \, %d \, \, \mathrm{particles} \,,\, v_c = %.1f \, \mathrm{km / s}$" %(snap_time_cgs,N,v_c)) + plt.ylim((0,2)) + plot_filename = "./plots/radial_velocity_profile/velocity_profile_%03d.png" %i + plt.savefig(plot_filename,format = "png") + plt.close() diff --git a/examples/CosmoVolume/cosmoVolume.yml b/examples/CosmoVolume/cosmoVolume.yml index 13cea318144d296183d630a53d78c69d050c1abe..46189bf25f26d46cbd1e5321b00298cd5553eb59 100644 --- a/examples/CosmoVolume/cosmoVolume.yml +++ b/examples/CosmoVolume/cosmoVolume.yml @@ -27,7 +27,6 @@ Statistics: SPH: resolution_eta: 1.2348 # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel). delta_neighbours: 0.1 # The tolerance for the targetted number of neighbours. - max_smoothing_length: 0.705 # Maximal smoothing length allowed (in internal units). CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. # Parameters related to the initial conditions diff --git a/examples/EAGLE_12/eagle_12.yml b/examples/EAGLE_12/eagle_12.yml index 80714d87f4afa7d7e4d41ce7bf56faed856208ef..bb5f97f029e1d50d81bbdccae9ac620e9e0e6f08 100644 --- a/examples/EAGLE_12/eagle_12.yml +++ b/examples/EAGLE_12/eagle_12.yml @@ -27,7 +27,6 @@ Statistics: SPH: resolution_eta: 1.2348 # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel). delta_neighbours: 0.1 # The tolerance for the targetted number of neighbours. - max_smoothing_length: 0.1 # Maximal smoothing length allowed (in internal units). CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. # Parameters related to the initial conditions diff --git a/examples/EAGLE_25/eagle_25.yml b/examples/EAGLE_25/eagle_25.yml index 6afb737677040ba0605d4e3116800f079a059be4..12a413b7e2c45443601c0b9753383b90942298b0 100644 --- a/examples/EAGLE_25/eagle_25.yml +++ b/examples/EAGLE_25/eagle_25.yml @@ -27,7 +27,6 @@ Statistics: SPH: resolution_eta: 1.2348 # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel). delta_neighbours: 0.1 # The tolerance for the targetted number of neighbours. - max_smoothing_length: 0.1 # Maximal smoothing length allowed (in internal units). CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. # Parameters related to the initial conditions diff --git a/examples/EAGLE_50/eagle_50.yml b/examples/EAGLE_50/eagle_50.yml index d9e5d46326780fe5b2abde025b50a7ec667b19b1..b84b1eb7c362f85d8cd6a08ff2a15f72d1337396 100644 --- a/examples/EAGLE_50/eagle_50.yml +++ b/examples/EAGLE_50/eagle_50.yml @@ -27,7 +27,6 @@ Statistics: SPH: resolution_eta: 1.2348 # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel). delta_neighbours: 0.1 # The tolerance for the targetted number of neighbours. - max_smoothing_length: 0.1 # Maximal smoothing length allowed (in internal units). CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. # Parameters related to the initial conditions diff --git a/examples/ExternalPointMass/externalPointMass.yml b/examples/ExternalPointMass/externalPointMass.yml index ce300b32157361e7860d201c186823471a179c0a..621a66bbc39838ac8d3d8a8a3992b2a7be3157a8 100644 --- a/examples/ExternalPointMass/externalPointMass.yml +++ b/examples/ExternalPointMass/externalPointMass.yml @@ -27,7 +27,6 @@ Statistics: SPH: resolution_eta: 1.2348 # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel). delta_neighbours: 0.1 # The tolerance for the targetted number of neighbours. - max_smoothing_length: 10. # Maximal smoothing length allowed (in internal units). CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. # Parameters related to the initial conditions diff --git a/examples/Feedback/feedback.yml b/examples/Feedback/feedback.yml index 9ff7eea325b43fe3c670d16bdbd4ccc66f33333e..de4f7abef1ef538a97a5e38c72b4db5ce2647976 100644 --- a/examples/Feedback/feedback.yml +++ b/examples/Feedback/feedback.yml @@ -27,7 +27,6 @@ Statistics: SPH: resolution_eta: 1.2348 # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel). delta_neighbours: 0.1 # The tolerance for the targetted number of neighbours. - max_smoothing_length: 0.1 # Maximal smoothing length allowed (in internal units). CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. # Parameters related to the initial conditions @@ -37,8 +36,8 @@ InitialConditions: # Parameters for feedback SN: - time: 0.001 # time the SN explodes (internal units) - energy: 1.0 # energy of the explosion (internal units) - x: 0.5 # x-position of explostion (internal units) - y: 0.5 # y-position of explostion (internal units) - z: 0.5 # z-position of explostion (internal units) + time: 0.001 # time the SN explodes (internal units) + energy: 1.0 # energy of the explosion (internal units) + x: 0.5 # x-position of explostion (internal units) + y: 0.5 # y-position of explostion (internal units) + z: 0.5 # z-position of explostion (internal units) diff --git a/examples/Gradients/gradientsCartesian.yml b/examples/Gradients/gradientsCartesian.yml index 917a4803004c2ce89984beb857cb1691d9a1ec1b..61192e52393d88501408ac3982afeff2dc58f727 100644 --- a/examples/Gradients/gradientsCartesian.yml +++ b/examples/Gradients/gradientsCartesian.yml @@ -27,7 +27,6 @@ Statistics: SPH: resolution_eta: 1.2348 # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel). delta_neighbours: 0.1 # The tolerance for the targetted number of neighbours. - max_smoothing_length: 0.01 # Maximal smoothing length allowed (in internal units). CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. # Parameters related to the initial conditions diff --git a/examples/Gradients/gradientsRandom.yml b/examples/Gradients/gradientsRandom.yml index 209f30060f031f7d50a15ffbf8ad0e7fe5b013b8..75e6e65c92b79f6883616b91a9345a56ca7330c8 100644 --- a/examples/Gradients/gradientsRandom.yml +++ b/examples/Gradients/gradientsRandom.yml @@ -27,7 +27,6 @@ Statistics: SPH: resolution_eta: 1.2348 # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel). delta_neighbours: 0.1 # The tolerance for the targetted number of neighbours. - max_smoothing_length: 0.01 # Maximal smoothing length allowed (in internal units). CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. # Parameters related to the initial conditions diff --git a/examples/Gradients/gradientsStretched.yml b/examples/Gradients/gradientsStretched.yml index 592a70762988fca764c3ec7dcbc9bfcc9a8f2751..71c75533d13ff35b1f5bd707917fff116764187f 100644 --- a/examples/Gradients/gradientsStretched.yml +++ b/examples/Gradients/gradientsStretched.yml @@ -27,7 +27,6 @@ Statistics: SPH: resolution_eta: 1.2348 # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel). delta_neighbours: 0.1 # The tolerance for the targetted number of neighbours. - max_smoothing_length: 0.01 # Maximal smoothing length allowed (in internal units). CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. # Parameters related to the initial conditions diff --git a/examples/GreshoVortex_2D/gresho.yml b/examples/GreshoVortex_2D/gresho.yml index b4de5bde517556cacb94d996f5a11cbe05188bf9..746bad295448f6513c31431e9e206143e9565328 100644 --- a/examples/GreshoVortex_2D/gresho.yml +++ b/examples/GreshoVortex_2D/gresho.yml @@ -6,6 +6,9 @@ InternalUnitSystem: UnitCurrent_in_cgs: 1 # Amperes UnitTemp_in_cgs: 1 # Kelvin +Scheduler: + max_top_level_cells: 15 + # Parameters governing the time integration TimeIntegration: time_begin: 0. # The starting time of the simulation (in internal units). @@ -27,7 +30,6 @@ Statistics: SPH: resolution_eta: 1.2348 # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel). delta_neighbours: 0.1 # The tolerance for the targetted number of neighbours. - max_smoothing_length: 0.02 # Maximal smoothing length allowed (in internal units). CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. # Parameters related to the initial conditions diff --git a/examples/HydrostaticHalo/README b/examples/HydrostaticHalo/README new file mode 100644 index 0000000000000000000000000000000000000000..797c533926b7a131db9a08424b48b58ac3d3b8f4 --- /dev/null +++ b/examples/HydrostaticHalo/README @@ -0,0 +1,25 @@ +Hydrostatic halo in equilibrium in an isothermal potential. Running +for 10 dynamical times. + +To make the initial conditions we distribute gas particles randomly in +a cube with a side length twice that of the virial radius. The density +profile of the gas is proportional to r^(-2) where r is the distance +from the centre of the cube. + +The parameter v_rot (in makeIC.py and hydrostatic.yml) sets the circular +velocity of the halo, and by extension, the viral radius, viral mass, +and the internal energy of the gas such that hydrostatic equilibrium +is achieved. + +To run this example, make such that the code is compiled with either +the isothermal potential or softened isothermal potential set in +src/const.h. In the latter case, a (small) value of epsilon needs to +be set in hydrostatic.yml. ~1 kpc should work well. + +The plotting scripts produce a plot of the density, internal energy +and radial velocity profile for each snapshot and divides the profile +by the expected profile. + +The script test_energy_conservation.py shows the evolution of energy +with time. These can be used to check if the example has run properly. + diff --git a/examples/HydrostaticHalo/density_profile.py b/examples/HydrostaticHalo/density_profile.py new file mode 100644 index 0000000000000000000000000000000000000000..52bebb9ffefa77dae66af155fb31fed539dcde13 --- /dev/null +++ b/examples/HydrostaticHalo/density_profile.py @@ -0,0 +1,120 @@ +import numpy as np +import h5py as h5 +import matplotlib.pyplot as plt +import sys + +#for the plotting +max_r = float(sys.argv[1]) #in units of the virial radius +n_radial_bins = int(sys.argv[2]) +n_snaps = int(sys.argv[3]) + +#some constants +OMEGA = 0.3 # Cosmological matter fraction at z = 0 +PARSEC_IN_CGS = 3.0856776e18 +KM_PER_SEC_IN_CGS = 1.0e5 +CONST_G_CGS = 6.672e-8 +CONST_m_H_CGS = 1.67e-24 +h = 0.67777 # hubble parameter +gamma = 5./3. +eta = 1.2349 +H_0_cgs = 100. * h * KM_PER_SEC_IN_CGS / (1.0e6 * PARSEC_IN_CGS) + +#read some header/parameter information from the first snapshot + +filename = "Hydrostatic_000.hdf5" +f = h5.File(filename,'r') +params = f["Parameters"] +unit_mass_cgs = float(params.attrs["InternalUnitSystem:UnitMass_in_cgs"]) +unit_length_cgs = float(params.attrs["InternalUnitSystem:UnitLength_in_cgs"]) +unit_velocity_cgs = float(params.attrs["InternalUnitSystem:UnitVelocity_in_cgs"]) +unit_time_cgs = unit_length_cgs / unit_velocity_cgs +v_c = float(params.attrs["SoftenedIsothermalPotential:vrot"]) +v_c_cgs = v_c * unit_velocity_cgs +#lambda_cgs = float(params.attrs["LambdaCooling:lambda_cgs"]) +#X_H = float(params.attrs["LambdaCooling:hydrogen_mass_abundance"]) +header = f["Header"] +N = header.attrs["NumPart_Total"][0] +box_centre = np.array(header.attrs["BoxSize"]) + +#calculate r_vir and M_vir from v_c +r_vir_cgs = v_c_cgs / (10. * H_0_cgs * np.sqrt(OMEGA)) +M_vir_cgs = r_vir_cgs * v_c_cgs**2 / CONST_G_CGS + +for i in range(n_snaps): + + filename = "Hydrostatic_%03d.hdf5" %i + f = h5.File(filename,'r') + coords_dset = f["PartType0/Coordinates"] + coords = np.array(coords_dset) +#translate coords by centre of box + header = f["Header"] + snap_time = header.attrs["Time"] + snap_time_cgs = snap_time * unit_time_cgs + coords[:,0] -= box_centre[0]/2. + coords[:,1] -= box_centre[1]/2. + coords[:,2] -= box_centre[2]/2. + radius = np.sqrt(coords[:,0]**2 + coords[:,1]**2 + coords[:,2]**2) + radius_cgs = radius*unit_length_cgs + radius_over_virial_radius = radius_cgs / r_vir_cgs + + r = radius_over_virial_radius + + bin_edges = np.linspace(0.,max_r,n_radial_bins+1) + bin_width = bin_edges[1] - bin_edges[0] + hist = np.histogram(r,bins = bin_edges)[0] # number of particles in each bin + +#find the mass in each radial bin + + mass_dset = f["PartType0/Masses"] +#mass of each particles should be equal + part_mass = np.array(mass_dset)[0] + part_mass_cgs = part_mass * unit_mass_cgs + part_mass_over_virial_mass = part_mass_cgs / M_vir_cgs + + mass_hist = hist * part_mass_over_virial_mass + radial_bin_mids = np.linspace(bin_width/2.,max_r - bin_width/2.,n_radial_bins) +#volume in each radial bin + volume = 4.*np.pi * radial_bin_mids**2 * bin_width + +#now divide hist by the volume so we have a density in each bin + + density = mass_hist / volume + + ##read the densities + + # density_dset = f["PartType0/Density"] + # density = np.array(density_dset) + # density_cgs = density * unit_mass_cgs / unit_length_cgs**3 + # rho = density_cgs * r_vir_cgs**3 / M_vir_cgs + + t = np.linspace(10./n_radial_bins,10.0,1000) + rho_analytic = t**(-2)/(4.*np.pi) + + #calculate cooling radius + + #r_cool_over_r_vir = np.sqrt((2.*(gamma - 1.)*lambda_cgs*M_vir_cgs*X_H**2)/(4.*np.pi*CONST_m_H_CGS**2*v_c_cgs**2*r_vir_cgs**3))*np.sqrt(snap_time_cgs) + + #initial analytic density profile + + if (i == 0): + r_0 = radial_bin_mids[0] + rho_0 = density[0] + + rho_analytic_init = rho_0 * (radial_bin_mids/r_0)**(-2) + plt.plot(radial_bin_mids,density/rho_analytic_init,'ko',label = "Average density of shell") + #plt.plot(t,rho_analytic,label = "Initial analytic density profile" + plt.xlabel(r"$r / r_{vir}$") + plt.ylabel(r"$\rho / \rho_{init})$") + plt.title(r"$\mathrm{Time}= %.3g \, s \, , \, %d \, \, \mathrm{particles} \,,\, v_c = %.1f \, \mathrm{km / s}$" %(snap_time_cgs,N,v_c)) + #plt.ylim((1.e-2,1.e1)) + #plt.plot((r_cool_over_r_vir,r_cool_over_r_vir),(0,20),'r',label = "Cooling radius") + plt.xlim((radial_bin_mids[0],max_r)) + plt.ylim((0,20)) + plt.plot((0,max_r),(1,1)) + #plt.xscale('log') + #plt.yscale('log') + plt.legend(loc = "upper right") + plot_filename = "./plots/density_profile/density_profile_%03d.png" %i + plt.savefig(plot_filename,format = "png") + plt.close() + diff --git a/examples/HydrostaticHalo/hydrostatic.yml b/examples/HydrostaticHalo/hydrostatic.yml new file mode 100644 index 0000000000000000000000000000000000000000..39a91a4ec475a70ef4e61b9cdc59b8221a74093e --- /dev/null +++ b/examples/HydrostaticHalo/hydrostatic.yml @@ -0,0 +1,44 @@ +# Define the system of units to use internally. +InternalUnitSystem: + UnitMass_in_cgs: 1.9885e39 # 10^6 solar masses + UnitLength_in_cgs: 3.0856776e21 # Kiloparsecs + UnitVelocity_in_cgs: 1e5 # Kilometres per second + UnitCurrent_in_cgs: 1 # Amperes + UnitTemp_in_cgs: 1 # Kelvin + +# Parameters governing the time integration +TimeIntegration: + time_begin: 0. # The starting time of the simulation (in internal units). + time_end: 30. # The end time of the simulation (in internal units). + dt_min: 1e-6 # The minimal time-step size of the simulation (in internal units). + dt_max: 1e-2 # The maximal time-step size of the simulation (in internal units). + +# Parameters governing the conserved quantities statistics +Statistics: + delta_time: 1e-2 # Time between statistics output + +# Parameters governing the snapshots +Snapshots: + basename: Hydrostatic # Common part of the name of output files + time_first: 0. # Time of the first output (in internal units) + delta_time: 0.1 # Time difference between consecutive outputs (in internal units) + +# Parameters for the hydrodynamics scheme +SPH: + resolution_eta: 1.2349 # Target smoothing length in units of the mean inter-particle separation (1.2349 == 48Ngbs with the cubic spline kernel). + delta_neighbours: 0.1 # The tolerance for the targetted number of neighbours. + CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. + +# Parameters related to the initial conditions +InitialConditions: + file_name: Hydrostatic.hdf5 # The file to read + +# External potential parameters +SoftenedIsothermalPotential: + position_x: 0. # location of centre of isothermal potential in internal units + position_y: 0. + position_z: 0. + vrot: 200. # rotation speed of isothermal potential in internal units + epsilon: 1.0 + timestep_mult: 0.03 # controls time step + diff --git a/examples/HydrostaticHalo/internal_energy_profile.py b/examples/HydrostaticHalo/internal_energy_profile.py new file mode 100644 index 0000000000000000000000000000000000000000..a1b2bda314a66eb965974d34519f66c544ee8aed --- /dev/null +++ b/examples/HydrostaticHalo/internal_energy_profile.py @@ -0,0 +1,111 @@ +import numpy as np +import h5py as h5 +import matplotlib.pyplot as plt +import sys + +def do_binning(x,y,x_bin_edges): + + #x and y are arrays, where y = f(x) + #returns number of elements of x in each bin, and the total of the y elements corresponding to those x values + + n_bins = x_bin_edges.size - 1 + count = np.zeros(n_bins) + y_totals = np.zeros(n_bins) + + for i in range(n_bins): + ind = np.intersect1d(np.where(x > bin_edges[i])[0],np.where(x <= bin_edges[i+1])[0]) + count[i] = ind.size + binned_y = y[ind] + y_totals[i] = np.sum(binned_y) + + return(count,y_totals) + + +#for the plotting +max_r = float(sys.argv[1]) +n_radial_bins = int(sys.argv[2]) +n_snaps = int(sys.argv[3]) + +#some constants +OMEGA = 0.3 # Cosmological matter fraction at z = 0 +PARSEC_IN_CGS = 3.0856776e18 +KM_PER_SEC_IN_CGS = 1.0e5 +CONST_G_CGS = 6.672e-8 +CONST_m_H_CGS = 1.67e-24 +h = 0.67777 # hubble parameter +gamma = 5./3. +eta = 1.2349 +H_0_cgs = 100. * h * KM_PER_SEC_IN_CGS / (1.0e6 * PARSEC_IN_CGS) + +#read some header/parameter information from the first snapshot + +filename = "Hydrostatic_000.hdf5" +f = h5.File(filename,'r') +params = f["Parameters"] +unit_mass_cgs = float(params.attrs["InternalUnitSystem:UnitMass_in_cgs"]) +unit_length_cgs = float(params.attrs["InternalUnitSystem:UnitLength_in_cgs"]) +unit_velocity_cgs = float(params.attrs["InternalUnitSystem:UnitVelocity_in_cgs"]) +unit_time_cgs = unit_length_cgs / unit_velocity_cgs +v_c = float(params.attrs["SoftenedIsothermalPotential:vrot"]) +v_c_cgs = v_c * unit_velocity_cgs +#lambda_cgs = float(params.attrs["LambdaCooling:lambda_cgs"]) +#X_H = float(params.attrs["LambdaCooling:hydrogen_mass_abundance"]) +header = f["Header"] +N = header.attrs["NumPart_Total"][0] +box_centre = np.array(header.attrs["BoxSize"]) + +#calculate r_vir and M_vir from v_c +r_vir_cgs = v_c_cgs / (10. * H_0_cgs * np.sqrt(OMEGA)) +M_vir_cgs = r_vir_cgs * v_c_cgs**2 / CONST_G_CGS + +for i in range(n_snaps): + + filename = "Hydrostatic_%03d.hdf5" %i + f = h5.File(filename,'r') + coords_dset = f["PartType0/Coordinates"] + coords = np.array(coords_dset) +#translate coords by centre of box + header = f["Header"] + snap_time = header.attrs["Time"] + snap_time_cgs = snap_time * unit_time_cgs + coords[:,0] -= box_centre[0]/2. + coords[:,1] -= box_centre[1]/2. + coords[:,2] -= box_centre[2]/2. + radius = np.sqrt(coords[:,0]**2 + coords[:,1]**2 + coords[:,2]**2) + radius_cgs = radius*unit_length_cgs + radius_over_virial_radius = radius_cgs / r_vir_cgs + +#get the internal energies + u_dset = f["PartType0/InternalEnergy"] + u = np.array(u_dset) + +#make dimensionless + u /= v_c**2/(2. * (gamma - 1.)) + r = radius_over_virial_radius + + bin_edges = np.linspace(0,max_r,n_radial_bins + 1) + (hist,u_totals) = do_binning(r,u,bin_edges) + + bin_widths = bin_edges[1] - bin_edges[0] + radial_bin_mids = np.linspace(bin_widths / 2. , max_r - bin_widths / 2. , n_radial_bins) + binned_u = u_totals / hist + + #calculate cooling radius + + #r_cool_over_r_vir = np.sqrt((2.*(gamma - 1.)*lambda_cgs*M_vir_cgs*X_H**2)/(4.*np.pi*CONST_m_H_CGS**2*v_c_cgs**2*r_vir_cgs**3))*np.sqrt(snap_time_cgs) + + plt.plot(radial_bin_mids,binned_u,'ko',label = "Numerical solution") + #plt.plot((0,1),(1,1),label = "Analytic Solution") + #plt.plot((r_cool_over_r_vir,r_cool_over_r_vir),(0,2),'r',label = "Cooling radius") + plt.legend(loc = "lower right") + plt.xlabel(r"$r / r_{vir}$") + plt.ylabel(r"$u / (v_c^2 / (2(\gamma - 1)) $") + plt.title(r"$\mathrm{Time}= %.3g \, s \, , \, %d \, \, \mathrm{particles} \,,\, v_c = %.1f \, \mathrm{km / s}$" %(snap_time_cgs,N,v_c)) + plt.ylim((0,2)) + plot_filename = "./plots/internal_energy/internal_energy_profile_%03d.png" %i + plt.savefig(plot_filename,format = "png") + plt.close() + + + + diff --git a/examples/HydrostaticHalo/makeIC.py b/examples/HydrostaticHalo/makeIC.py new file mode 100644 index 0000000000000000000000000000000000000000..f33387e18dd0ab523684227f5c745b5c8b807b7f --- /dev/null +++ b/examples/HydrostaticHalo/makeIC.py @@ -0,0 +1,234 @@ +############################################################################### + # This file is part of SWIFT. + # Copyright (c) 2016 Stefan Arridge (stefan.arridge@durham.ac.uk) + # + # This program is free software: you can redistribute it and/or modify + # it under the terms of the GNU Lesser General Public License as published + # by the Free Software Foundation, either version 3 of the License, or + # (at your option) any later version. + # + # This program is distributed in the hope that it will be useful, + # but WITHOUT ANY WARRANTY; without even the implied warranty of + # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + # GNU General Public License for more details. + # + # You should have received a copy of the GNU Lesser General Public License + # along with this program. If not, see <http://www.gnu.org/licenses/>. + # + ############################################################################## + +import h5py +import sys +import numpy as np +import math +import random + +# Generates N particles in a spherically symmetric distribution with density profile ~r^(-2) +# usage: python makeIC.py 1000: generate 1000 particles + +# Some constants + +OMEGA = 0.3 # Cosmological matter fraction at z = 0 +PARSEC_IN_CGS = 3.0856776e18 +KM_PER_SEC_IN_CGS = 1.0e5 +CONST_G_CGS = 6.672e-8 +h = 0.67777 # hubble parameter +gamma = 5./3. +eta = 1.2349 + +# First set unit velocity and then the circular velocity parameter for the isothermal potential +const_unit_velocity_in_cgs = 1.e5 #kms^-1 + +v_c = 200. +v_c_cgs = v_c * const_unit_velocity_in_cgs + +# Now we use this to get the virial mass and virial radius, which we will set to be the unit mass and radius + +# Find H_0, the inverse Hubble time, in cgs + +H_0_cgs = 100. * h * KM_PER_SEC_IN_CGS / (1.0e6 * PARSEC_IN_CGS) + +# From this we can find the virial radius, the radius within which the average density of the halo is +# 200. * the mean matter density + +r_vir_cgs = v_c_cgs / (10. * H_0_cgs * np.sqrt(OMEGA)) + +# Now get the virial mass + +M_vir_cgs = r_vir_cgs * v_c_cgs**2 / CONST_G_CGS + +# Now set the unit length and mass + +const_unit_mass_in_cgs = M_vir_cgs +const_unit_length_in_cgs = r_vir_cgs + +print "UnitMass_in_cgs: ", const_unit_mass_in_cgs +print "UnitLength_in_cgs: ", const_unit_length_in_cgs +print "UnitVelocity_in_cgs: ", const_unit_velocity_in_cgs + +#derived quantities +const_unit_time_in_cgs = (const_unit_length_in_cgs / const_unit_velocity_in_cgs) +print "UnitTime_in_cgs: ", const_unit_time_in_cgs +const_G = ((CONST_G_CGS*const_unit_mass_in_cgs*const_unit_time_in_cgs*const_unit_time_in_cgs/(const_unit_length_in_cgs*const_unit_length_in_cgs*const_unit_length_in_cgs))) +print 'G=', const_G + +# Parameters +periodic= 1 # 1 For periodic box +boxSize = 4. +G = const_G +N = int(sys.argv[1]) # Number of particles + +# Create the file +filename = "Hydrostatic.hdf5" +file = h5py.File(filename, 'w') + +#Units +grp = file.create_group("/Units") +grp.attrs["Unit length in cgs (U_L)"] = const_unit_length_in_cgs +grp.attrs["Unit mass in cgs (U_M)"] = const_unit_mass_in_cgs +grp.attrs["Unit time in cgs (U_t)"] = const_unit_length_in_cgs / const_unit_velocity_in_cgs +grp.attrs["Unit current in cgs (U_I)"] = 1. +grp.attrs["Unit temperature in cgs (U_T)"] = 1. + + +# Runtime parameters +grp = file.create_group("/RuntimePars") +grp.attrs["PeriodicBoundariesOn"] = periodic + +# set seed for random number +np.random.seed(1234) + + +# Positions +# r^(-2) distribution corresponds to uniform distribution in radius +radius = boxSize * np.sqrt(3.) / 2.* np.random.rand(N) #the diagonal extent of the cube +ctheta = -1. + 2 * np.random.rand(N) +stheta = np.sqrt(1.-ctheta**2) +phi = 2 * math.pi * np.random.rand(N) +coords = np.zeros((N, 3)) +coords[:,0] = radius * stheta * np.cos(phi) +coords[:,1] = radius * stheta * np.sin(phi) +coords[:,2] = radius * ctheta + +#shift to centre of box +coords += np.full((N,3),boxSize/2.) +print "x range = (%f,%f)" %(np.min(coords[:,0]),np.max(coords[:,0])) +print "y range = (%f,%f)" %(np.min(coords[:,1]),np.max(coords[:,1])) +print "z range = (%f,%f)" %(np.min(coords[:,2]),np.max(coords[:,2])) + +#print np.mean(coords[:,0]) +#print np.mean(coords[:,1]) +#print np.mean(coords[:,2]) + +#now find the particles which are within the box + +x_coords = coords[:,0] +y_coords = coords[:,1] +z_coords = coords[:,2] + +ind = np.where(x_coords < boxSize)[0] +x_coords = x_coords[ind] +y_coords = y_coords[ind] +z_coords = z_coords[ind] + +ind = np.where(x_coords > 0.)[0] +x_coords = x_coords[ind] +y_coords = y_coords[ind] +z_coords = z_coords[ind] + +ind = np.where(y_coords < boxSize)[0] +x_coords = x_coords[ind] +y_coords = y_coords[ind] +z_coords = z_coords[ind] + +ind = np.where(y_coords > 0.)[0] +x_coords = x_coords[ind] +y_coords = y_coords[ind] +z_coords = z_coords[ind] + +ind = np.where(z_coords < boxSize)[0] +x_coords = x_coords[ind] +y_coords = y_coords[ind] +z_coords = z_coords[ind] + +ind = np.where(z_coords > 0.)[0] +x_coords = x_coords[ind] +y_coords = y_coords[ind] +z_coords = z_coords[ind] + +#count number of particles + +N = x_coords.size + +print "Number of particles in the box = " , N + +#make the coords and radius arrays again +coords_2 = np.zeros((N,3)) +coords_2[:,0] = x_coords +coords_2[:,1] = y_coords +coords_2[:,2] = z_coords + +radius = np.sqrt(coords_2[:,0]**2 + coords_2[:,1]**2 + coords_2[:,2]**2) + +#test we've done it right + +print "x range = (%f,%f)" %(np.min(coords_2[:,0]),np.max(coords_2[:,0])) +print "y range = (%f,%f)" %(np.min(coords_2[:,1]),np.max(coords_2[:,1])) +print "z range = (%f,%f)" %(np.min(coords_2[:,2]),np.max(coords_2[:,2])) + +print np.mean(coords_2[:,0]) +print np.mean(coords_2[:,1]) +print np.mean(coords_2[:,2]) + +# Header +grp = file.create_group("/Header") +grp.attrs["BoxSize"] = boxSize +grp.attrs["NumPart_Total"] = [N ,0, 0, 0, 0, 0] +grp.attrs["NumPart_Total_HighWord"] = [0, 0, 0, 0, 0, 0] +grp.attrs["NumPart_ThisFile"] = [N, 0, 0, 0, 0, 0] +grp.attrs["Time"] = 0.0 +grp.attrs["NumFilesPerSnapshot"] = 1 +grp.attrs["MassTable"] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] +grp.attrs["Flag_Entropy_ICs"] = [0, 0, 0, 0, 0, 0] +grp.attrs["Dimension"] = 3 + +# Particle group +grp = file.create_group("/PartType0") + +ds = grp.create_dataset('Coordinates', (N, 3), 'd') +ds[()] = coords_2 +coords_2 = np.zeros(1) + +# All velocities set to zero +v = np.zeros((N,3)) +ds = grp.create_dataset('Velocities', (N, 3), 'f') +ds[()] = v +v = np.zeros(1) + +# All particles of equal mass +mass = 1. / N +m = np.full((N,),mass) +ds = grp.create_dataset('Masses', (N, ), 'f') +ds[()] = m +m = np.zeros(1) + +# Smoothing lengths +l = (4. * np.pi * radius**2 / N)**(1./3.) #local mean inter-particle separation +h = np.full((N, ), eta * l) +ds = grp.create_dataset('SmoothingLength', (N,), 'f') +ds[()] = h +h = np.zeros(1) + +# Internal energies +u = v_c**2 / (2. * (gamma - 1.)) +u = np.full((N, ), u) +ds = grp.create_dataset('InternalEnergy', (N,), 'f') +ds[()] = u +u = np.zeros(1) + +# Particle IDs +ids = 1 + np.linspace(0, N, N, endpoint=False, dtype='L') +ds = grp.create_dataset('ParticleIDs', (N, ), 'L') +ds[()] = ids + +file.close() diff --git a/examples/HydrostaticHalo/run.sh b/examples/HydrostaticHalo/run.sh new file mode 100755 index 0000000000000000000000000000000000000000..d23ead6a67f43c9d19d76a797e72d050a3978d61 --- /dev/null +++ b/examples/HydrostaticHalo/run.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +# Generate the initial conditions if they are not present. +echo "Generating initial conditions for the isothermal potential box example..." +python makeIC.py 100000 + +# Run for 10 dynamical times +../swift -g -s -t 2 hydrostatic.yml 2>&1 | tee output.log + +echo "Plotting density profiles" +mkdir plots +mkdir plots/density_profile +python density_profile.py 2. 200 300 + +echo "Plotting internal energy profiles" +mkdir plots/internal_energy +python internal_energy_profile.py 2. 200 300 + +echo "Plotting radial velocity profiles" +mkdir plots/radial_velocity_profile +python velocity_profile.py 2. 200 300 + +echo "Plotting energy as a function of time" +python test_energy_conservation.py 300 diff --git a/examples/HydrostaticHalo/test_energy_conservation.py b/examples/HydrostaticHalo/test_energy_conservation.py new file mode 100644 index 0000000000000000000000000000000000000000..ca091050c4127d11a37a2cc7504e42d244031e25 --- /dev/null +++ b/examples/HydrostaticHalo/test_energy_conservation.py @@ -0,0 +1,95 @@ +import numpy as np +import h5py as h5 +import matplotlib.pyplot as plt +import sys + +n_snaps = int(sys.argv[1]) + +#some constants +OMEGA = 0.3 # Cosmological matter fraction at z = 0 +PARSEC_IN_CGS = 3.0856776e18 +KM_PER_SEC_IN_CGS = 1.0e5 +CONST_G_CGS = 6.672e-8 +h = 0.67777 # hubble parameter +gamma = 5./3. +eta = 1.2349 +H_0_cgs = 100. * h * KM_PER_SEC_IN_CGS / (1.0e6 * PARSEC_IN_CGS) + +#read some header/parameter information from the first snapshot + +filename = "Hydrostatic_000.hdf5" +f = h5.File(filename,'r') +params = f["Parameters"] +unit_mass_cgs = float(params.attrs["InternalUnitSystem:UnitMass_in_cgs"]) +unit_length_cgs = float(params.attrs["InternalUnitSystem:UnitLength_in_cgs"]) +unit_velocity_cgs = float(params.attrs["InternalUnitSystem:UnitVelocity_in_cgs"]) +unit_time_cgs = unit_length_cgs / unit_velocity_cgs +v_c = float(params.attrs["SoftenedIsothermalPotential:vrot"]) +v_c_cgs = v_c * unit_velocity_cgs +header = f["Header"] +N = header.attrs["NumPart_Total"][0] +box_centre = np.array(header.attrs["BoxSize"]) + +#calculate r_vir and M_vir from v_c +r_vir_cgs = v_c_cgs / (10. * H_0_cgs * np.sqrt(OMEGA)) +M_vir_cgs = r_vir_cgs * v_c_cgs**2 / CONST_G_CGS + +potential_energy_array = [] +internal_energy_array = [] +kinetic_energy_array = [] +time_array_cgs = [] + +for i in range(n_snaps): + + filename = "Hydrostatic_%03d.hdf5" %i + f = h5.File(filename,'r') + coords_dset = f["PartType0/Coordinates"] + coords = np.array(coords_dset) +#translate coords by centre of box + header = f["Header"] + snap_time = header.attrs["Time"] + snap_time_cgs = snap_time * unit_time_cgs + time_array_cgs = np.append(time_array_cgs,snap_time_cgs) + coords[:,0] -= box_centre[0]/2. + coords[:,1] -= box_centre[1]/2. + coords[:,2] -= box_centre[2]/2. + radius = np.sqrt(coords[:,0]**2 + coords[:,1]**2 + coords[:,2]**2) + radius_cgs = radius*unit_length_cgs + radius_over_virial_radius = radius_cgs / r_vir_cgs + + r = radius_over_virial_radius + total_potential_energy = np.sum(v_c**2*np.log(r)) + potential_energy_array = np.append(potential_energy_array,total_potential_energy) + + vels_dset = f["PartType0/Velocities"] + vels = np.array(vels_dset) + speed_squared = vels[:,0]**2 + vels[:,1]**2 + vels[:,2]**2 + total_kinetic_energy = 0.5 * np.sum(speed_squared) + kinetic_energy_array = np.append(kinetic_energy_array,total_kinetic_energy) + + u_dset = f["PartType0/InternalEnergy"] + u = np.array(u_dset) + total_internal_energy = np.sum(u) + internal_energy_array = np.append(internal_energy_array,total_internal_energy) + +#put energies in units of v_c^2 and rescale by number of particles + +pe = potential_energy_array / (N*v_c**2) +ke = kinetic_energy_array / (N*v_c**2) +ie = internal_energy_array / (N*v_c**2) +te = pe + ke + ie + +dyn_time_cgs = r_vir_cgs / v_c_cgs +time_array = time_array_cgs / dyn_time_cgs + +plt.plot(time_array,ke,label = "Kinetic Energy") +plt.plot(time_array,pe,label = "Potential Energy") +plt.plot(time_array,ie,label = "Internal Energy") +plt.plot(time_array,te,label = "Total Energy") +plt.legend(loc = "lower right") +plt.xlabel(r"$t / t_{dyn}$") +plt.ylabel(r"$E / v_c^2$") +plt.title(r"$%d \, \, \mathrm{particles} \,,\, v_c = %.1f \, \mathrm{km / s}$" %(N,v_c)) +plt.ylim((-2,2)) +plt.savefig("energy_conservation.png",format = 'png') + diff --git a/examples/HydrostaticHalo/velocity_profile.py b/examples/HydrostaticHalo/velocity_profile.py new file mode 100644 index 0000000000000000000000000000000000000000..f6a7350b9731d660b2092266d4d6ad3730bab48c --- /dev/null +++ b/examples/HydrostaticHalo/velocity_profile.py @@ -0,0 +1,111 @@ +import numpy as np +import h5py as h5 +import matplotlib.pyplot as plt +import sys + +def do_binning(x,y,x_bin_edges): + + #x and y are arrays, where y = f(x) + #returns number of elements of x in each bin, and the total of the y elements corresponding to those x values + + n_bins = x_bin_edges.size - 1 + count = np.zeros(n_bins) + y_totals = np.zeros(n_bins) + + for i in range(n_bins): + ind = np.intersect1d(np.where(x > bin_edges[i])[0],np.where(x <= bin_edges[i+1])[0]) + count[i] = ind.size + binned_y = y[ind] + y_totals[i] = np.sum(binned_y) + + return(count,y_totals) + + +#for the plotting +max_r = float(sys.argv[1]) +n_radial_bins = int(sys.argv[2]) +n_snaps = int(sys.argv[3]) + +#some constants +OMEGA = 0.3 # Cosmological matter fraction at z = 0 +PARSEC_IN_CGS = 3.0856776e18 +KM_PER_SEC_IN_CGS = 1.0e5 +CONST_G_CGS = 6.672e-8 +CONST_m_H_CGS = 1.67e-24 +h = 0.67777 # hubble parameter +gamma = 5./3. +eta = 1.2349 +H_0_cgs = 100. * h * KM_PER_SEC_IN_CGS / (1.0e6 * PARSEC_IN_CGS) + +#read some header/parameter information from the first snapshot + +filename = "Hydrostatic_000.hdf5" +f = h5.File(filename,'r') +params = f["Parameters"] +unit_mass_cgs = float(params.attrs["InternalUnitSystem:UnitMass_in_cgs"]) +unit_length_cgs = float(params.attrs["InternalUnitSystem:UnitLength_in_cgs"]) +unit_velocity_cgs = float(params.attrs["InternalUnitSystem:UnitVelocity_in_cgs"]) +unit_time_cgs = unit_length_cgs / unit_velocity_cgs +v_c = float(params.attrs["SoftenedIsothermalPotential:vrot"]) +v_c_cgs = v_c * unit_velocity_cgs +header = f["Header"] +N = header.attrs["NumPart_Total"][0] +box_centre = np.array(header.attrs["BoxSize"]) + +#calculate r_vir and M_vir from v_c +r_vir_cgs = v_c_cgs / (10. * H_0_cgs * np.sqrt(OMEGA)) +M_vir_cgs = r_vir_cgs * v_c_cgs**2 / CONST_G_CGS + +for i in range(n_snaps): + + filename = "Hydrostatic_%03d.hdf5" %i + f = h5.File(filename,'r') + coords_dset = f["PartType0/Coordinates"] + coords = np.array(coords_dset) +#translate coords by centre of box + header = f["Header"] + snap_time = header.attrs["Time"] + snap_time_cgs = snap_time * unit_time_cgs + coords[:,0] -= box_centre[0]/2. + coords[:,1] -= box_centre[1]/2. + coords[:,2] -= box_centre[2]/2. + radius = np.sqrt(coords[:,0]**2 + coords[:,1]**2 + coords[:,2]**2) + radius_cgs = radius*unit_length_cgs + radius_over_virial_radius = radius_cgs / r_vir_cgs + +#get the internal energies + vel_dset = f["PartType0/Velocities"] + vel = np.array(vel_dset) + +#make dimensionless + vel /= v_c + r = radius_over_virial_radius + + #find radial component of velocity + + v_r = np.zeros(r.size) + for j in range(r.size): + v_r[j] = -np.dot(coords[j,:],vel[j,:])/radius[j] + + bin_edges = np.linspace(0,max_r,n_radial_bins + 1) + (hist,v_r_totals) = do_binning(r,v_r,bin_edges) + + bin_widths = bin_edges[1] - bin_edges[0] + radial_bin_mids = np.linspace(bin_widths / 2. , max_r - bin_widths / 2. , n_radial_bins) + binned_v_r = v_r_totals / hist + + #calculate cooling radius + + #r_cool_over_r_vir = np.sqrt((2.*(gamma - 1.)*lambda_cgs*M_vir_cgs*X_H**2)/(4.*np.pi*CONST_m_H_CGS**2*v_c_cgs**2*r_vir_cgs**3))*np.sqrt(snap_time_cgs) + + plt.plot(radial_bin_mids,binned_v_r,'ko',label = "Average radial velocity in shell") + #plt.plot((0,1),(1,1),label = "Analytic Solution") + #plt.plot((r_cool_over_r_vir,r_cool_over_r_vir),(0,2),'r',label = "Cooling radius") + plt.legend(loc = "upper right") + plt.xlabel(r"$r / r_{vir}$") + plt.ylabel(r"$v_r / v_c$") + plt.title(r"$\mathrm{Time}= %.3g \, s \, , \, %d \, \, \mathrm{particles} \,,\, v_c = %.1f \, \mathrm{km / s}$" %(snap_time_cgs,N,v_c)) + plt.ylim((0,2)) + plot_filename = "./plots/radial_velocity_profile/velocity_profile_%03d.png" %i + plt.savefig(plot_filename,format = "png") + plt.close() diff --git a/examples/IsothermalPotential/GravityOnly/README b/examples/IsothermalPotential/README similarity index 100% rename from examples/IsothermalPotential/GravityOnly/README rename to examples/IsothermalPotential/README diff --git a/examples/IsothermalPotential/GravityOnly/isothermal.yml b/examples/IsothermalPotential/isothermal.yml similarity index 100% rename from examples/IsothermalPotential/GravityOnly/isothermal.yml rename to examples/IsothermalPotential/isothermal.yml diff --git a/examples/IsothermalPotential/GravityOnly/makeIC.py b/examples/IsothermalPotential/makeIC.py similarity index 97% rename from examples/IsothermalPotential/GravityOnly/makeIC.py rename to examples/IsothermalPotential/makeIC.py index 07993f19d40a9a3b9a4b86c9dd8c44f7e6fa3d7e..976119f0a312c5acc81fab943ba3cf5769102269 100644 --- a/examples/IsothermalPotential/GravityOnly/makeIC.py +++ b/examples/IsothermalPotential/makeIC.py @@ -141,17 +141,17 @@ ds = grp1.create_dataset('Velocities', (numPart, 3), 'f') ds[()] = v v = numpy.zeros(1) -m = numpy.full((numPart, ), mass) +m = numpy.full((numPart, ), mass, dtype='f') ds = grp1.create_dataset('Masses', (numPart,), 'f') ds[()] = m m = numpy.zeros(1) -h = numpy.full((numPart, ), 1.1255 * boxSize / L) +h = numpy.full((numPart, ), 1.1255 * boxSize / L, dtype='f') ds = grp1.create_dataset('SmoothingLength', (numPart,), 'f') ds[()] = h h = numpy.zeros(1) -u = numpy.full((numPart, ), internalEnergy) +u = numpy.full((numPart, ), internalEnergy, dtype='f') ds = grp1.create_dataset('InternalEnergy', (numPart,), 'f') ds[()] = u u = numpy.zeros(1) diff --git a/examples/IsothermalPotential/GravityOnly/run.sh b/examples/IsothermalPotential/run.sh similarity index 79% rename from examples/IsothermalPotential/GravityOnly/run.sh rename to examples/IsothermalPotential/run.sh index f6adfcececf4923485c0deabd97e9af9a6f64b05..28a3cc0910f986f84bcd603091543643356f1c4a 100755 --- a/examples/IsothermalPotential/GravityOnly/run.sh +++ b/examples/IsothermalPotential/run.sh @@ -7,4 +7,4 @@ then python makeIC.py 1000 1 fi -../../swift -g -t 2 isothermal.yml 2>&1 | tee output.log +../swift -g -t 1 isothermal.yml 2>&1 | tee output.log diff --git a/examples/IsothermalPotential/GravityOnly/test.pro b/examples/IsothermalPotential/test.pro similarity index 100% rename from examples/IsothermalPotential/GravityOnly/test.pro rename to examples/IsothermalPotential/test.pro diff --git a/examples/KelvinHelmholtz_2D/kelvinHelmholtz.yml b/examples/KelvinHelmholtz_2D/kelvinHelmholtz.yml index 38dd16880a209b885f7ad9c30c024988f4d8228f..a229ecbdedba00d334ad9d3b80dce187b4ac0224 100644 --- a/examples/KelvinHelmholtz_2D/kelvinHelmholtz.yml +++ b/examples/KelvinHelmholtz_2D/kelvinHelmholtz.yml @@ -6,6 +6,9 @@ InternalUnitSystem: UnitCurrent_in_cgs: 1 # Amperes UnitTemp_in_cgs: 1 # Kelvin +Scheduler: + max_top_level_cells: 30 + # Parameters governing the time integration TimeIntegration: time_begin: 0. # The starting time of the simulation (in internal units). @@ -27,7 +30,6 @@ Statistics: SPH: resolution_eta: 1.2348 # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel). delta_neighbours: 0.1 # The tolerance for the targetted number of neighbours. - max_smoothing_length: 0.01 # Maximal smoothing length allowed (in internal units). CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. # Parameters related to the initial conditions diff --git a/examples/Makefile.am b/examples/Makefile.am index d9e1f2fe741098fe2051155fc1ff2d66d4751cee..4da84788a485dacd2103fe85ad3e729ade6b582a 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -30,13 +30,12 @@ EXTRA_LIBS = $(HDF5_LIBS) $(FFTW_LIBS) $(PROFILER_LIBS) $(TCMALLOC_LIBS) MPI_LIBS = $(METIS_LIBS) $(MPI_THREAD_LIBS) MPI_FLAGS = -DWITH_MPI $(METIS_INCS) - # Programs. -bin_PROGRAMS = swift swift_fixdt +bin_PROGRAMS = swift # Build MPI versions as well? if HAVEMPI -bin_PROGRAMS += swift_mpi swift_fixdt_mpi +bin_PROGRAMS += swift_mpi endif # engine_policy_setaffinity is available? @@ -51,19 +50,11 @@ swift_SOURCES = main.c swift_CFLAGS = $(MYFLAGS) $(AM_CFLAGS) -DENGINE_POLICY="engine_policy_keep $(ENGINE_POLICY_SETAFFINITY)" swift_LDADD = ../src/.libs/libswiftsim.a $(EXTRA_LIBS) -swift_fixdt_SOURCES = main.c -swift_fixdt_CFLAGS = $(MYFLAGS) $(AM_CFLAGS) -DENGINE_POLICY="engine_policy_fixdt | engine_policy_keep $(ENGINE_POLICY_SETAFFINITY)" -swift_fixdt_LDADD = ../src/.libs/libswiftsim.a $(EXTRA_LIBS) - # Sources for swift_mpi, do we need an affinity policy for MPI? swift_mpi_SOURCES = main.c swift_mpi_CFLAGS = $(MYFLAGS) $(AM_CFLAGS) $(MPI_FLAGS) -DENGINE_POLICY="engine_policy_keep $(ENGINE_POLICY_SETAFFINITY)" swift_mpi_LDADD = ../src/.libs/libswiftsim_mpi.a $(MPI_LIBS) $(EXTRA_LIBS) -swift_fixdt_mpi_SOURCES = main.c -swift_fixdt_mpi_CFLAGS = $(MYFLAGS) $(AM_CFLAGS) $(MPI_FLAGS) -DENGINE_POLICY="engine_policy_fixdt | engine_policy_keep $(ENGINE_POLICY_SETAFFINITY)" -swift_fixdt_mpi_LDADD = ../src/.libs/libswiftsim_mpi.a $(MPI_LIBS) $(EXTRA_LIBS) - # Scripts to generate ICs EXTRA_DIST = BigCosmoVolume/makeIC.py \ BigPerturbedBox/makeIC_fcc.py \ @@ -74,6 +65,9 @@ EXTRA_DIST = BigCosmoVolume/makeIC.py \ EAGLE_50/eagle_50.yml EAGLE_50/getIC.sh EAGLE_50/README EAGLE_50/run.sh \ ExternalPointMass/externalPointMass.yml ExternalPointMass/makeIC.py ExternalPointMass/run.sh ExternalPointMass/test.pro \ GreshoVortex_2D/getGlass.sh GreshoVortex_2D/gresho.yml GreshoVortex_2D/makeIC.py GreshoVortex_2D/plotSolution.py GreshoVortex_2D/run.sh \ + HydrostaticHalo/README HydrostaticHalo/hydrostatic.yml HydrostaticHalo/makeIC.py HydrostaticHalo/run.sh \ + HydrostaticHalo/density_profile.py HydrostaticHalo/velocity_profile.py HydrostaticHalo/internal_energy_profile.py HydrostaticHalo/test_energy_conservation.py \ + IsothermalPotential/README IsothermalPotential/run.sh IsothermalPotential/test.pro IsothermalPotential/isothermal.yml IsothermalPotential/makeIC.py \ KelvinHelmholtz_2D/kelvinHelmholtz.yml KelvinHelmholtz_2D/makeIC.py KelvinHelmholtz_2D/plotSolution.py KelvinHelmholtz_2D/run.sh \ MultiTypes/makeIC.py MultiTypes/multiTypes.yml MultiTypes/run.sh \ PerturbedBox_2D/makeIC.py PerturbedBox_2D/perturbedPlane.yml \ diff --git a/examples/MultiTypes/multiTypes.yml b/examples/MultiTypes/multiTypes.yml index 51a6d2b478681e2e1c61e199f758e35c507ec195..4d54f95fcdd09464b03d0f9987398cd2710b2e44 100644 --- a/examples/MultiTypes/multiTypes.yml +++ b/examples/MultiTypes/multiTypes.yml @@ -27,7 +27,6 @@ Statistics: SPH: resolution_eta: 1.2348 # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel). delta_neighbours: 0.1 # The tolerance for the targetted number of neighbours. - max_smoothing_length: 0.1 # Maximal smoothing length allowed (in internal units). CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. # Parameters related to the initial conditions diff --git a/examples/PerturbedBox_2D/perturbedPlane.yml b/examples/PerturbedBox_2D/perturbedPlane.yml index e810131cc4b1c66b46b483b1605f9d84bcf203b3..b92e29f620edc6f72399111fbe73ba6bd1485e92 100644 --- a/examples/PerturbedBox_2D/perturbedPlane.yml +++ b/examples/PerturbedBox_2D/perturbedPlane.yml @@ -27,7 +27,6 @@ Statistics: SPH: resolution_eta: 1.2348 # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel). delta_neighbours: 0.1 # The tolerance for the targetted number of neighbours. - max_smoothing_length: 0.1 # Maximal smoothing length allowed (in internal units). CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. # Parameters related to the initial conditions diff --git a/examples/PerturbedBox_3D/perturbedBox.yml b/examples/PerturbedBox_3D/perturbedBox.yml index 3a445e27e74fb83fb8deb56fde6003c22f7dedf1..71c8dece4df5505eb44511ee92291feedd7ffab1 100644 --- a/examples/PerturbedBox_3D/perturbedBox.yml +++ b/examples/PerturbedBox_3D/perturbedBox.yml @@ -27,7 +27,6 @@ Statistics: SPH: resolution_eta: 1.2348 # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel). delta_neighbours: 0.1 # The tolerance for the targetted number of neighbours. - max_smoothing_length: 0.1 # Maximal smoothing length allowed (in internal units). CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. # Parameters related to the initial conditions diff --git a/examples/SedovBlast_1D/sedov.yml b/examples/SedovBlast_1D/sedov.yml index 1ecfeb32452d05f299b98124c4fdfc79126f7504..2a15d6ed22e71735c04274cee3f719b9d21f170e 100644 --- a/examples/SedovBlast_1D/sedov.yml +++ b/examples/SedovBlast_1D/sedov.yml @@ -27,7 +27,6 @@ Statistics: SPH: resolution_eta: 1.2348 # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel). delta_neighbours: 0.1 # The tolerance for the targetted number of neighbours. - max_smoothing_length: 0.1 # Maximal smoothing length allowed (in internal units). CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. # Parameters related to the initial conditions diff --git a/examples/SedovBlast_2D/sedov.yml b/examples/SedovBlast_2D/sedov.yml index 6f519835d26ff5aa851ffb8999e650815c522cd3..1cc4aced9af3314cadde44f768016225426addf6 100644 --- a/examples/SedovBlast_2D/sedov.yml +++ b/examples/SedovBlast_2D/sedov.yml @@ -27,7 +27,6 @@ Statistics: SPH: resolution_eta: 1.2348 # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel). delta_neighbours: 0.1 # The tolerance for the targetted number of neighbours. - max_smoothing_length: 0.1 # Maximal smoothing length allowed (in internal units). CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. # Parameters related to the initial conditions diff --git a/examples/SedovBlast_3D/sedov.yml b/examples/SedovBlast_3D/sedov.yml index 6f519835d26ff5aa851ffb8999e650815c522cd3..1cc4aced9af3314cadde44f768016225426addf6 100644 --- a/examples/SedovBlast_3D/sedov.yml +++ b/examples/SedovBlast_3D/sedov.yml @@ -27,7 +27,6 @@ Statistics: SPH: resolution_eta: 1.2348 # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel). delta_neighbours: 0.1 # The tolerance for the targetted number of neighbours. - max_smoothing_length: 0.1 # Maximal smoothing length allowed (in internal units). CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. # Parameters related to the initial conditions diff --git a/examples/SodShock_1D/sodShock.yml b/examples/SodShock_1D/sodShock.yml index d5c4d0b034ff5351222d2162e37e3e40ceab834f..a5759109e48b7e7eb9cbd15957cf438edd909f1f 100644 --- a/examples/SodShock_1D/sodShock.yml +++ b/examples/SodShock_1D/sodShock.yml @@ -27,7 +27,6 @@ Statistics: SPH: resolution_eta: 1.2348 # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel). delta_neighbours: 0.1 # The tolerance for the targetted number of neighbours. - max_smoothing_length: 0.4 # Maximal smoothing length allowed (in internal units). CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. # Parameters related to the initial conditions diff --git a/examples/SodShock_2D/sodShock.yml b/examples/SodShock_2D/sodShock.yml index 6805724ff58defebc41f3fb5b636d0003b0d6680..7ee61adf38b41012ed4d77a882640b826f15dec1 100644 --- a/examples/SodShock_2D/sodShock.yml +++ b/examples/SodShock_2D/sodShock.yml @@ -6,6 +6,9 @@ InternalUnitSystem: UnitCurrent_in_cgs: 1 # Amperes UnitTemp_in_cgs: 1 # Kelvin +Scheduler: + max_top_level_cells: 60 + # Parameters governing the time integration TimeIntegration: time_begin: 0. # The starting time of the simulation (in internal units). @@ -27,7 +30,6 @@ Statistics: SPH: resolution_eta: 1.2348 # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel). delta_neighbours: 0.1 # The tolerance for the targetted number of neighbours. - max_smoothing_length: 0.02 # Maximal smoothing length allowed (in internal units). CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. # Parameters related to the initial conditions diff --git a/examples/SodShock_3D/sodShock.yml b/examples/SodShock_3D/sodShock.yml index 1ab6eb626db09678f66322e8f0e8674c0931ddb6..e7e01fa36bf93105371aa97336e18535e4078853 100644 --- a/examples/SodShock_3D/sodShock.yml +++ b/examples/SodShock_3D/sodShock.yml @@ -27,7 +27,6 @@ Statistics: SPH: resolution_eta: 1.2348 # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel). delta_neighbours: 0.1 # The tolerance for the targetted number of neighbours. - max_smoothing_length: 0.05 # Maximal smoothing length allowed (in internal units). CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. # Parameters related to the initial conditions diff --git a/examples/SquareTest_2D/square.yml b/examples/SquareTest_2D/square.yml index 4f39c6490899cfaafeda17fb0c28281cbadcbbea..40ccf41cec99f82f9c208f9f719323d32caea19b 100644 --- a/examples/SquareTest_2D/square.yml +++ b/examples/SquareTest_2D/square.yml @@ -6,6 +6,9 @@ InternalUnitSystem: UnitCurrent_in_cgs: 1 # Amperes UnitTemp_in_cgs: 1 # Kelvin +Scheduler: + max_top_level_cells: 15 + # Parameters governing the time integration TimeIntegration: time_begin: 0. # The starting time of the simulation (in internal units). @@ -27,7 +30,6 @@ Statistics: SPH: resolution_eta: 1.2348 # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel). delta_neighbours: 0.1 # The tolerance for the targetted number of neighbours. - max_smoothing_length: 0.02 # Maximal smoothing length allowed (in internal units). CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. # Parameters related to the initial conditions diff --git a/examples/UniformBox_2D/uniformPlane.yml b/examples/UniformBox_2D/uniformPlane.yml index a3e2d275e50fb20f66ea6494c1202319e462dbed..0354f8e78eea17a41b3ed02e615cd3fb216f59c0 100644 --- a/examples/UniformBox_2D/uniformPlane.yml +++ b/examples/UniformBox_2D/uniformPlane.yml @@ -27,7 +27,6 @@ Statistics: SPH: resolution_eta: 1.2348 # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel). delta_neighbours: 0.1 # The tolerance for the targetted number of neighbours. - max_smoothing_length: 0.1 # Maximal smoothing length allowed (in internal units). CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. # Parameters related to the initial conditions diff --git a/examples/UniformBox_3D/uniformBox.yml b/examples/UniformBox_3D/uniformBox.yml index 8aaa802b64de46244f7066bce00f342cad8c5ef0..e75c878389be83304dbb9670e20a6aaf03c9c6e0 100644 --- a/examples/UniformBox_3D/uniformBox.yml +++ b/examples/UniformBox_3D/uniformBox.yml @@ -27,7 +27,6 @@ Statistics: SPH: resolution_eta: 1.2348 # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel). delta_neighbours: 0.1 # The tolerance for the targetted number of neighbours. - max_smoothing_length: 0.1 # Maximal smoothing length allowed (in internal units). CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. # Parameters related to the initial conditions diff --git a/examples/main.c b/examples/main.c index 06efe75b32f790b10d1125fb5010bc3d1b4f9e24..dcc113ab6af6a06e7c20ac1aac7c2d3b715f7ef3 100644 --- a/examples/main.c +++ b/examples/main.c @@ -52,8 +52,6 @@ void print_help_message() { printf("\nUsage: swift [OPTION]... PARAMFILE\n"); printf(" swift_mpi [OPTION]... PARAMFILE\n"); - printf(" swift_fixdt [OPTION]... PARAMFILE\n"); - printf(" swift_fixdt_mpi [OPTION]... PARAMFILE\n\n"); printf("Valid options are:\n"); printf(" %2s %8s %s\n", "-a", "", "Pin runners using processor affinity"); @@ -114,8 +112,8 @@ int main(int argc, char *argv[]) { error("Call to MPI_Init failed with error %i.", res); if (prov != MPI_THREAD_MULTIPLE) error( - "MPI does not provide the level of threading required " - "(MPI_THREAD_MULTIPLE)."); + "MPI does not provide the level of threading" + " required (MPI_THREAD_MULTIPLE)."); if ((res = MPI_Comm_size(MPI_COMM_WORLD, &nr_nodes)) != MPI_SUCCESS) error("MPI_Comm_size failed with error %i.", res); if ((res = MPI_Comm_rank(MPI_COMM_WORLD, &myrank)) != MPI_SUCCESS) @@ -127,9 +125,7 @@ int main(int argc, char *argv[]) { if ((res = MPI_Comm_set_errhandler(MPI_COMM_WORLD, MPI_ERRORS_RETURN)) != MPI_SUCCESS) error("Call to MPI_Comm_set_errhandler failed with error %i.", res); - if (myrank == 0) - printf("[0000][00000.0] MPI is up and running with %i node(s).\n", - nr_nodes); + if (myrank == 0) message("MPI is up and running with %i node(s).", nr_nodes); if (nr_nodes == 1) { message("WARNING: you are running with one MPI rank."); message("WARNING: you should use the non-MPI version of this program."); @@ -235,6 +231,13 @@ int main(int argc, char *argv[]) { if (myrank == 0) print_help_message(); return 1; } +#ifndef SWIFT_DEBUG_TASKS + if (dump_tasks) { + error( + "Task dumping is only possible if SWIFT was configured with the " + "--enable-task-debugging option."); + } +#endif break; case '?': if (myrank == 0) print_help_message(); @@ -282,6 +285,11 @@ int main(int argc, char *argv[]) { message("Running on: %s", hostname()); #endif +/* Do we have debugging checks ? */ +#ifdef SWIFT_DEBUG_CHECKS + message("WARNING: Debugging checks activated. Code will be slower !"); +#endif + /* Do we choke on FP-exceptions ? */ if (with_fp_exceptions) { feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW); @@ -454,7 +462,7 @@ int main(int argc, char *argv[]) { /* Initialise the external potential properties */ struct external_potential potential; if (with_external_gravity) - potential_init(params, &prog_const, &us, &potential); + potential_init(params, &prog_const, &us, &s, &potential); if (with_external_gravity && myrank == 0) potential_print(&potential); /* Initialise the cooling function properties */ @@ -549,6 +557,7 @@ int main(int argc, char *argv[]) { /* Take a step. */ engine_step(&e); +#ifdef SWIFT_DEBUG_TASKS /* Dump the task data using the given frequency. */ if (dump_tasks && (dump_tasks == 1 || j % dump_tasks == 1)) { #ifdef WITH_MPI @@ -626,8 +635,9 @@ int main(int argc, char *argv[]) { } } fclose(file_thread); -#endif +#endif // WITH_MPI } +#endif // SWIFT_DEBUG_TASKS } /* Print the values of the runner histogram. */ diff --git a/examples/parameter_example.yml b/examples/parameter_example.yml index fb193a81baf410360172793763875891f654211a..899bfb02243c69d3c0d0a94cb05c4f63cb62df32 100644 --- a/examples/parameter_example.yml +++ b/examples/parameter_example.yml @@ -8,13 +8,14 @@ InternalUnitSystem: # Parameters for the task scheduling Scheduler: - nr_queues: 0 # (Optional) The number of task queues to use. Use 0 to let the system decide. - cell_max_size: 8000000 # (Optional) Maximal number of interactions per task if we force the split (this is the default value). - cell_sub_size: 64000000 # (Optional) Maximal number of interactions per sub-task (this is the default value). - cell_split_size: 400 # (Optional) Maximal number of particles per cell (this is the default value). - cell_max_count: 10000 # (Optional) Maximal number of particles per cell allowed before triggering a sanitizing (this is the default value). + nr_queues: 0 # (Optional) The number of task queues to use. Use 0 to let the system decide. + cell_max_size: 8000000 # (Optional) Maximal number of interactions per task if we force the split (this is the default value). + cell_sub_size: 64000000 # (Optional) Maximal number of interactions per sub-task (this is the default value). + cell_split_size: 400 # (Optional) Maximal number of particles per cell (this is the default value). + cell_max_count: 10000 # (Optional) Maximal number of particles per cell allowed before triggering a sanitizing (this is the default value). + max_top_level_cells: 12 # (Optional) Maximal number of top-level cells in any dimension. The number of top-level cells will be the cube of this (this is the default value). -# Parameters governing the time integration +# Parameters governing the time integration (Set dt_min and dt_max to the same value for a fixed time-step run.) TimeIntegration: time_begin: 0. # The starting time of the simulation (in internal units). time_end: 1. # The end time of the simulation (in internal units). @@ -43,9 +44,8 @@ Statistics: SPH: resolution_eta: 1.2348 # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel). delta_neighbours: 0.1 # The tolerance for the targetted number of neighbours. - max_ghost_iterations: 30 # (Optional) Maximal number of iterations allowed to converge towards the smoothing length. - max_smoothing_length: 0.1 # Maximal smoothing length allowed (in internal units). CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. + max_ghost_iterations: 30 # (Optional) Maximal number of iterations allowed to converge towards the smoothing length. max_volume_change: 2. # (Optional) Maximal allowed change of kernel volume over one time-step # Parameters related to the initial conditions @@ -76,12 +76,21 @@ PointMassPotential: # Isothermal potential parameters IsothermalPotential: - position_x: 100. # Location of centre of isothermal potential (internal units) + position_x: 100. # Location of centre of isothermal potential with respect to centre of the box (internal units) position_y: 100. position_z: 100. vrot: 200. # Rotation speed of isothermal potential (internal units) timestep_mult: 0.03 # Dimensionless pre-factor for the time-step condition +# External potential parameters +SoftenedIsothermalPotential: + position_x: 0. # Location of centre of isothermal potential with respect to centre of the box (internal units) + position_y: 0. + position_z: 0. + vrot: 200. # rotation speed of isothermal potential (internal units) + epsilon: 0.1 # Softening size (internal units) + timestep_mult: 0.03 # controls time step + # Disk-patch potential parameters DiscPatchPotential: surface_density: 10. # Surface density of the disc (internal units) diff --git a/examples/plot_scaling_results.py b/examples/plot_scaling_results.py index 938d204bea8a9da81a93cf2d6d7334ac99d10e3a..26864fe675f502b025f0bf10d73bbba6f8162957 100755 --- a/examples/plot_scaling_results.py +++ b/examples/plot_scaling_results.py @@ -49,7 +49,7 @@ hexcols = ['#332288', '#88CCEE', '#44AA99', '#117733', '#999933', '#DDCC77', '#CC6677', '#882255', '#AA4499', '#661100', '#6699CC', '#AA4466', '#4477AA'] linestyle = (hexcols[0],hexcols[1],hexcols[3],hexcols[5],hexcols[6],hexcols[8]) -#cmdLine = './swift_fixdt -s -t 16 cosmoVolume.yml' +#cmdLine = './swift -s -t 16 cosmoVolume.yml' #platform = 'KNL' # Work out how many data series there are diff --git a/examples/plot_tasks.py b/examples/plot_tasks.py index 7b4683422725f206a3f582e00d82712c7e3c3f59..6295c81a5f2fdb1e726cdf0a8fb43713004800f1 100755 --- a/examples/plot_tasks.py +++ b/examples/plot_tasks.py @@ -56,7 +56,7 @@ pl.rcParams.update(PLOT_PARAMS) # Tasks and subtypes. Indexed as in tasks.h. TASKTYPES = ["none", "sort", "self", "pair", "sub_self", "sub_pair", "init", "ghost", - "extra_ghost", "kick", "kick_fixdt", "send", "recv", + "extra_ghost", "kick", "send", "recv", "grav_gather_m", "grav_fft", "grav_mm", "grav_up", "grav_external", "cooling", "count"] @@ -70,7 +70,6 @@ TASKCOLOURS = {"none": "black", "ghost": "cyan", "extra_ghost": "cyan", "kick": "green", - "kick_fixdt": "green", "send": "yellow", "recv": "magenta", "grav_gather_m": "mediumorchid", diff --git a/examples/plot_tasks_MPI.py b/examples/plot_tasks_MPI.py index 02bc4a03510afce396429316fb4489926bc41b12..734918b8cbf388ef8f1a064e014cfd28775edde2 100755 --- a/examples/plot_tasks_MPI.py +++ b/examples/plot_tasks_MPI.py @@ -64,7 +64,7 @@ pl.rcParams.update(PLOT_PARAMS) # Tasks and subtypes. Indexed as in tasks.h. TASKTYPES = ["none", "sort", "self", "pair", "sub_self", "sub_pair", "init", - "ghost", "extra_ghost", "kick", "kick_fixdt", "send", "recv", + "ghost", "extra_ghost", "kick", "send", "recv", "grav_gather_m", "grav_fft", "grav_mm", "grav_up", "grav_external", "cooling", "count"] @@ -78,7 +78,6 @@ TASKCOLOURS = {"none": "black", "ghost": "cyan", "extra_ghost": "cyan", "kick": "green", - "kick_fixdt": "green", "send": "yellow", "recv": "magenta", "grav_gather_m": "mediumorchid", diff --git a/m4/ax_cc_maxopt.m4 b/m4/ax_cc_maxopt.m4 index d5b87c903c5af46b767d7b49e40963345c8128af..93d5d6dcd78ff77c934f77ad0e1e02ef37873a37 100644 --- a/m4/ax_cc_maxopt.m4 +++ b/m4/ax_cc_maxopt.m4 @@ -160,6 +160,9 @@ if test "$ac_test_CFLAGS" != "set"; then # note that we enable "unsafe" fp optimization with other compilers, too AX_CHECK_COMPILE_FLAG(-ffast-math, CFLAGS="$CFLAGS -ffast-math") + # not all codes will benefit from this. + AX_CHECK_COMPILE_FLAG(-funroll-loops, CFLAGS="$CFLAGS -funroll-loops") + AX_GCC_ARCHFLAG($acx_maxopt_portable) ;; diff --git a/src/Makefile.am b/src/Makefile.am index 34e6e0ea2617474bb3c29482c1779a7af81de2e0..b37d330dbce96f578f88bc95755abdbea3c08e75 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -60,7 +60,7 @@ AM_SOURCES = space.c runner.c queue.c task.c cell.c engine.c \ nobase_noinst_HEADERS = align.h approx_math.h atomic.h cbrt.h cycle.h error.h inline.h kernel_hydro.h kernel_gravity.h \ kernel_long_gravity.h vector.h runner_doiact.h runner_doiact_grav.h runner_doiact_fft.h \ units.h intrinsics.h minmax.h kick.h timestep.h drift.h adiabatic_index.h io_properties.h \ - dimension.h equation_of_state.h \ + dimension.h equation_of_state.h active.h \ gravity.h gravity_io.h \ gravity/Default/gravity.h gravity/Default/gravity_iact.h gravity/Default/gravity_io.h \ gravity/Default/gravity_debug.h gravity/Default/gravity_part.h \ @@ -80,6 +80,7 @@ nobase_noinst_HEADERS = align.h approx_math.h atomic.h cbrt.h cycle.h error.h in riemann/riemann_exact.h riemann/riemann_vacuum.h \ potential/none/potential.h potential/point_mass/potential.h \ potential/isothermal/potential.h potential/disc_patch/potential.h \ + potential/softened_isothermal/potential.h \ cooling/none/cooling.h cooling/none/cooling_struct.h \ cooling/const_du/cooling.h cooling/const_du/cooling_struct.h \ cooling/const_lambda/cooling.h cooling/const_lambda/cooling_struct.h diff --git a/src/active.h b/src/active.h new file mode 100644 index 0000000000000000000000000000000000000000..17adfd07d2bfe0519f0b432217d5253de13c4b78 --- /dev/null +++ b/src/active.h @@ -0,0 +1,104 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2016 Matthieu Schaller (matthieu.schaller@durham.ac.uk) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ +#ifndef SWIFT_ACTIVE_H +#define SWIFT_ACTIVE_H + +/* Config parameters. */ +#include "../config.h" + +/* Local includes. */ +#include "cell.h" +#include "const.h" +#include "engine.h" +#include "part.h" + +/** + * @brief Does a cell contain any active particle ? + * + * @param c The #cell. + * @param e The #engine containing information about the current time. + */ +__attribute__((always_inline)) INLINE static int cell_is_active( + const struct cell *c, const struct engine *e) { + +#ifdef SWIFT_DEBUG_CHECKS + if (c->ti_end_min < e->ti_current) + error("cell in an impossible time-zone! c->ti_end_min=%d e->ti_current=%d", + c->ti_end_min, e->ti_current); +#endif + + return (c->ti_end_min == e->ti_current); +} + +/** + * @brief Are *all* particles in a cell active ? + * + * @param c The #cell. + * @param e The #engine containing information about the current time. + */ +__attribute__((always_inline)) INLINE static int cell_is_all_active( + const struct cell *c, const struct engine *e) { + +#ifdef SWIFT_DEBUG_CHECKS + if (c->ti_end_max < e->ti_current) + error("cell in an impossible time-zone! c->ti_end_max=%d e->ti_current=%d", + c->ti_end_max, e->ti_current); +#endif + + return (c->ti_end_max == e->ti_current); +} + +/** + * @brief Is this particle active ? + * + * @param p The #part. + * @param e The #engine containing information about the current time. + */ +__attribute__((always_inline)) INLINE static int part_is_active( + const struct part *p, const struct engine *e) { + +#ifdef SWIFT_DEBUG_CHECKS + if (p->ti_end < e->ti_current) + error("particle in an impossible time-zone! p->ti_end=%d e->ti_current=%d", + p->ti_end, e->ti_current); +#endif + + return (p->ti_end == e->ti_current); +} + +/** + * @brief Is this g-particle active ? + * + * @param gp The #gpart. + * @param e The #engine containing information about the current time. + */ +__attribute__((always_inline)) INLINE static int gpart_is_active( + const struct gpart *gp, const struct engine *e) { + +#ifdef SWIFT_DEBUG_CHECKS + if (gp->ti_end < e->ti_current) + error( + "g-particle in an impossible time-zone! gp->ti_end=%d e->ti_current=%d", + gp->ti_end, e->ti_current); +#endif + + return (gp->ti_end == e->ti_current); +} + +#endif /* SWIFT_ACTIVE_H */ diff --git a/src/cell.c b/src/cell.c index a54906d667dd312fd35a7584047113a45183b46c..878401d770ca4a7787056a25da6d3b60d4313f2f 100644 --- a/src/cell.c +++ b/src/cell.c @@ -47,6 +47,7 @@ #include "cell.h" /* Local headers. */ +#include "active.h" #include "atomic.h" #include "error.h" #include "gravity.h" @@ -757,16 +758,26 @@ void cell_convert_hydro(struct cell *c, void *data) { */ void cell_clean_links(struct cell *c, void *data) { c->density = NULL; - c->nr_density = 0; - c->gradient = NULL; - c->nr_gradient = 0; - c->force = NULL; - c->nr_force = 0; - c->grav = NULL; - c->nr_grav = 0; +} + +/** + * @brief Checks that a cell is at the current point in time + * + * Calls error() if the cell is not at the current time. + * + * @param c Cell to act upon + * @param data The current time on the integer time-line + */ +void cell_check_drift_point(struct cell *c, void *data) { + + const int ti_current = *(int *)data; + + if (c->ti_old != ti_current) + error("Cell in an incorrect time-zone! c->ti_old=%d ti_current=%d", + c->ti_old, ti_current); } /** @@ -793,7 +804,7 @@ int cell_are_neighbours(const struct cell *restrict ci, for (int k = 0; k < 3; k++) { const double center_i = ci->loc[k]; const double center_j = cj->loc[k]; - if (fabsf(center_i - center_j) > min_dist) return 0; + if (fabs(center_i - center_j) > min_dist) return 0; } return 1; @@ -823,7 +834,7 @@ void cell_check_multipole(struct cell *c, void *data) { mb.mass); for (int k = 0; k < 3; ++k) - if (fabsf(ma.CoM[k] - mb.CoM[k]) / fabsf(ma.CoM[k] + mb.CoM[k]) > 1e-5) + if (fabs(ma.CoM[k] - mb.CoM[k]) / fabs(ma.CoM[k] + mb.CoM[k]) > 1e-5) error("Multipole CoM are different (%12.15e vs. %12.15e", ma.CoM[k], mb.CoM[k]); @@ -874,14 +885,14 @@ void cell_clean(struct cell *c) { * @brief Checks whether a given cell needs drifting or not. * * @param c the #cell. - * @param ti_current The current time on the integer time-line. + * @param e The #engine (holding current time information). * * @return 1 If the cell needs drifting, 0 otherwise. */ -int cell_is_drift_needed(struct cell *c, int ti_current) { +int cell_is_drift_needed(struct cell *c, const struct engine *e) { /* Do we have at least one active particle in the cell ?*/ - if (c->ti_end_min == ti_current) return 1; + if (cell_is_active(c, e)) return 1; /* Loop over the pair tasks that involve this cell */ for (struct link *l = c->density; l != NULL; l = l->next) { @@ -889,9 +900,9 @@ int cell_is_drift_needed(struct cell *c, int ti_current) { if (l->t->type != task_type_pair && l->t->type != task_type_sub_pair) continue; - /* Does the other cell in the pair have an active particle ? */ - if ((l->t->ci == c && l->t->cj->ti_end_min == ti_current) || - (l->t->cj == c && l->t->ci->ti_end_min == ti_current)) + /* Is the other cell in the pair active ? */ + if ((l->t->ci == c && cell_is_active(l->t->cj, e)) || + (l->t->cj == c && cell_is_active(l->t->ci, e))) return 1; } diff --git a/src/cell.h b/src/cell.h index ae22de0cb268bb5240c480b2eed9435ec218adf8..eefb2114cde1705ab4e4c59f4b837bddeb093e2b 100644 --- a/src/cell.h +++ b/src/cell.h @@ -37,6 +37,7 @@ #include "task.h" /* Avoid cyclic inclusions */ +struct engine; struct space; struct scheduler; @@ -79,127 +80,191 @@ struct pcell { } SWIFT_STRUCT_ALIGN; -/* Structure to store the data of a single cell. */ +/** + * @brief Cell within the tree structure. + * + * Contains particles, links to tasks, a multipole object and counters. + */ struct cell { - /* The cell location on the grid. */ + /*! This cell's multipole. */ + struct multipole multipole; + + /*! The cell location on the grid. */ double loc[3]; - /* The cell dimensions. */ + /*! The cell dimensions. */ double width[3]; - /* Max smoothing length in this cell. */ + /*! Max smoothing length in this cell. */ double h_max; - /* Minimum and maximum end of time step in this cell. */ - int ti_end_min, ti_end_max; - - /* Last time the cell's content was drifted forward in time. */ - int ti_old; - - /* Minimum dimension, i.e. smallest edge of this cell. */ - float dmin; - - /* Maximum slack allowed for particle movement. */ - float slack; - - /* Maximum particle movement in this cell since last construction. */ - float dx_max; - - /* The depth of this cell in the tree. */ - int depth, split, maxdepth; - - /* Nr of parts. */ - int count, gcount; + /*! Linking pointer for "memory management". */ + struct cell *next; - /* Pointers to the particle data. */ + /*! Pointer to the #part data. */ struct part *parts; - /* Pointers to the extra particle data. */ + /*! Pointer to the #xpart data. */ struct xpart *xparts; - /* Pointers to the gravity particle data. */ + /*! Pointer to the #gpart data. */ struct gpart *gparts; - /* Pointers for the sorted indices. */ + /*! Pointer for the sorted indices. */ struct entry *sort; - unsigned int sorted; - /* Pointers to the next level of cells. */ + /*! Pointers to the next level of cells. */ struct cell *progeny[8]; - /* Parent cell. */ + /*! Parent cell. */ struct cell *parent; - /* Super cell, i.e. the highest-level supercell that has pair/self tasks */ + /*! Super cell, i.e. the highest-level parent cell that has pair/self tasks */ struct cell *super; - /* The task computing this cell's sorts. */ + /*! The task computing this cell's sorts. */ struct task *sorts; - int sortsize; - /* The tasks computing this cell's density. */ - struct link *density, *gradient, *force, *grav; - int nr_density, nr_gradient, nr_force, nr_grav; + /*! Linked list of the tasks computing this cell's hydro density. */ + struct link *density; - /* The hierarchical tasks. */ - struct task *extra_ghost, *ghost, *init, *kick; + /* Linked list of the tasks computing this cell's hydro gradients. */ + struct link *gradient; -#ifdef WITH_MPI + /*! Linked list of the tasks computing this cell's hydro forces. */ + struct link *force; - /* Task receiving data. */ - struct task *recv_xv, *recv_rho, *recv_gradient, *recv_ti; + /*! Linked list of the tasks computing this cell's gravity forces. */ + struct link *grav; - /* Task send data. */ - struct link *send_xv, *send_rho, *send_gradient, *send_ti; + /*! The initialistation task */ + struct task *init; -#endif + /*! The ghost task */ + struct task *ghost; + + /*! The extra ghost task for complex hydro schemes */ + struct task *extra_ghost; + + /*! The kick task */ + struct task *kick; + + /*! Task constructing the multipole from the particles */ + struct task *grav_up; - /* Tasks for gravity tree. */ - struct task *grav_up, *grav_down; + /*! Task propagating the multipole to the particles */ + struct task *grav_down; - /* Task for cooling */ + /*! Task for cooling */ struct task *cooling; - /* Task for source terms */ + /*! Task for source terms */ struct task *sourceterms; - /* Number of tasks that are associated with this cell. */ - int nr_tasks; +#ifdef WITH_MPI - /* Is the data of this cell being used in a sub-cell? */ - int hold, ghold; + /* Task receiving data (positions). */ + struct task *recv_xv; - /* Spin lock for various uses. */ - swift_lock_type lock, glock; + /* Task receiving data (density). */ + struct task *recv_rho; - /* ID of the previous owner, e.g. runner. */ - int owner; + /* Task receiving data (gradient). */ + struct task *recv_gradient; - /* Number of particles updated in this cell. */ - int updated, g_updated; + /* Task receiving data (time-step). */ + struct task *recv_ti; - /* Linking pointer for "memory management". */ - struct cell *next; + /* Linked list for sending data (positions). */ + struct link *send_xv; - /* This cell's multipole. */ - struct multipole multipole; + /* Linked list for sending data (density). */ + struct link *send_rho; - /* ID of the node this cell lives on. */ - int nodeID; + /* Linked list for sending data (gradient). */ + struct link *send_gradient; -#ifdef WITH_MPI + /* Linked list for sending data (time-step). */ + struct link *send_ti; - /* Bit mask of the proxies this cell is registered with. */ + /*! Bit mask of the proxies this cell is registered with. */ unsigned long long int sendto; - /* Pointer to this cell's packed representation. */ + /*! Pointer to this cell's packed representation. */ struct pcell *pcell; + + /*! Size of the packed representation */ int pcell_size; + + /*! MPI tag associated with this cell */ int tag; #endif + /*! Minimum end of (integer) time step in this cell. */ + int ti_end_min; + + /*! Maximum end of (integer) time step in this cell. */ + int ti_end_max; + + /*! Last (integer) time the cell's content was drifted forward in time. */ + int ti_old; + + /*! Minimum dimension, i.e. smallest edge of this cell (min(width)). */ + float dmin; + + /*! Maximum particle movement in this cell since last construction. */ + float dx_max; + + /*! Nr of #part in this cell. */ + int count; + + /*! Nr of #gpart in this cell. */ + int gcount; + + /*! The size of the sort array */ + int sortsize; + + /*! Bit-mask indicating the sorted directions */ + unsigned int sorted; + + /*! Spin lock for various uses (#part case). */ + swift_lock_type lock; + + /*! Spin lock for various uses (#gpart case). */ + swift_lock_type glock; + + /*! ID of the previous owner, e.g. runner. */ + int owner; + + /*! Number of #part updated in this cell. */ + int updated; + + /*! Number of #gpart updated in this cell. */ + int g_updated; + + /*! ID of the node this cell lives on. */ + int nodeID; + + /*! Is the #part data of this cell being used in a sub-cell? */ + int hold; + + /*! Is the #gpart data of this cell being used in a sub-cell? */ + int ghold; + + /*! Number of tasks that are associated with this cell. */ + short int nr_tasks; + + /*! The depth of this cell in the tree. */ + char depth; + + /*! Is this cell split ? */ + char split; + + /*! The maximal depth of this cell and its progenies */ + char maxdepth; + } SWIFT_STRUCT_ALIGN; /* Convert cell location to ID. */ @@ -226,7 +291,8 @@ int cell_are_neighbours(const struct cell *restrict ci, const struct cell *restrict cj); void cell_check_multipole(struct cell *c, void *data); void cell_clean(struct cell *c); -int cell_is_drift_needed(struct cell *c, int ti_current); +void cell_check_drift_point(struct cell *c, void *data); +int cell_is_drift_needed(struct cell *c, const struct engine *e); int cell_unskip_tasks(struct cell *c, struct scheduler *s); void cell_set_super(struct cell *c, struct cell *super); diff --git a/src/const.h b/src/const.h index 11ee65bfdfabbf43962c721b8599928c25fef7cc..740122547fe38372e33219735115edec11b6c413 100644 --- a/src/const.h +++ b/src/const.h @@ -94,6 +94,7 @@ #define EXTERNAL_POTENTIAL_NONE //#define EXTERNAL_POTENTIAL_POINTMASS //#define EXTERNAL_POTENTIAL_ISOTHERMALPOTENTIAL +//#define EXTERNAL_POTENTIAL_SOFTENED_ISOTHERMAL_POTENTIAL //#define EXTERNAL_POTENTIAL_DISC_PATCH /* Source terms */ diff --git a/src/cooling/const_du/cooling.h b/src/cooling/const_du/cooling.h index b25980ff2269ca9ea176edcc2a3c771647819133..448af9c3765e3bb6d4cbf4cc94e245a3976d5314 100644 --- a/src/cooling/const_du/cooling.h +++ b/src/cooling/const_du/cooling.h @@ -103,7 +103,7 @@ __attribute__((always_inline)) INLINE static float cooling_timestep( const float cooling_rate = cooling->cooling_rate; const float internal_energy = hydro_get_internal_energy(p, 0); - return cooling->cooling_tstep_mult * internal_energy / cooling_rate; + return cooling->cooling_tstep_mult * internal_energy / fabsf(cooling_rate); } /** diff --git a/src/cooling/const_lambda/cooling.h b/src/cooling/const_lambda/cooling.h index 11cf2cae51f1ab2646d1391d2164c399c77a7bba..cb9db2dc34a6014ea15a24d368a006fee3838d67 100644 --- a/src/cooling/const_lambda/cooling.h +++ b/src/cooling/const_lambda/cooling.h @@ -24,6 +24,7 @@ #define SWIFT_COOLING_CONST_LAMBDA_H /* Some standard headers. */ +#include <float.h> #include <math.h> /* Local includes. */ @@ -47,29 +48,16 @@ __attribute__((always_inline)) INLINE static float cooling_rate( const struct phys_const* const phys_const, const struct UnitSystem* us, const struct cooling_function_data* cooling, const struct part* p) { - /* Get particle properties */ - /* Density */ + /* Get particle density */ const float rho = hydro_get_density(p); + /* Get cooling function properties */ const float X_H = cooling->hydrogen_mass_abundance; - /* lambda should always be set in cgs units */ - const float lambda_cgs = cooling->lambda; - - /*convert from internal code units to cgs*/ - const float rho_cgs = - rho * units_cgs_conversion_factor(us, UNIT_CONV_DENSITY); - const float m_p_cgs = phys_const->const_proton_mass * - units_cgs_conversion_factor(us, UNIT_CONV_MASS); - const float n_H_cgs = X_H * rho_cgs / m_p_cgs; /* Calculate du_dt */ - const float du_dt_cgs = -lambda_cgs * n_H_cgs * n_H_cgs / rho_cgs; - - /* Convert du/dt back to internal code units */ - const float du_dt = - du_dt_cgs * units_cgs_conversion_factor(us, UNIT_CONV_TIME) / - units_cgs_conversion_factor(us, UNIT_CONV_ENERGY_PER_UNIT_MASS); - + const float du_dt = -cooling->lambda * + (X_H * rho / phys_const->const_proton_mass) * + (X_H * rho / phys_const->const_proton_mass) / rho; return du_dt; } @@ -97,7 +85,7 @@ __attribute__((always_inline)) INLINE static void cooling_cool_part( /* Calculate du_dt */ const float du_dt = cooling_rate(phys_const, us, cooling, p); - /* Intergrate cooling equation, but enforce energy floor */ + /* Integrate cooling equation, but enforce energy floor */ float u_new; if (u_old + du_dt * dt > u_floor) { u_new = u_old + du_dt * dt; @@ -105,16 +93,12 @@ __attribute__((always_inline)) INLINE static void cooling_cool_part( u_new = u_floor; } + /* Don't allow particle to cool too much in one timestep */ + if (u_new < 0.5f * u_old) u_new = 0.5f * u_old; + /* Update the internal energy */ hydro_set_internal_energy(p, u_new); - /* if (-(u_new_test - u_old) / u_old > 1.0e-6) */ - /* error( */ - /* "Particle has not successfully cooled: u_old = %g , du_dt = %g , dt = - * " */ - /* "%g, du_dt*dt = %g, u_old + du_dt*dt = %g, u_new = %g\n", */ - /* u_old, du_dt, dt, du_dt * dt, u_new, u_new_test); */ - /* Store the radiated energy */ xp->cooling_data.radiated_energy += hydro_get_mass(p) * (u_old - u_new); } @@ -132,13 +116,16 @@ __attribute__((always_inline)) INLINE static float cooling_timestep( const struct phys_const* restrict phys_const, const struct UnitSystem* restrict us, const struct part* restrict p) { - /* Get du_dt */ - const float du_dt = cooling_rate(phys_const, us, cooling, p); - /* Get current internal energy (dt=0) */ const float u = hydro_get_internal_energy(p, 0.f); + const float du_dt = cooling_rate(phys_const, us, cooling, p); - return u / du_dt; + /* If we are close to (or below) the energy floor, we ignore cooling timestep + */ + if (u < 1.01f * cooling->min_energy) + return FLT_MAX; + else + return cooling->cooling_tstep_mult * u / fabsf(du_dt); } /** @@ -178,9 +165,9 @@ static INLINE void cooling_init_backend( const struct phys_const* phys_const, struct cooling_function_data* cooling) { - cooling->lambda = - parser_get_param_double(parameter_file, "LambdaCooling:lambda"); - cooling->min_temperature = parser_get_param_double( + const double lambda_cgs = + parser_get_param_double(parameter_file, "LambdaCooling:lambda_cgs"); + const float min_temperature = parser_get_param_double( parameter_file, "LambdaCooling:minimum_temperature"); cooling->hydrogen_mass_abundance = parser_get_param_double( parameter_file, "LambdaCooling:hydrogen_mass_abundance"); @@ -189,16 +176,19 @@ static INLINE void cooling_init_backend( cooling->cooling_tstep_mult = parser_get_param_double( parameter_file, "LambdaCooling:cooling_tstep_mult"); - /*convert minimum temperature into minimum internal energy*/ + /* convert minimum temperature into minimum internal energy */ const float u_floor = - phys_const->const_boltzmann_k * cooling->min_temperature / + phys_const->const_boltzmann_k * min_temperature / (hydro_gamma_minus_one * cooling->mean_molecular_weight * phys_const->const_proton_mass); - const float u_floor_cgs = - u_floor * units_cgs_conversion_factor(us, UNIT_CONV_ENERGY_PER_UNIT_MASS); cooling->min_energy = u_floor; - cooling->min_energy_cgs = u_floor_cgs; + + /* convert lambda to code units */ + cooling->lambda = lambda_cgs * + units_cgs_conversion_factor(us, UNIT_CONV_TIME) / + (units_cgs_conversion_factor(us, UNIT_CONV_ENERGY) * + units_cgs_conversion_factor(us, UNIT_CONV_VOLUME)); } /** @@ -211,10 +201,10 @@ static INLINE void cooling_print_backend( message( "Cooling function is 'Constant lambda' with " - "(lambda,min_temperature,hydrogen_mass_abundance,mean_molecular_weight) " + "(lambda,min_energy,hydrogen_mass_abundance,mean_molecular_weight) " "= (%g,%g,%g,%g)", - cooling->lambda, cooling->min_temperature, - cooling->hydrogen_mass_abundance, cooling->mean_molecular_weight); + cooling->lambda, cooling->min_energy, cooling->hydrogen_mass_abundance, + cooling->mean_molecular_weight); } #endif /* SWIFT_COOLING_CONST_LAMBDA_H */ diff --git a/src/cooling/const_lambda/cooling_struct.h b/src/cooling/const_lambda/cooling_struct.h index 27c5df16bffbe7d165237d201ca68ea4ba89dd73..30d4e5e4af9c7bd139337709897d8111f88d2aa8 100644 --- a/src/cooling/const_lambda/cooling_struct.h +++ b/src/cooling/const_lambda/cooling_struct.h @@ -28,21 +28,17 @@ */ struct cooling_function_data { - /*! Cooling rate in cgs units. Defined by 'rho * du/dt = -lambda * n_H^2'*/ - float lambda; + /*! Cooling rate in internal units */ + double lambda; - /*! Minimum temperature (in Kelvin) for all gas particles*/ - float min_temperature; - - /*! Fraction of gas mass that is Hydrogen. Used to calculate n_H*/ + /*! Fraction of gas mass that is Hydrogen. Used to calculate n_H */ float hydrogen_mass_abundance; - /* 'mu', used to convert min_temperature to min_internal energy*/ + /*! 'mu', used to convert min_temperature to min_internal energy */ float mean_molecular_weight; - /*! Minimally allowed internal energy of the particles */ + /*! Minimally allowed internal energy of all the particles */ float min_energy; - float min_energy_cgs; /*! Constant multiplication factor for time-step criterion */ float cooling_tstep_mult; diff --git a/src/debug.c b/src/debug.c index be42485a38ea8d560797e8f1ccc5936456febcd8..7a50368f069deef0c7d77b4ac3407ab059888d68 100644 --- a/src/debug.c +++ b/src/debug.c @@ -171,7 +171,7 @@ int checkSpacehmax(struct space *s) { } /* If within some epsilon we are OK. */ - if (abs(cell_h_max - part_h_max) <= FLT_EPSILON) return 1; + if (fabsf(cell_h_max - part_h_max) <= FLT_EPSILON) return 1; /* There is a problem. Hunt it down. */ for (int k = 0; k < s->nr_cells; k++) { @@ -193,6 +193,60 @@ int checkSpacehmax(struct space *s) { return 0; } +/** + * @brief Check if the h_max and dx_max values of a cell's hierarchy are + * consistent with the particles. Report verbosely if not. + * + * @param c the top cell of the hierarchy. + * @param depth the recursion depth for use in messages. Set to 0 initially. + * @result 1 or 0 + */ +int checkCellhdxmax(const struct cell *c, int *depth) { + + *depth = *depth + 1; + + float h_max = 0.0f; + float dx_max = 0.0f; + if (!c->split) { + const size_t nr_parts = c->count; + struct part *parts = c->parts; + for (size_t k = 0; k < nr_parts; k++) { + h_max = (h_max > parts[k].h) ? h_max : parts[k].h; + } + } else { + for (int k = 0; k < 8; k++) + if (c->progeny[k] != NULL) { + struct cell *cp = c->progeny[k]; + checkCellhdxmax(cp, depth); + dx_max = max(dx_max, cp->dx_max); + h_max = max(h_max, cp->h_max); + } + } + + /* Check. */ + int result = 1; + if (c->h_max != h_max) { + message("%d Inconsistent h_max: cell %f != parts %f", *depth, c->h_max, + h_max); + message("location: %f %f %f", c->loc[0], c->loc[1], c->loc[2]); + result = 0; + } + if (c->dx_max != dx_max) { + message("%d Inconsistent dx_max: %f != %f", *depth, c->dx_max, dx_max); + message("location: %f %f %f", c->loc[0], c->loc[1], c->loc[2]); + result = 0; + } + + /* Check rebuild criterion. */ + if (h_max > c->dmin) { + message("%d Inconsistent c->dmin: %f > %f", *depth, h_max, c->dmin); + message("location: %f %f %f", c->loc[0], c->loc[1], c->loc[2]); + result = 0; + } + + return result; +} + #ifdef HAVE_METIS /** @@ -331,4 +385,47 @@ void dumpMETISGraph(const char *prefix, idx_t nvertices, idx_t nvertexweights, } } -#endif +#endif /* HAVE_METIS */ + +#ifdef HAVE_MPI +/** + * @brief Dump the positions and MPI ranks of the given top-level cells + * to a simple text file. + * + * Can be used to visualise the partitioning of an MPI run. Note should + * be used immediately after repartitioning when the top-level cells + * have been assigned their nodes. Each time this is called a new file + * with the given prefix, a unique integer and type of .dat is created. + * + * @param prefix base output filename + * @param cells_top the top-level cells. + * @param nr_cells the number of cells. + */ +void dumpCellRanks(const char *prefix, struct cell *cells_top, int nr_cells) { + + FILE *file = NULL; + + /* Name of output file. */ + static int nseq = 0; + char fname[200]; + sprintf(fname, "%s_%03d.dat", prefix, nseq); + nseq++; + + file = fopen(fname, "w"); + + /* Header. */ + fprintf(file, "# %6s %6s %6s %6s %6s %6s %6s\n", "x", "y", "z", "xw", "yw", + "zw", "rank"); + + /* Output */ + for (int i = 0; i < nr_cells; i++) { + struct cell *c = &cells_top[i]; + fprintf(file, " %6.3f %6.3f %6.3f %6.3f %6.3f %6.3f %6d\n", c->loc[0], + c->loc[1], c->loc[2], c->width[0], c->width[1], c->width[2], + c->nodeID); + } + + fclose(file); +} + +#endif /* HAVE_MPI */ diff --git a/src/debug.h b/src/debug.h index 2142a22eca91338580d8f50197a57de0cf248bee..7422a6f7f9815490966f08415e0312876ce0123f 100644 --- a/src/debug.h +++ b/src/debug.h @@ -32,11 +32,16 @@ void printParticle_single(const struct part *p, const struct xpart *xp); void printgParticle_single(struct gpart *gp); int checkSpacehmax(struct space *s); +int checkCellhdxmax(const struct cell *c, int *depth); #ifdef HAVE_METIS #include "metis.h" void dumpMETISGraph(const char *prefix, idx_t nvtxs, idx_t ncon, idx_t *xadj, idx_t *adjncy, idx_t *vwgt, idx_t *vsize, idx_t *adjwgt); +#endif +#ifdef HAVE_MPI +void dumpCellRanks(const char *prefix, struct cell *cells_top, int nr_cells); #endif + #endif /* SWIFT_DEBUG_H */ diff --git a/src/engine.c b/src/engine.c index 31927bdbe3ab4501631b2155bb51d4a33b646a7b..e989aefd5343eb7f377c6c1e8bc41f9875f2f42e 100644 --- a/src/engine.c +++ b/src/engine.c @@ -74,7 +74,6 @@ const char *engine_policy_names[16] = {"none", "steal", "keep", "block", - "fix_dt", "cpu_tight", "mpi", "numa_affinity", @@ -126,7 +125,6 @@ void engine_addlink(struct engine *e, struct link **l, struct task *t) { void engine_make_hierarchical_tasks(struct engine *e, struct cell *c) { struct scheduler *s = &e->sched; - const int is_fixdt = (e->policy & engine_policy_fixdt); const int is_hydro = (e->policy & engine_policy_hydro); const int is_with_cooling = (e->policy & engine_policy_cooling); const int is_with_sourceterms = (e->policy & engine_policy_sourceterms); @@ -141,14 +139,8 @@ void engine_make_hierarchical_tasks(struct engine *e, struct cell *c) { c->init = scheduler_addtask(s, task_type_init, task_subtype_none, 0, 0, c, NULL, 0); - /* Add the kick task that matches the policy. */ - if (is_fixdt) { - c->kick = scheduler_addtask(s, task_type_kick_fixdt, task_subtype_none, - 0, 0, c, NULL, 0); - } else { - c->kick = scheduler_addtask(s, task_type_kick, task_subtype_none, 0, 0, - c, NULL, 0); - } + c->kick = scheduler_addtask(s, task_type_kick, task_subtype_none, 0, 0, c, + NULL, 0); /* Generate the ghost task. */ if (is_hydro) @@ -565,6 +557,11 @@ void engine_repartition(struct engine *e) { ticks tic = getticks(); +#ifdef SWIFT_DEBUG_CHECKS + /* Check that all cells have been drifted to the current time */ + space_check_drift_point(e->s, e->ti_current); +#endif + /* Clear the repartition flag. */ enum repartition_type reparttype = e->forcerepart; e->forcerepart = REPART_NONE; @@ -657,9 +654,8 @@ void engine_addtasks_send(struct engine *e, struct cell *ci, struct cell *cj, 4 * ci->tag, 0, ci, cj, 0); t_rho = scheduler_addtask(s, task_type_send, task_subtype_none, 4 * ci->tag + 1, 0, ci, cj, 0); - if (!(e->policy & engine_policy_fixdt)) - t_ti = scheduler_addtask(s, task_type_send, task_subtype_tend, - 4 * ci->tag + 2, 0, ci, cj, 0); + t_ti = scheduler_addtask(s, task_type_send, task_subtype_tend, + 4 * ci->tag + 2, 0, ci, cj, 0); #ifdef EXTRA_HYDRO_LOOP t_gradient = scheduler_addtask(s, task_type_send, task_subtype_none, 4 * ci->tag + 3, 0, ci, cj, 0); @@ -743,9 +739,8 @@ void engine_addtasks_recv(struct engine *e, struct cell *c, struct task *t_xv, 0, c, NULL, 0); t_rho = scheduler_addtask(s, task_type_recv, task_subtype_none, 4 * c->tag + 1, 0, c, NULL, 0); - if (!(e->policy & engine_policy_fixdt)) - t_ti = scheduler_addtask(s, task_type_recv, task_subtype_tend, - 4 * c->tag + 2, 0, c, NULL, 0); + t_ti = scheduler_addtask(s, task_type_recv, task_subtype_tend, + 4 * c->tag + 2, 0, c, NULL, 0); #ifdef EXTRA_HYDRO_LOOP t_gradient = scheduler_addtask(s, task_type_recv, task_subtype_none, 4 * c->tag + 3, 0, c, NULL, 0); @@ -1359,15 +1354,12 @@ void engine_count_and_link_tasks(struct engine *e) { atomic_inc(&ci->nr_tasks); if (t->subtype == task_subtype_density) { engine_addlink(e, &ci->density, t); - atomic_inc(&ci->nr_density); } if (t->subtype == task_subtype_grav) { engine_addlink(e, &ci->grav, t); - atomic_inc(&ci->nr_grav); } if (t->subtype == task_subtype_external_grav) { engine_addlink(e, &ci->grav, t); - atomic_inc(&ci->nr_grav); } /* Link pair tasks to cells. */ @@ -1376,15 +1368,14 @@ void engine_count_and_link_tasks(struct engine *e) { atomic_inc(&cj->nr_tasks); if (t->subtype == task_subtype_density) { engine_addlink(e, &ci->density, t); - atomic_inc(&ci->nr_density); engine_addlink(e, &cj->density, t); - atomic_inc(&cj->nr_density); } if (t->subtype == task_subtype_grav) { engine_addlink(e, &ci->grav, t); - atomic_inc(&ci->nr_grav); engine_addlink(e, &cj->grav, t); - atomic_inc(&cj->nr_grav); + } + if (t->subtype == task_subtype_external_grav) { + error("Found a pair/external-gravity task..."); } /* Link sub-self tasks to cells. */ @@ -1392,15 +1383,12 @@ void engine_count_and_link_tasks(struct engine *e) { atomic_inc(&ci->nr_tasks); if (t->subtype == task_subtype_density) { engine_addlink(e, &ci->density, t); - atomic_inc(&ci->nr_density); } if (t->subtype == task_subtype_grav) { engine_addlink(e, &ci->grav, t); - atomic_inc(&ci->nr_grav); } if (t->subtype == task_subtype_external_grav) { engine_addlink(e, &ci->grav, t); - atomic_inc(&ci->nr_grav); } /* Link sub-pair tasks to cells. */ @@ -1409,22 +1397,14 @@ void engine_count_and_link_tasks(struct engine *e) { atomic_inc(&cj->nr_tasks); if (t->subtype == task_subtype_density) { engine_addlink(e, &ci->density, t); - atomic_inc(&ci->nr_density); engine_addlink(e, &cj->density, t); - atomic_inc(&cj->nr_density); } if (t->subtype == task_subtype_grav) { engine_addlink(e, &ci->grav, t); - atomic_inc(&ci->nr_grav); engine_addlink(e, &cj->grav, t); - atomic_inc(&cj->nr_grav); } if (t->subtype == task_subtype_external_grav) { error("Found a sub-pair/external-gravity task..."); - engine_addlink(e, &ci->grav, t); - atomic_inc(&ci->nr_grav); - engine_addlink(e, &cj->grav, t); - atomic_inc(&cj->nr_grav); } } } @@ -1650,9 +1630,7 @@ void engine_make_extra_hydroloop_tasks(struct engine *e) { /* Add the link between the new loops and the cell */ engine_addlink(e, &t->ci->gradient, t2); - atomic_inc(&t->ci->nr_gradient); engine_addlink(e, &t->ci->force, t3); - atomic_inc(&t->ci->nr_force); /* Now, build all the dependencies for the hydro */ engine_make_hydro_loops_dependencies(sched, t, t2, t3, t->ci); @@ -1665,7 +1643,6 @@ void engine_make_extra_hydroloop_tasks(struct engine *e) { /* Add the link between the new loop and the cell */ engine_addlink(e, &t->ci->force, t2); - atomic_inc(&t->ci->nr_force); /* Now, build all the dependencies for the hydro */ engine_make_hydro_loops_dependencies(sched, t, t2, t->ci); @@ -1684,13 +1661,9 @@ void engine_make_extra_hydroloop_tasks(struct engine *e) { /* Add the link between the new loop and both cells */ engine_addlink(e, &t->ci->gradient, t2); - atomic_inc(&t->ci->nr_gradient); engine_addlink(e, &t->cj->gradient, t2); - atomic_inc(&t->cj->nr_gradient); engine_addlink(e, &t->ci->force, t3); - atomic_inc(&t->ci->nr_force); engine_addlink(e, &t->cj->force, t3); - atomic_inc(&t->cj->nr_force); /* Now, build all the dependencies for the hydro for the cells */ /* that are local and are not descendant of the same super-cells */ @@ -1709,9 +1682,7 @@ void engine_make_extra_hydroloop_tasks(struct engine *e) { /* Add the link between the new loop and both cells */ engine_addlink(e, &t->ci->force, t2); - atomic_inc(&t->ci->nr_force); engine_addlink(e, &t->cj->force, t2); - atomic_inc(&t->cj->nr_force); /* Now, build all the dependencies for the hydro for the cells */ /* that are local and are not descendant of the same super-cells */ @@ -1742,9 +1713,7 @@ void engine_make_extra_hydroloop_tasks(struct engine *e) { /* Add the link between the new loop and the cell */ engine_addlink(e, &t->ci->gradient, t2); - atomic_inc(&t->ci->nr_gradient); engine_addlink(e, &t->ci->force, t3); - atomic_inc(&t->ci->nr_force); /* Now, build all the dependencies for the hydro for the cells */ /* that are local and are not descendant of the same super-cells */ @@ -1760,7 +1729,6 @@ void engine_make_extra_hydroloop_tasks(struct engine *e) { /* Add the link between the new loop and the cell */ engine_addlink(e, &t->ci->force, t2); - atomic_inc(&t->ci->nr_force); /* Now, build all the dependencies for the hydro for the cells */ /* that are local and are not descendant of the same super-cells */ @@ -1786,13 +1754,9 @@ void engine_make_extra_hydroloop_tasks(struct engine *e) { /* Add the link between the new loop and both cells */ engine_addlink(e, &t->ci->gradient, t2); - atomic_inc(&t->ci->nr_gradient); engine_addlink(e, &t->cj->gradient, t2); - atomic_inc(&t->cj->nr_gradient); engine_addlink(e, &t->ci->force, t3); - atomic_inc(&t->ci->nr_force); engine_addlink(e, &t->cj->force, t3); - atomic_inc(&t->cj->nr_force); /* Now, build all the dependencies for the hydro for the cells */ /* that are local and are not descendant of the same super-cells */ @@ -1811,9 +1775,7 @@ void engine_make_extra_hydroloop_tasks(struct engine *e) { /* Add the link between the new loop and both cells */ engine_addlink(e, &t->ci->force, t2); - atomic_inc(&t->ci->nr_force); engine_addlink(e, &t->cj->force, t2); - atomic_inc(&t->cj->nr_force); /* Now, build all the dependencies for the hydro for the cells */ /* that are local and are not descendant of the same super-cells */ @@ -1993,52 +1955,6 @@ void engine_maketasks(struct engine *e) { clocks_from_ticks(getticks() - tic), clocks_getunit()); } -/** - * @brief Mark tasks to be un-skipped and set the sort flags accordingly. - * Threadpool mapper function for fixdt version. - * - * @param map_data pointer to the tasks - * @param num_elements number of tasks - * @param extra_data pointer to int that will define if a rebuild is needed. - */ -void engine_marktasks_fixdt_mapper(void *map_data, int num_elements, - void *extra_data) { - /* Unpack the arguments. */ - struct task *tasks = (struct task *)map_data; - size_t *rebuild_space = &((size_t *)extra_data)[0]; - struct scheduler *s = (struct scheduler *)(((size_t *)extra_data)[1]); - - for (int ind = 0; ind < num_elements; ind++) { - struct task *t = &tasks[ind]; - - /* All tasks are unskipped (we skip by default). */ - scheduler_activate(s, t); - - /* Pair? */ - if (t->type == task_type_pair || t->type == task_type_sub_pair) { - - /* Local pointers. */ - const struct cell *ci = t->ci; - const struct cell *cj = t->cj; - - /* Too much particle movement? */ - if (t->tight && - (max(ci->h_max, cj->h_max) + ci->dx_max + cj->dx_max > cj->dmin || - ci->dx_max > space_maxreldx * ci->h_max || - cj->dx_max > space_maxreldx * cj->h_max)) - *rebuild_space = 1; - - } - - /* Sort? */ - else if (t->type == task_type_sort) { - - /* If all the sorts have been done, make this task implicit. */ - if (!(t->flags & (t->flags ^ t->ci->sorted))) t->implicit = 1; - } - } -} - /** * @brief Mark tasks to be un-skipped and set the sort flags accordingly. * Threadpool mapper function. @@ -2194,24 +2110,11 @@ int engine_marktasks(struct engine *e) { const ticks tic = getticks(); int rebuild_space = 0; - /* Much less to do here if we're on a fixed time-step. */ - if (e->policy & engine_policy_fixdt) { - - /* Run through the tasks and mark as skip or not. */ - size_t extra_data[2] = {rebuild_space, (size_t)&e->sched}; - threadpool_map(&e->threadpool, engine_marktasks_fixdt_mapper, s->tasks, - s->nr_tasks, sizeof(struct task), 1000, extra_data); - return rebuild_space; - - /* Multiple-timestep case */ - } else { - - /* Run through the tasks and mark as skip or not. */ - size_t extra_data[3] = {e->ti_current, rebuild_space, (size_t)&e->sched}; - threadpool_map(&e->threadpool, engine_marktasks_mapper, s->tasks, - s->nr_tasks, sizeof(struct task), 10000, extra_data); - rebuild_space = extra_data[1]; - } + /* Run through the tasks and mark as skip or not. */ + size_t extra_data[3] = {e->ti_current, rebuild_space, (size_t)&e->sched}; + threadpool_map(&e->threadpool, engine_marktasks_mapper, s->tasks, s->nr_tasks, + sizeof(struct task), 10000, extra_data); + rebuild_space = extra_data[1]; if (e->verbose) message("took %.3f %s.", clocks_from_ticks(getticks() - tic), @@ -2275,9 +2178,10 @@ void engine_rebuild(struct engine *e) { e->forcerebuild = 0; /* Re-build the space. */ - space_rebuild(e->s, 0.0, e->verbose); + space_rebuild(e->s, e->verbose); - if (e->ti_current == 0) space_sanitize(e->s); + /* Initial cleaning up session ? */ + if (e->s->sanitized == 0) space_sanitize(e->s); /* If in parallel, exchange the cell structure. */ #ifdef WITH_MPI @@ -2335,6 +2239,11 @@ void engine_prepare(struct engine *e, int nodrift) { e->drift_all = (e->policy & engine_policy_drift_all); } +#ifdef SWIFT_DEBUG_CHECKS + /* Check that all cells have been drifted to the current time */ + space_check_drift_point(e->s, e->ti_current); +#endif + engine_rebuild(e); } @@ -2347,7 +2256,7 @@ void engine_prepare(struct engine *e, int nodrift) { TIMER_TOC(timer_prepare); if (e->verbose) - message("took %.3f %s (including marktask, rebuild and reweight).", + message("took %.3f %s (including drift all, rebuild and reweight).", clocks_from_ticks(getticks() - tic), clocks_getunit()); } @@ -2535,16 +2444,34 @@ void engine_print_stats(struct engine *e) { clocks_getunit()); } +/** + * @brief Sets all the force and kick tasks to be skipped. + * + * @param e The #engine to act on. + */ +void engine_skip_force_and_kick(struct engine *e) { + + struct task *tasks = e->sched.tasks; + const int nr_tasks = e->sched.nr_tasks; + + for (int i = 0; i < nr_tasks; ++i) { + + struct task *t = &tasks[i]; + + /* Skip everything that updates the particles */ + if (t->subtype == task_subtype_force || t->type == task_type_kick || + t->type == task_type_cooling || t->type == task_type_sourceterms) + t->skip = 1; + } +} + /** * @brief Launch the runners. * * @param e The #engine. * @param nr_runners The number of #runner to let loose. - * @param mask The task mask to launch. - * @param submask The sub-task mask to launch. */ -void engine_launch(struct engine *e, int nr_runners, unsigned int mask, - unsigned int submask) { +void engine_launch(struct engine *e, int nr_runners) { const ticks tic = getticks(); @@ -2559,7 +2486,7 @@ void engine_launch(struct engine *e, int nr_runners, unsigned int mask, /* Load the tasks. */ pthread_mutex_unlock(&e->barrier_mutex); - scheduler_start(&e->sched, mask, submask); + scheduler_start(&e->sched); pthread_mutex_lock(&e->barrier_mutex); /* Remove the safeguard. */ @@ -2599,61 +2526,12 @@ void engine_init_particles(struct engine *e, int flag_entropy_ICs) { engine_marktasks(e); - /* Build the masks corresponding to the policy */ - unsigned int mask = 0; - unsigned int submask = 0; - - /* We always have sort tasks */ - mask |= 1 << task_type_sort; - mask |= 1 << task_type_init; - - /* Add the tasks corresponding to hydro operations to the masks */ - if (e->policy & engine_policy_hydro) { - - mask |= 1 << task_type_self; - mask |= 1 << task_type_pair; - mask |= 1 << task_type_sub_self; - mask |= 1 << task_type_sub_pair; - mask |= 1 << task_type_ghost; - - submask |= 1 << task_subtype_density; - } - - /* Add the tasks corresponding to self-gravity to the masks */ - if (e->policy & engine_policy_self_gravity) { - - mask |= 1 << task_type_grav_up; - mask |= 1 << task_type_grav_mm; - mask |= 1 << task_type_grav_gather_m; - mask |= 1 << task_type_grav_fft; - mask |= 1 << task_type_self; - mask |= 1 << task_type_pair; - mask |= 1 << task_type_sub_self; - mask |= 1 << task_type_sub_pair; - - submask |= 1 << task_subtype_grav; - } - - /* Add the tasks corresponding to external gravity to the masks */ - if (e->policy & engine_policy_external_gravity) { - - mask |= 1 << task_type_self; - mask |= 1 << task_type_sub_self; - - submask |= 1 << task_subtype_external_grav; - } - - /* Add MPI tasks if need be */ - if (e->policy & engine_policy_mpi) { - - mask |= 1 << task_type_send; - mask |= 1 << task_type_recv; - submask |= 1 << task_subtype_tend; - } + /* No time integration. We just want the density and ghosts */ + engine_skip_force_and_kick(e); /* Now, launch the calculation */ TIMER_TIC; - engine_launch(e, e->nr_threads, mask, submask); + engine_launch(e, e->nr_threads); TIMER_TOC(timer_runners); /* Apply some conversions (e.g. internal energy -> entropy) */ @@ -2663,14 +2541,18 @@ void engine_init_particles(struct engine *e, int flag_entropy_ICs) { space_map_cells_pre(s, 0, cell_convert_hydro, NULL); /* Correct what we did (e.g. in PE-SPH, need to recompute rho_bar) */ - if (hydro_need_extra_init_loop) - engine_launch(e, e->nr_threads, mask, submask); + if (hydro_need_extra_init_loop) { + engine_marktasks(e); + engine_skip_force_and_kick(e); + engine_launch(e, e->nr_threads); + } } clocks_gettime(&time2); /* Ready to go */ e->step = -1; + e->forcerebuild = 1; e->wallclock_time = (float)clocks_diff(&time1, &time2); if (e->verbose) message("took %.3f %s.", e->wallclock_time, clocks_getunit()); @@ -2741,7 +2623,7 @@ void engine_step(struct engine *e) { /* Drift only the necessary particles, that means all particles * if we are about to repartition. */ - int repart = (e->forcerepart != REPART_NONE); + const int repart = (e->forcerepart != REPART_NONE); e->drift_all = repart || e->drift_all; engine_drift(e); @@ -2754,85 +2636,11 @@ void engine_step(struct engine *e) { /* Restore the default drifting policy */ e->drift_all = (e->policy & engine_policy_drift_all); - /* Build the masks corresponding to the policy */ - unsigned int mask = 0, submask = 0; - - /* We always have sort tasks and init tasks */ - mask |= 1 << task_type_sort; - mask |= 1 << task_type_init; - - /* Add the correct kick task */ - if (e->policy & engine_policy_fixdt) { - mask |= 1 << task_type_kick_fixdt; - } else { - mask |= 1 << task_type_kick; - } - - /* Add the tasks corresponding to hydro operations to the masks */ - if (e->policy & engine_policy_hydro) { - - mask |= 1 << task_type_self; - mask |= 1 << task_type_pair; - mask |= 1 << task_type_sub_self; - mask |= 1 << task_type_sub_pair; - mask |= 1 << task_type_ghost; - - submask |= 1 << task_subtype_density; - submask |= 1 << task_subtype_force; - -#ifdef EXTRA_HYDRO_LOOP - mask |= 1 << task_type_extra_ghost; - submask |= 1 << task_subtype_gradient; -#endif - } - - /* Add the tasks corresponding to self-gravity to the masks */ - if (e->policy & engine_policy_self_gravity) { - - mask |= 1 << task_type_grav_up; - mask |= 1 << task_type_grav_mm; - mask |= 1 << task_type_grav_gather_m; - mask |= 1 << task_type_grav_fft; - mask |= 1 << task_type_self; - mask |= 1 << task_type_pair; - mask |= 1 << task_type_sub_self; - mask |= 1 << task_type_sub_pair; - - submask |= 1 << task_subtype_grav; - } - - /* Add the tasks corresponding to external gravity to the masks */ - if (e->policy & engine_policy_external_gravity) { - - mask |= 1 << task_type_self; - mask |= 1 << task_type_sub_self; - - submask |= 1 << task_subtype_external_grav; - } - - /* Add the tasks corresponding to cooling to the masks */ - if (e->policy & engine_policy_cooling) { - mask |= 1 << task_type_cooling; - } - - /* Add the tasks corresponding to sourceterms to the masks */ - if (e->policy & engine_policy_sourceterms) { - mask |= 1 << task_type_sourceterms; - } - - /* Add MPI tasks if need be */ - if (e->policy & engine_policy_mpi) { - - mask |= 1 << task_type_send; - mask |= 1 << task_type_recv; - submask |= 1 << task_subtype_tend; - } - if (e->verbose) engine_print_task_counts(e); /* Send off the runners. */ TIMER_TIC; - engine_launch(e, e->nr_threads, mask, submask); + engine_launch(e, e->nr_threads); TIMER_TOC(timer_runners); /* Save some statistics */ @@ -3386,9 +3194,10 @@ void engine_init(struct engine *e, struct space *s, e->file_stats = fopen(energyfileName, "w"); fprintf(e->file_stats, "#%14s %14s %14s %14s %14s %14s %14s %14s %14s %14s %14s %14s %14s " - "%14s\n", - "Time", "Mass", "E_tot", "E_kin", "E_int", "E_pot", "E_radcool", - "Entropy", "p_x", "p_y", "p_z", "ang_x", "ang_y", "ang_z"); + "%14s %14s %14s\n", + "Time", "Mass", "E_tot", "E_kin", "E_int", "E_pot", "E_pot_self", + "E_pot_ext", "E_radcool", "Entropy", "p_x", "p_y", "p_z", "ang_x", + "ang_y", "ang_z"); fflush(e->file_stats); char timestepsfileName[200] = ""; @@ -3443,32 +3252,19 @@ void engine_init(struct engine *e, struct space *s, e->timeBase_inv = 1.0 / e->timeBase; e->ti_current = 0; - /* Fixed time-step case */ - if (e->policy & engine_policy_fixdt) { - e->dt_min = e->dt_max; - - /* Find timestep on the timeline */ - int dti_timeline = max_nr_timesteps; - while (e->dt_min < dti_timeline * e->timeBase) dti_timeline /= 2; - - e->dt_min = e->dt_max = dti_timeline * e->timeBase; - - if (e->nodeID == 0) message("Timestep set to %e", e->dt_max); - } else { - - if (e->nodeID == 0) { - message("Absolute minimal timestep size: %e", e->timeBase); + /* Info about time-steps */ + if (e->nodeID == 0) { + message("Absolute minimal timestep size: %e", e->timeBase); - float dt_min = e->timeEnd - e->timeBegin; - while (dt_min > e->dt_min) dt_min /= 2.f; + float dt_min = e->timeEnd - e->timeBegin; + while (dt_min > e->dt_min) dt_min /= 2.f; - message("Minimal timestep size (on time-line): %e", dt_min); + message("Minimal timestep size (on time-line): %e", dt_min); - float dt_max = e->timeEnd - e->timeBegin; - while (dt_max > e->dt_max) dt_max /= 2.f; + float dt_max = e->timeEnd - e->timeBegin; + while (dt_max > e->dt_max) dt_max /= 2.f; - message("Maximal timestep size (on time-line): %e", dt_max); - } + message("Maximal timestep size (on time-line): %e", dt_max); } if (e->dt_min < e->timeBase && e->nodeID == 0) diff --git a/src/engine.h b/src/engine.h index ec9e16553c3172f22e9bfe60971163488947a47e..861e321627032eb1f773992a9c123249c013daa0 100644 --- a/src/engine.h +++ b/src/engine.h @@ -56,17 +56,16 @@ enum engine_policy { engine_policy_steal = (1 << 1), engine_policy_keep = (1 << 2), engine_policy_block = (1 << 3), - engine_policy_fixdt = (1 << 4), - engine_policy_cputight = (1 << 5), - engine_policy_mpi = (1 << 6), - engine_policy_setaffinity = (1 << 7), - engine_policy_hydro = (1 << 8), - engine_policy_self_gravity = (1 << 9), - engine_policy_external_gravity = (1 << 10), - engine_policy_cosmology = (1 << 11), - engine_policy_drift_all = (1 << 12), - engine_policy_cooling = (1 << 13), - engine_policy_sourceterms = (1 << 14) + engine_policy_cputight = (1 << 4), + engine_policy_mpi = (1 << 5), + engine_policy_setaffinity = (1 << 6), + engine_policy_hydro = (1 << 7), + engine_policy_self_gravity = (1 << 8), + engine_policy_external_gravity = (1 << 9), + engine_policy_cosmology = (1 << 10), + engine_policy_drift_all = (1 << 11), + engine_policy_cooling = (1 << 12), + engine_policy_sourceterms = (1 << 13) }; extern const char *engine_policy_names[]; @@ -230,8 +229,7 @@ void engine_init(struct engine *e, struct space *s, const struct external_potential *potential, const struct cooling_function_data *cooling, struct sourceterms *sourceterms); -void engine_launch(struct engine *e, int nr_runners, unsigned int mask, - unsigned int submask); +void engine_launch(struct engine *e, int nr_runners); void engine_prepare(struct engine *e, int nodrift); void engine_print(struct engine *e); void engine_init_particles(struct engine *e, int flag_entropy_ICs); diff --git a/src/error.h b/src/error.h index b131cb124feedc48e83427122f3a0edcb2ec81d4..92a9ce71a3d939cb2e18267848b0e2c66dd4741a 100644 --- a/src/error.h +++ b/src/error.h @@ -38,19 +38,19 @@ #ifdef WITH_MPI extern int engine_rank; #define error(s, ...) \ - { \ + ({ \ fprintf(stderr, "[%04i] %s %s:%s():%i: " s "\n", engine_rank, \ clocks_get_timesincestart(), __FILE__, __FUNCTION__, __LINE__, \ ##__VA_ARGS__); \ MPI_Abort(MPI_COMM_WORLD, -1); \ - } + }) #else #define error(s, ...) \ - { \ + ({ \ fprintf(stderr, "%s %s:%s():%i: " s "\n", clocks_get_timesincestart(), \ __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__); \ abort(); \ - } + }) #endif #ifdef WITH_MPI @@ -60,7 +60,7 @@ extern int engine_rank; * */ #define mpi_error(res, s, ...) \ - { \ + ({ \ fprintf(stderr, "[%04i] %s %s:%s():%i: " s "\n", engine_rank, \ clocks_get_timesincestart(), __FILE__, __FUNCTION__, __LINE__, \ ##__VA_ARGS__); \ @@ -69,10 +69,10 @@ extern int engine_rank; MPI_Error_string(res, buf, &len); \ fprintf(stderr, "%s\n\n", buf); \ MPI_Abort(MPI_COMM_WORLD, -1); \ - } + }) #define mpi_error_string(res, s, ...) \ - { \ + ({ \ fprintf(stderr, "[%04i] %s %s:%s():%i: " s "\n", engine_rank, \ clocks_get_timesincestart(), __FILE__, __FUNCTION__, __LINE__, \ ##__VA_ARGS__); \ @@ -80,7 +80,7 @@ extern int engine_rank; char buf[len]; \ MPI_Error_string(res, buf, &len); \ fprintf(stderr, "%s\n\n", buf); \ - } + }) #endif /** @@ -89,13 +89,17 @@ extern int engine_rank; */ #ifdef WITH_MPI extern int engine_rank; -#define message(s, ...) \ - printf("[%04i] %s %s: " s "\n", engine_rank, clocks_get_timesincestart(), \ - __FUNCTION__, ##__VA_ARGS__) +#define message(s, ...) \ + ({ \ + printf("[%04i] %s %s: " s "\n", engine_rank, clocks_get_timesincestart(), \ + __FUNCTION__, ##__VA_ARGS__); \ + }) #else -#define message(s, ...) \ - printf("%s %s: " s "\n", clocks_get_timesincestart(), __FUNCTION__, \ - ##__VA_ARGS__) +#define message(s, ...) \ + ({ \ + printf("%s %s: " s "\n", clocks_get_timesincestart(), __FUNCTION__, \ + ##__VA_ARGS__); \ + }) #endif /** @@ -105,7 +109,7 @@ extern int engine_rank; #ifdef WITH_MPI extern int engine_rank; #define assert(expr) \ - { \ + ({ \ if (!(expr)) { \ fprintf(stderr, "[%04i] %s %s:%s():%i: FAILED ASSERTION: " #expr " \n", \ engine_rank, clocks_get_timesincestart(), __FILE__, \ @@ -113,17 +117,17 @@ extern int engine_rank; fflush(stderr); \ MPI_Abort(MPI_COMM_WORLD, -1); \ } \ - } + }) #else #define assert(expr) \ - { \ + ({ \ if (!(expr)) { \ fprintf(stderr, "%s %s:%s():%i: FAILED ASSERTION: " #expr " \n", \ clocks_get_timesincestart(), __FILE__, __FUNCTION__, __LINE__); \ fflush(stderr); \ abort(); \ } \ - } + }) #endif #endif /* SWIFT_ERROR_H */ diff --git a/src/hydro/Default/hydro.h b/src/hydro/Default/hydro.h index ccdd0cee32b9386eff54da655b75285b8e08a598..3fd357a2d8778f5ca8b014935d538350eccb99c6 100644 --- a/src/hydro/Default/hydro.h +++ b/src/hydro/Default/hydro.h @@ -199,10 +199,9 @@ __attribute__((always_inline)) INLINE static void hydro_init_part( * and add the self-contribution term. * * @param p The particle to act upon - * @param time The current time */ __attribute__((always_inline)) INLINE static void hydro_end_density( - struct part *restrict p, float time) { + struct part *restrict p) { /* Some smoothing length multiples. */ const float h = p->h; diff --git a/src/hydro/Gadget2/hydro.h b/src/hydro/Gadget2/hydro.h index c999e20d401570ac6518291df8cf315569fe78bd..157893bc9e27806d2b97ac5f5a81d0f6fbb1c589 100644 --- a/src/hydro/Gadget2/hydro.h +++ b/src/hydro/Gadget2/hydro.h @@ -246,10 +246,9 @@ __attribute__((always_inline)) INLINE static void hydro_init_part( * and add the self-contribution term. * * @param p The particle to act upon - * @param ti_current The current time (on the integer timeline) */ __attribute__((always_inline)) INLINE static void hydro_end_density( - struct part *restrict p, int ti_current) { + struct part *restrict p) { /* Some smoothing length multiples. */ const float h = p->h; diff --git a/src/hydro/Gadget2/hydro_iact.h b/src/hydro/Gadget2/hydro_iact.h index fca1bcff91a71fb2a26adc117382630a576f9090..08fb2b37db566e191bd74d82488b5d68e764573b 100644 --- a/src/hydro/Gadget2/hydro_iact.h +++ b/src/hydro/Gadget2/hydro_iact.h @@ -226,7 +226,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_vec_density( error( "The Gadget2 serial version of runner_iact_density was called when the " - "vectorised version should have been used.") + "vectorised version should have been used."); #endif } @@ -377,7 +377,7 @@ runner_iact_nonsym_vec_density(float *R2, float *Dx, float *Hi, float *Hj, error( "The Gadget2 serial version of runner_iact_nonsym_density was called " - "when the vectorised version should have been used.") + "when the vectorised version should have been used."); #endif } @@ -656,7 +656,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_vec_force( error( "The Gadget2 serial version of runner_iact_nonsym_force was called when " - "the vectorised version should have been used.") + "the vectorised version should have been used."); #endif } @@ -917,7 +917,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_vec_force( error( "The Gadget2 serial version of runner_iact_nonsym_force was called when " - "the vectorised version should have been used.") + "the vectorised version should have been used."); #endif } diff --git a/src/hydro/Gizmo/hydro.h b/src/hydro/Gizmo/hydro.h index bd970795bdf070a7bd7915cc4f493218dbf319d1..1c64291ee64dd770b1f1a76371f67a34230365c7 100644 --- a/src/hydro/Gizmo/hydro.h +++ b/src/hydro/Gizmo/hydro.h @@ -109,10 +109,9 @@ __attribute__((always_inline)) INLINE static void hydro_init_part( * passive particles. * * @param p The particle to act upon. - * @param The current physical time. */ __attribute__((always_inline)) INLINE static void hydro_end_density( - struct part* restrict p, float time) { + struct part* restrict p) { /* Some smoothing length multiples. */ const float h = p->h; diff --git a/src/hydro/Minimal/hydro.h b/src/hydro/Minimal/hydro.h index 3015f26c6bad7f006e8cda16695c750ff40d74df..3b3454f1bb348b178ac57899da4f7611802a69cd 100644 --- a/src/hydro/Minimal/hydro.h +++ b/src/hydro/Minimal/hydro.h @@ -256,10 +256,9 @@ __attribute__((always_inline)) INLINE static void hydro_init_part( * added to them here. * * @param p The particle to act upon - * @param time The current time */ __attribute__((always_inline)) INLINE static void hydro_end_density( - struct part *restrict p, float time) { + struct part *restrict p) { /* Some smoothing length multiples. */ const float h = p->h; diff --git a/src/hydro/PressureEntropy/hydro.h b/src/hydro/PressureEntropy/hydro.h index 0c69728a9ce6317a8d7ddab945e7aab6e94ee247..8c063596efd3be97ebb4da6b6879ac06122bd357 100644 --- a/src/hydro/PressureEntropy/hydro.h +++ b/src/hydro/PressureEntropy/hydro.h @@ -254,10 +254,9 @@ __attribute__((always_inline)) INLINE static void hydro_init_part( * and add the self-contribution term. * * @param p The particle to act upon - * @param ti_current The current time (on the integer timeline) */ __attribute__((always_inline)) INLINE static void hydro_end_density( - struct part *restrict p, int ti_current) { + struct part *restrict p) { /* Some smoothing length multiples. */ const float h = p->h; diff --git a/src/partition.c b/src/partition.c index 8d17bedf0aaeadc64044b12ffe1bb8887b02d83e..3f5386154497d6901a5330b828007f86d87033a4 100644 --- a/src/partition.c +++ b/src/partition.c @@ -370,7 +370,7 @@ static void pick_metis(struct space *s, int nregions, int *vertexw, int *edgew, /* Dump graph in METIS format */ /* dumpMETISGraph("metis_graph", idx_ncells, one, xadj, adjncy, - * weights_v, weights_e, NULL); + * weights_v, NULL, weights_e); */ if (METIS_PartGraphKway(&idx_ncells, &one, xadj, adjncy, weights_v, weights_e, @@ -420,7 +420,7 @@ static void repart_edge_metis(int partweights, int bothweights, int nodeID, * assume the same graph structure as used in the part_ calls). */ int nr_cells = s->nr_cells; struct cell *cells = s->cells_top; - float wscale = 1e-3, vscale = 1e-3, wscale_buff = 0.0; + float wscale = 1.f, wscale_buff = 0.0; int wtot = 0; int wmax = 1e9 / nr_nodes; int wmin; @@ -459,15 +459,8 @@ static void repart_edge_metis(int partweights, int bothweights, int nodeID, t->type != task_type_init) continue; - /* Get the task weight. This can be slightly negative on multiple board - * computers when the runners are not pinned to cores, don't stress just - * make a report and ignore these tasks. */ - int w = (t->toc - t->tic) * wscale; - if (w < 0) { - message("Task toc before tic: -%.3f %s, (try using processor affinity).", - clocks_from_ticks(t->tic - t->toc), clocks_getunit()); - w = 0; - } + /* Get the task weight. */ + int w = t->cost * wscale; /* Do we need to re-scale? */ wtot += w; @@ -616,7 +609,7 @@ static void repart_edge_metis(int partweights, int bothweights, int nodeID, if (weights_e[k] == 0) weights_e[k] = 1; if (bothweights) for (int k = 0; k < nr_cells; k++) - if ((weights_v[k] *= vscale) == 0) weights_v[k] = 1; + if (weights_v[k] == 0) weights_v[k] = 1; /* And partition, use both weights or not as requested. */ if (bothweights) diff --git a/src/potential.c b/src/potential.c index 5433a05e3e7886ad88021d3916cae26adfe8b954..6ee80900952c032d019ad5d20ec086d05d34ef29 100644 --- a/src/potential.c +++ b/src/potential.c @@ -31,14 +31,15 @@ * @param parameter_file The parsed parameter file * @param phys_const Physical constants in internal units * @param us The current internal system of units + * @param s The #space we run in. * @param potential The external potential properties to initialize */ void potential_init(const struct swift_params* parameter_file, const struct phys_const* phys_const, - const struct UnitSystem* us, + const struct UnitSystem* us, const struct space* s, struct external_potential* potential) { - potential_init_backend(parameter_file, phys_const, us, potential); + potential_init_backend(parameter_file, phys_const, us, s, potential); } /** diff --git a/src/potential.h b/src/potential.h index 77bd41794a3a8cd244405493898d63b3f80ff3a6..f7fdd0072c502641d36f229337f4616b9033cbda 100644 --- a/src/potential.h +++ b/src/potential.h @@ -37,6 +37,8 @@ #include "./potential/point_mass/potential.h" #elif defined(EXTERNAL_POTENTIAL_ISOTHERMALPOTENTIAL) #include "./potential/isothermal/potential.h" +#elif defined(EXTERNAL_POTENTIAL_SOFTENED_ISOTHERMAL_POTENTIAL) +#include "./potential/softened_isothermal/potential.h" #elif defined(EXTERNAL_POTENTIAL_DISC_PATCH) #include "./potential/disc_patch/potential.h" #else @@ -46,7 +48,7 @@ /* Now, some generic functions, defined in the source file */ void potential_init(const struct swift_params* parameter_file, const struct phys_const* phys_const, - const struct UnitSystem* us, + const struct UnitSystem* us, const struct space* s, struct external_potential* potential); void potential_print(const struct external_potential* potential); diff --git a/src/potential/disc_patch/potential.h b/src/potential/disc_patch/potential.h index 21d168818e164ad3b3e18076ba824285e40956aa..fe1df8796f046edded0c5b1779859a1c6fffffc0 100644 --- a/src/potential/disc_patch/potential.h +++ b/src/potential/disc_patch/potential.h @@ -33,6 +33,7 @@ #include "parser.h" #include "part.h" #include "physical_constants.h" +#include "space.h" #include "units.h" /** @@ -149,6 +150,25 @@ __attribute__((always_inline)) INLINE static void external_gravity_acceleration( if (dz < 0) g->a_grav[2] += z_accel; } +/** + * @brief Computes the gravitational potential energy of a particle in the + * disc patch potential. + * Time evolving system so not sure how to do this + * Placeholder for now- just returns 0 + * + * @param potential The #external_potential used in the run. + * @param phys_const Physical constants in internal units. + * @param p Pointer to the particle data. + */ + +__attribute__((always_inline)) INLINE static float +external_gravity_get_potential_energy( + const struct external_potential* potential, + const struct phys_const* const phys_const, const struct gpart* p) { + + return 0.f; +} + /** * @brief Initialises the external potential properties in the internal system * of units. @@ -161,7 +181,7 @@ __attribute__((always_inline)) INLINE static void external_gravity_acceleration( static INLINE void potential_init_backend( const struct swift_params* parameter_file, const struct phys_const* phys_const, const struct UnitSystem* us, - struct external_potential* potential) { + const struct space* s, struct external_potential* potential) { potential->surface_density = parser_get_param_double( parameter_file, "DiscPatchPotential:surface_density"); diff --git a/src/potential/isothermal/potential.h b/src/potential/isothermal/potential.h index a993c09a978ca3692ec3359f7633df14760f263d..a582dce17daba0ac9705ef4ae1fc6be9db19315a 100644 --- a/src/potential/isothermal/potential.h +++ b/src/potential/isothermal/potential.h @@ -31,6 +31,7 @@ #include "parser.h" #include "part.h" #include "physical_constants.h" +#include "space.h" #include "units.h" /** @@ -105,6 +106,7 @@ __attribute__((always_inline)) INLINE static void external_gravity_acceleration( const float dx = g->x[0] - potential->x; const float dy = g->x[1] - potential->y; const float dz = g->x[2] - potential->z; + const float rinv2 = 1.f / (dx * dx + dy * dy + dz * dz); const double term = -potential->vrot2_over_G * rinv2; @@ -114,6 +116,27 @@ __attribute__((always_inline)) INLINE static void external_gravity_acceleration( g->a_grav[2] += term * dz; } +/** + * @brief Computes the gravitational potential energy of a particle in an + * isothermal potential. + * + * @param potential The #external_potential used in the run. + * @param phys_const Physical constants in internal units. + * @param g Pointer to the particle data. + */ +__attribute__((always_inline)) INLINE static float +external_gravity_get_potential_energy( + const struct external_potential* potential, + const struct phys_const* const phys_const, const struct gpart* g) { + + const float dx = g->x[0] - potential->x; + const float dy = g->x[1] - potential->y; + const float dz = g->x[2] - potential->z; + + return 0.5f * potential->vrot * potential->vrot * + logf(dx * dx + dy * dy * dz * dz); +} + /** * @brief Initialises the external potential properties in the internal system * of units. @@ -126,13 +149,16 @@ __attribute__((always_inline)) INLINE static void external_gravity_acceleration( static INLINE void potential_init_backend( const struct swift_params* parameter_file, const struct phys_const* phys_const, const struct UnitSystem* us, - struct external_potential* potential) { + const struct space* s, struct external_potential* potential) { potential->x = + s->dim[0] / 2. + parser_get_param_double(parameter_file, "IsothermalPotential:position_x"); potential->y = + s->dim[1] / 2. + parser_get_param_double(parameter_file, "IsothermalPotential:position_y"); potential->z = + s->dim[2] / 2. + parser_get_param_double(parameter_file, "IsothermalPotential:position_z"); potential->vrot = parser_get_param_double(parameter_file, "IsothermalPotential:vrot"); diff --git a/src/potential/none/potential.h b/src/potential/none/potential.h index 8b1c3e841521f3fb42fbdf5c8922cead2ea7cbcb..8248b64678e28e06b9df4aab375cde0b5ed5281b 100644 --- a/src/potential/none/potential.h +++ b/src/potential/none/potential.h @@ -30,6 +30,7 @@ #include "parser.h" #include "part.h" #include "physical_constants.h" +#include "space.h" #include "units.h" /** @@ -67,6 +68,21 @@ __attribute__((always_inline)) INLINE static void external_gravity_acceleration( double time, const struct external_potential* restrict potential, const struct phys_const* restrict phys_const, struct gpart* restrict g) {} +/** + * @brief Computes the gravitational potential energy due to nothing. + * + * @param potential The #external_potential used in the run. + * @param phys_const Physical constants in internal units. + * @param g Pointer to the particle data. + */ +__attribute__((always_inline)) INLINE static float +external_gravity_get_potential_energy( + const struct external_potential* potential, + const struct phys_const* const phys_const, const struct gpart* g) { + + return 0.f; +} + /** * @brief Initialises the external potential properties in the internal system * of units. @@ -81,7 +97,7 @@ __attribute__((always_inline)) INLINE static void external_gravity_acceleration( static INLINE void potential_init_backend( const struct swift_params* parameter_file, const struct phys_const* phys_const, const struct UnitSystem* us, - struct external_potential* potential) {} + const struct space* s, struct external_potential* potential) {} /** * @brief Prints the properties of the external potential to stdout. diff --git a/src/potential/point_mass/potential.h b/src/potential/point_mass/potential.h index f718af2e2c4ff91540e1834cb2072d321ce38705..5f3d1c27b85c4f1353481e6351fba47aff62d66f 100644 --- a/src/potential/point_mass/potential.h +++ b/src/potential/point_mass/potential.h @@ -31,6 +31,7 @@ #include "parser.h" #include "part.h" #include "physical_constants.h" +#include "space.h" #include "units.h" /** @@ -115,6 +116,26 @@ __attribute__((always_inline)) INLINE static void external_gravity_acceleration( g->a_grav[2] += -potential->mass * dz * rinv3; } +/** + * @brief Computes the gravitational potential energy of a particle in a point + * mass potential. + * + * @param potential The #external_potential used in the run. + * @param phys_const Physical constants in internal units. + * @param g Pointer to the particle data. + */ +__attribute__((always_inline)) INLINE static float +external_gravity_get_potential_energy( + const struct external_potential* potential, + const struct phys_const* const phys_const, const struct gpart* g) { + + const float dx = g->x[0] - potential->x; + const float dy = g->x[1] - potential->y; + const float dz = g->x[2] - potential->z; + const float rinv = 1. / sqrtf(dx * dx + dy * dy + dz * dz); + return -phys_const->const_newton_G * potential->mass * rinv; +} + /** * @brief Initialises the external potential properties in the internal system * of units. @@ -122,12 +143,13 @@ __attribute__((always_inline)) INLINE static void external_gravity_acceleration( * @param parameter_file The parsed parameter file * @param phys_const Physical constants in internal units * @param us The current internal system of units + * @param s The #space we run in. * @param potential The external potential properties to initialize */ static INLINE void potential_init_backend( const struct swift_params* parameter_file, const struct phys_const* phys_const, const struct UnitSystem* us, - struct external_potential* potential) { + const struct space* s, struct external_potential* potential) { potential->x = parser_get_param_double(parameter_file, "PointMassPotential:position_x"); diff --git a/src/potential/softened_isothermal/potential.h b/src/potential/softened_isothermal/potential.h new file mode 100644 index 0000000000000000000000000000000000000000..24e59b12a5745728fb1189fbbfbc7cc3c06fbfa6 --- /dev/null +++ b/src/potential/softened_isothermal/potential.h @@ -0,0 +1,196 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2016 Stefan Arridge (stefan.arridge@durham.ac.uk) + * Matthieu Schaller (matthieu.schaller@durham.ac.uk) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ +#ifndef SWIFT_POTENTIAL_SOFTENED_ISOTHERMAL_H +#define SWIFT_POTENTIAL_SOFTENED_ISOTHERMAL_H + +/* Config parameters. */ +#include "../config.h" + +/* Some standard headers. */ +#include <math.h> + +/* Local includes. */ +#include "error.h" +#include "parser.h" +#include "part.h" +#include "physical_constants.h" +#include "space.h" +#include "units.h" + +/** + * @brief External Potential Properties - Softened Isothermal sphere case + */ +struct external_potential { + + /*! Position of the centre of potential */ + double x, y, z; + + /*! Rotation velocity */ + double vrot; + + /*! Square of vrot, the circular velocity which defines the isothermal + * potential */ + double vrot2_over_G; + + /*! Square of the softening length. Acceleration tends to zero within this + * distance from the origin */ + double epsilon2; + + /*! Time-step condition pre-factor */ + double timestep_mult; +}; + +/** + * @brief Computes the time-step due to the acceleration from an isothermal + * potential. + * + * @param time The current time. + * @param potential The #external_potential used in the run. + * @param phys_const The physical constants in internal units. + * @param g Pointer to the g-particle data. + */ +__attribute__((always_inline)) INLINE static float external_gravity_timestep( + double time, const struct external_potential* restrict potential, + const struct phys_const* restrict phys_const, + const struct gpart* restrict g) { + + const float dx = g->x[0] - potential->x; + const float dy = g->x[1] - potential->y; + const float dz = g->x[2] - potential->z; + + const float r2_plus_epsilon2_inv = + 1.f / (dx * dx + dy * dy + dz * dz + potential->epsilon2); + const float drdv = + dx * (g->v_full[0]) + dy * (g->v_full[1]) + dz * (g->v_full[2]); + const double vrot = potential->vrot; + + const float dota_x = vrot * vrot * r2_plus_epsilon2_inv * + (g->v_full[0] - 2.f * drdv * dx * r2_plus_epsilon2_inv); + const float dota_y = vrot * vrot * r2_plus_epsilon2_inv * + (g->v_full[1] - 2.f * drdv * dy * r2_plus_epsilon2_inv); + const float dota_z = vrot * vrot * r2_plus_epsilon2_inv * + (g->v_full[2] - 2.f * drdv * dz * r2_plus_epsilon2_inv); + const float dota_2 = dota_x * dota_x + dota_y * dota_y + dota_z * dota_z; + const float a_2 = g->a_grav[0] * g->a_grav[0] + g->a_grav[1] * g->a_grav[1] + + g->a_grav[2] * g->a_grav[2]; + + return potential->timestep_mult * sqrtf(a_2 / dota_2); +} + +/** + * @brief Computes the gravitational acceleration from an isothermal potential. + * + * Note that the accelerations are multiplied by Newton's G constant + * later on. + * + * a = v_rot^2 * (x,y,z) / (r^2 + epsilon^2) + * @param time The current time. + * @param potential The #external_potential used in the run. + * @param phys_const The physical constants in internal units. + * @param g Pointer to the g-particle data. + */ +__attribute__((always_inline)) INLINE static void external_gravity_acceleration( + double time, const struct external_potential* potential, + const struct phys_const* const phys_const, struct gpart* g) { + + const float dx = g->x[0] - potential->x; + const float dy = g->x[1] - potential->y; + const float dz = g->x[2] - potential->z; + const float r2_plus_epsilon2_inv = + 1.f / (dx * dx + dy * dy + dz * dz + potential->epsilon2); + + const double term = -potential->vrot2_over_G * r2_plus_epsilon2_inv; + + g->a_grav[0] += term * dx; + g->a_grav[1] += term * dy; + g->a_grav[2] += term * dz; +} + +/** + * @brief Computes the gravitational potential energy of a particle in an + * isothermal potential. + * + * @param potential The #external_potential used in the run. + * @param phys_const Physical constants in internal units. + * @param g Pointer to the particle data. + */ +__attribute__((always_inline)) INLINE static float +external_gravity_get_potential_energy( + const struct external_potential* potential, + const struct phys_const* const phys_const, const struct gpart* g) { + + const float dx = g->x[0] - potential->x; + const float dy = g->x[1] - potential->y; + const float dz = g->x[2] - potential->z; + + return 0.5f * potential->vrot * potential->vrot * + logf(dx * dx + dy * dy * dz * dz + potential->epsilon2); +} +/** + * @brief Initialises the external potential properties in the internal system + * of units. + * + * @param parameter_file The parsed parameter file + * @param phys_const Physical constants in internal units + * @param us The current internal system of units + * @param potential The external potential properties to initialize + */ +static INLINE void potential_init_backend( + const struct swift_params* parameter_file, + const struct phys_const* phys_const, const struct UnitSystem* us, + const struct space* s, struct external_potential* potential) { + + potential->x = s->dim[0] / 2. + + parser_get_param_double( + parameter_file, "SoftenedIsothermalPotential:position_x"); + potential->y = s->dim[1] / 2. + + parser_get_param_double( + parameter_file, "SoftenedIsothermalPotential:position_y"); + potential->z = s->dim[2] / 2. + + parser_get_param_double( + parameter_file, "SoftenedIsothermalPotential:position_z"); + potential->vrot = parser_get_param_double(parameter_file, + "SoftenedIsothermalPotential:vrot"); + potential->timestep_mult = parser_get_param_float( + parameter_file, "SoftenedIsothermalPotential:timestep_mult"); + const double epsilon = parser_get_param_float( + parameter_file, "SoftenedIsothermalPotential:epsilon"); + potential->vrot2_over_G = + potential->vrot * potential->vrot / phys_const->const_newton_G; + potential->epsilon2 = epsilon * epsilon; +} + +/** + * @brief Prints the properties of the external potential to stdout. + * + * @param potential The external potential properties. + */ +static INLINE void potential_print_backend( + const struct external_potential* potential) { + + message( + "External potential is 'Isothermal' with properties are (x,y,z) = (%e, " + "%e, %e), vrot = %e " + "timestep multiplier = %e, epsilon = %e", + potential->x, potential->y, potential->z, potential->vrot, + potential->timestep_mult, sqrtf(potential->epsilon2)); +} + +#endif /* SWIFT_POTENTIAL_ISOTHERMAL_H */ diff --git a/src/runner.c b/src/runner.c index f5efc99d492be837509e50bd2674ab6923404446..2d6da4e4aedc9c40d1dade243e605e9aeda86dbe 100644 --- a/src/runner.c +++ b/src/runner.c @@ -38,6 +38,7 @@ #include "runner.h" /* Local headers. */ +#include "active.h" #include "approx_math.h" #include "atomic.h" #include "cell.h" @@ -132,16 +133,16 @@ void runner_do_sourceterms(struct runner *r, struct cell *c, int timer) { if (c->split) { for (int k = 0; k < 8; k++) if (c->progeny[k] != NULL) runner_do_sourceterms(r, c->progeny[k], 0); - return; - } + } else { - if (count > 0) { + if (count > 0) { - /* do sourceterms in this cell? */ - const int incell = - sourceterms_test_cell(cell_min, cell_width, sourceterms, dimen); - if (incell == 1) { - sourceterms_apply(r, sourceterms, c); + /* do sourceterms in this cell? */ + const int incell = + sourceterms_test_cell(cell_min, cell_width, sourceterms, dimen); + if (incell == 1) { + sourceterms_apply(r, sourceterms, c); + } } } @@ -159,37 +160,32 @@ void runner_do_grav_external(struct runner *r, struct cell *c, int timer) { struct gpart *restrict gparts = c->gparts; const int gcount = c->gcount; - const int ti_current = r->e->ti_current; - const struct external_potential *potential = r->e->external_potential; - const struct phys_const *constants = r->e->physical_constants; + const struct engine *e = r->e; + const struct external_potential *potential = e->external_potential; + const struct phys_const *constants = e->physical_constants; const double time = r->e->time; TIMER_TIC; /* Anything to do here? */ - if (c->ti_end_min > ti_current) return; + if (!cell_is_active(c, e)) return; /* Recurse? */ if (c->split) { for (int k = 0; k < 8; k++) if (c->progeny[k] != NULL) runner_do_grav_external(r, c->progeny[k], 0); - return; - } - -#ifdef TASK_VERBOSE - OUT; -#endif - - /* Loop over the gparts in this cell. */ - for (int i = 0; i < gcount; i++) { + } else { - /* Get a direct pointer on the part. */ - struct gpart *restrict gp = &gparts[i]; + /* Loop over the gparts in this cell. */ + for (int i = 0; i < gcount; i++) { - /* Is this part within the time step? */ - if (gp->ti_end <= ti_current) { + /* Get a direct pointer on the part. */ + struct gpart *restrict gp = &gparts[i]; - external_gravity_acceleration(time, potential, constants, gp); + /* Is this part within the time step? */ + if (gpart_is_active(gp, e)) { + external_gravity_acceleration(time, potential, constants, gp); + } } } @@ -221,26 +217,22 @@ void runner_do_cooling(struct runner *r, struct cell *c, int timer) { if (c->split) { for (int k = 0; k < 8; k++) if (c->progeny[k] != NULL) runner_do_cooling(r, c->progeny[k], 0); - return; - } - -#ifdef TASK_VERBOSE - OUT; -#endif + } else { - /* Loop over the parts in this cell. */ - for (int i = 0; i < count; i++) { + /* Loop over the parts in this cell. */ + for (int i = 0; i < count; i++) { - /* Get a direct pointer on the part. */ - struct part *restrict p = &parts[i]; - struct xpart *restrict xp = &xparts[i]; + /* Get a direct pointer on the part. */ + struct part *restrict p = &parts[i]; + struct xpart *restrict xp = &xparts[i]; - /* Kick has already updated ti_end, so need to check ti_begin */ - if (p->ti_begin == ti_current) { + /* Kick has already updated ti_end, so need to check ti_begin */ + if (p->ti_begin == ti_current) { - const double dt = (p->ti_end - p->ti_begin) * timeBase; + const double dt = (p->ti_end - p->ti_begin) * timeBase; - cooling_cool_part(constants, us, cooling_func, p, xp, dt); + cooling_cool_part(constants, us, cooling_func, p, xp, dt); + } } } @@ -492,18 +484,17 @@ void runner_do_init(struct runner *r, struct cell *c, int timer) { struct gpart *restrict gparts = c->gparts; const int count = c->count; const int gcount = c->gcount; - const int ti_current = r->e->ti_current; + const struct engine *e = r->e; TIMER_TIC; /* Anything to do here? */ - if (c->ti_end_min > ti_current) return; + if (!cell_is_active(c, e)) return; /* Recurse? */ if (c->split) { for (int k = 0; k < 8; k++) if (c->progeny[k] != NULL) runner_do_init(r, c->progeny[k], 0); - return; } else { /* Loop over the parts in this cell. */ @@ -512,7 +503,7 @@ void runner_do_init(struct runner *r, struct cell *c, int timer) { /* Get a direct pointer on the part. */ struct part *restrict p = &parts[i]; - if (p->ti_end <= ti_current) { + if (part_is_active(p, e)) { /* Get ready for a density calculation */ hydro_init_part(p); @@ -525,7 +516,7 @@ void runner_do_init(struct runner *r, struct cell *c, int timer) { /* Get a direct pointer on the part. */ struct gpart *restrict gp = &gparts[i]; - if (gp->ti_end <= ti_current) { + if (gpart_is_active(gp, e)) { /* Get ready for a density calculation */ gravity_init_gpart(gp); @@ -542,23 +533,25 @@ void runner_do_init(struct runner *r, struct cell *c, int timer) { * * @param r The runner thread. * @param c The cell. + * @param timer Are we timing this ? */ -void runner_do_extra_ghost(struct runner *r, struct cell *c) { +void runner_do_extra_ghost(struct runner *r, struct cell *c, int timer) { #ifdef EXTRA_HYDRO_LOOP struct part *restrict parts = c->parts; const int count = c->count; - const int ti_current = r->e->ti_current; + const struct engine *e = r->e; + + TIMER_TIC; /* Anything to do here? */ - if (c->ti_end_min > ti_current) return; + if (!cell_is_active(c, e)) return; /* Recurse? */ if (c->split) { for (int k = 0; k < 8; k++) - if (c->progeny[k] != NULL) runner_do_extra_ghost(r, c->progeny[k]); - return; + if (c->progeny[k] != NULL) runner_do_extra_ghost(r, c->progeny[k], 0); } else { /* Loop over the parts in this cell. */ @@ -567,7 +560,7 @@ void runner_do_extra_ghost(struct runner *r, struct cell *c) { /* Get a direct pointer on the part. */ struct part *restrict p = &parts[i]; - if (p->ti_end <= ti_current) { + if (part_is_active(p, e)) { /* Get ready for a force calculation */ hydro_end_gradient(p); @@ -575,6 +568,8 @@ void runner_do_extra_ghost(struct runner *r, struct cell *c) { } } + if (timer) TIMER_TOC(timer_do_extra_ghost); + #else error("SWIFT was not compiled with the extra hydro loop activated."); #endif @@ -586,164 +581,166 @@ void runner_do_extra_ghost(struct runner *r, struct cell *c) { * * @param r The runner thread. * @param c The cell. + * @param timer Are we timing this ? */ -void runner_do_ghost(struct runner *r, struct cell *c) { +void runner_do_ghost(struct runner *r, struct cell *c, int timer) { struct part *restrict parts = c->parts; struct xpart *restrict xparts = c->xparts; int redo, count = c->count; - const int ti_current = r->e->ti_current; - const double timeBase = r->e->timeBase; - const float target_wcount = r->e->hydro_properties->target_neighbours; + const struct engine *e = r->e; + const int ti_current = e->ti_current; + const double timeBase = e->timeBase; + const float target_wcount = e->hydro_properties->target_neighbours; const float max_wcount = - target_wcount + r->e->hydro_properties->delta_neighbours; + target_wcount + e->hydro_properties->delta_neighbours; const float min_wcount = - target_wcount - r->e->hydro_properties->delta_neighbours; - const int max_smoothing_iter = - r->e->hydro_properties->max_smoothing_iterations; + target_wcount - e->hydro_properties->delta_neighbours; + const int max_smoothing_iter = e->hydro_properties->max_smoothing_iterations; TIMER_TIC; /* Anything to do here? */ - if (c->ti_end_min > ti_current) return; + if (!cell_is_active(c, e)) return; /* Recurse? */ if (c->split) { for (int k = 0; k < 8; k++) - if (c->progeny[k] != NULL) runner_do_ghost(r, c->progeny[k]); - return; - } + if (c->progeny[k] != NULL) runner_do_ghost(r, c->progeny[k], 0); + } else { - /* Init the IDs that have to be updated. */ - int *pid = NULL; - if ((pid = malloc(sizeof(int) * count)) == NULL) - error("Can't allocate memory for pid."); - for (int k = 0; k < count; k++) pid[k] = k; + /* Init the IDs that have to be updated. */ + int *pid = NULL; + if ((pid = malloc(sizeof(int) * count)) == NULL) + error("Can't allocate memory for pid."); + for (int k = 0; k < count; k++) pid[k] = k; - /* While there are particles that need to be updated... */ - for (int num_reruns = 0; count > 0 && num_reruns < max_smoothing_iter; - num_reruns++) { + /* While there are particles that need to be updated... */ + for (int num_reruns = 0; count > 0 && num_reruns < max_smoothing_iter; + num_reruns++) { - /* Reset the redo-count. */ - redo = 0; + /* Reset the redo-count. */ + redo = 0; - /* Loop over the parts in this cell. */ - for (int i = 0; i < count; i++) { + /* Loop over the parts in this cell. */ + for (int i = 0; i < count; i++) { - /* Get a direct pointer on the part. */ - struct part *restrict p = &parts[pid[i]]; - struct xpart *restrict xp = &xparts[pid[i]]; + /* Get a direct pointer on the part. */ + struct part *restrict p = &parts[pid[i]]; + struct xpart *restrict xp = &xparts[pid[i]]; - /* Is this part within the timestep? */ - if (p->ti_end <= ti_current) { + /* Is this part within the timestep? */ + if (part_is_active(p, e)) { - /* Finish the density calculation */ - hydro_end_density(p, ti_current); + /* Finish the density calculation */ + hydro_end_density(p); - float h_corr = 0.f; + float h_corr = 0.f; - /* If no derivative, double the smoothing length. */ - if (p->density.wcount_dh == 0.0f) h_corr = p->h; + /* If no derivative, double the smoothing length. */ + if (p->density.wcount_dh == 0.0f) h_corr = p->h; - /* Otherwise, compute the smoothing length update (Newton step). */ - else { - h_corr = (target_wcount - p->density.wcount) / p->density.wcount_dh; + /* Otherwise, compute the smoothing length update (Newton step). */ + else { + h_corr = (target_wcount - p->density.wcount) / p->density.wcount_dh; - /* Truncate to the range [ -p->h/2 , p->h ]. */ - h_corr = (h_corr < p->h) ? h_corr : p->h; - h_corr = (h_corr > -0.5f * p->h) ? h_corr : -0.5f * p->h; - } + /* Truncate to the range [ -p->h/2 , p->h ]. */ + h_corr = (h_corr < p->h) ? h_corr : p->h; + h_corr = (h_corr > -0.5f * p->h) ? h_corr : -0.5f * p->h; + } - /* Did we get the right number density? */ - if (p->density.wcount > max_wcount || p->density.wcount < min_wcount) { + /* Did we get the right number density? */ + if (p->density.wcount > max_wcount || + p->density.wcount < min_wcount) { - /* Ok, correct then */ - p->h += h_corr; + /* Ok, correct then */ + p->h += h_corr; - /* Flag for another round of fun */ - pid[redo] = pid[i]; - redo += 1; + /* Flag for another round of fun */ + pid[redo] = pid[i]; + redo += 1; - /* Re-initialise everything */ - hydro_init_part(p); + /* Re-initialise everything */ + hydro_init_part(p); - /* Off we go ! */ - continue; - } + /* Off we go ! */ + continue; + } - /* We now have a particle whose smoothing length has converged */ + /* We now have a particle whose smoothing length has converged */ - /* As of here, particle force variables will be set. */ + /* As of here, particle force variables will be set. */ - /* Compute variables required for the force loop */ - hydro_prepare_force(p, xp, ti_current, timeBase); + /* Compute variables required for the force loop */ + hydro_prepare_force(p, xp, ti_current, timeBase); - /* The particle force values are now set. Do _NOT_ - try to read any particle density variables! */ + /* The particle force values are now set. Do _NOT_ + try to read any particle density variables! */ - /* Prepare the particle for the force loop over neighbours */ - hydro_reset_acceleration(p); + /* Prepare the particle for the force loop over neighbours */ + hydro_reset_acceleration(p); + } } - } - /* We now need to treat the particles whose smoothing length had not - * converged again */ + /* We now need to treat the particles whose smoothing length had not + * converged again */ - /* Re-set the counter for the next loop (potentially). */ - count = redo; - if (count > 0) { + /* Re-set the counter for the next loop (potentially). */ + count = redo; + if (count > 0) { - /* Climb up the cell hierarchy. */ - for (struct cell *finger = c; finger != NULL; finger = finger->parent) { + /* Climb up the cell hierarchy. */ + for (struct cell *finger = c; finger != NULL; finger = finger->parent) { - /* Run through this cell's density interactions. */ - for (struct link *l = finger->density; l != NULL; l = l->next) { + /* Run through this cell's density interactions. */ + for (struct link *l = finger->density; l != NULL; l = l->next) { - /* Self-interaction? */ - if (l->t->type == task_type_self) - runner_doself_subset_density(r, finger, parts, pid, count); + /* Self-interaction? */ + if (l->t->type == task_type_self) + runner_doself_subset_density(r, finger, parts, pid, count); - /* Otherwise, pair interaction? */ - else if (l->t->type == task_type_pair) { + /* Otherwise, pair interaction? */ + else if (l->t->type == task_type_pair) { - /* Left or right? */ - if (l->t->ci == finger) - runner_dopair_subset_density(r, finger, parts, pid, count, - l->t->cj); - else - runner_dopair_subset_density(r, finger, parts, pid, count, - l->t->ci); + /* Left or right? */ + if (l->t->ci == finger) + runner_dopair_subset_density(r, finger, parts, pid, count, + l->t->cj); + else + runner_dopair_subset_density(r, finger, parts, pid, count, + l->t->ci); - } + } + + /* Otherwise, sub-self interaction? */ + else if (l->t->type == task_type_sub_self) + runner_dosub_subset_density(r, finger, parts, pid, count, NULL, + -1, 1); - /* Otherwise, sub-self interaction? */ - else if (l->t->type == task_type_sub_self) - runner_dosub_subset_density(r, finger, parts, pid, count, NULL, -1, - 1); - - /* Otherwise, sub-pair interaction? */ - else if (l->t->type == task_type_sub_pair) { - - /* Left or right? */ - if (l->t->ci == finger) - runner_dosub_subset_density(r, finger, parts, pid, count, - l->t->cj, -1, 1); - else - runner_dosub_subset_density(r, finger, parts, pid, count, - l->t->ci, -1, 1); + /* Otherwise, sub-pair interaction? */ + else if (l->t->type == task_type_sub_pair) { + + /* Left or right? */ + if (l->t->ci == finger) + runner_dosub_subset_density(r, finger, parts, pid, count, + l->t->cj, -1, 1); + else + runner_dosub_subset_density(r, finger, parts, pid, count, + l->t->ci, -1, 1); + } } } } } - } - if (count) - message("Smoothing length failed to converge on %i particles.", count); + if (count) + message("Smoothing length failed to converge on %i particles.", count); - /* Be clean */ - free(pid); + /* Be clean */ + free(pid); + } - TIMER_TOC(timer_do_ghost); + if (timer) TIMER_TOC(timer_do_ghost); } /** @@ -757,20 +754,18 @@ void runner_do_ghost(struct runner *r, struct cell *c) { */ static void runner_do_drift(struct cell *c, struct engine *e, int drift) { - const int ti_current = e->ti_current; - /* Unskip any active tasks. */ - if (c->ti_end_min == e->ti_current) { + if (cell_is_active(c, e)) { const int forcerebuild = cell_unskip_tasks(c, &e->sched); if (forcerebuild) atomic_inc(&e->forcerebuild); } /* Do we really need to drift? */ if (drift) { - if (!e->drift_all && !cell_is_drift_needed(c, ti_current)) return; + if (!e->drift_all && !cell_is_drift_needed(c, e)) return; } else { - /* Not drifting, but may still need to recurse for task skipping. */ + /* Not drifting, but may still need to recurse for task un-skipping. */ if (c->split) { for (int k = 0; k < 8; k++) { if (c->progeny[k] != NULL) { @@ -782,8 +777,12 @@ static void runner_do_drift(struct cell *c, struct engine *e, int drift) { return; } + /* Now, we can drift */ + + /* Get some information first */ const double timeBase = e->timeBase; const int ti_old = c->ti_old; + const int ti_current = e->ti_current; struct part *const parts = c->parts; struct xpart *const xparts = c->xparts; struct gpart *const gparts = c->gparts; @@ -796,7 +795,7 @@ static void runner_do_drift(struct cell *c, struct engine *e, int drift) { if (!c->split) { /* Check that we are actually going to move forward. */ - if (ti_current >= ti_old) { + if (ti_current > ti_old) { /* Loop over all the g-particles in the cell */ const size_t nr_gparts = c->gcount; @@ -840,6 +839,12 @@ static void runner_do_drift(struct cell *c, struct engine *e, int drift) { dx_max = sqrtf(dx2_max); } /* Check that we are actually going to move forward. */ + + else { + /* ti_old == ti_current, just keep the current cell values. */ + h_max = c->h_max; + dx_max = c->dx_max; + } } /* Otherwise, aggregate data from children. */ @@ -889,118 +894,6 @@ void runner_do_drift_mapper(void *map_data, int num_elements, } } -/** - * @brief Kick particles in momentum space and collect statistics (fixed - * time-step case) - * - * @param r The runner thread. - * @param c The cell. - * @param timer Are we timing this ? - */ -void runner_do_kick_fixdt(struct runner *r, struct cell *c, int timer) { - - const double global_dt = r->e->dt_max; - const double timeBase = r->e->timeBase; - const int count = c->count; - const int gcount = c->gcount; - struct part *restrict parts = c->parts; - struct xpart *restrict xparts = c->xparts; - struct gpart *restrict gparts = c->gparts; - const double const_G = r->e->physical_constants->const_newton_G; - - int updated = 0, g_updated = 0; - int ti_end_min = max_nr_timesteps, ti_end_max = 0; - - TIMER_TIC - -#ifdef TASK_VERBOSE - OUT; -#endif - - /* The new time-step */ - const int new_dti = global_dt / timeBase; - - /* No children? */ - if (!c->split) { - - /* Loop over the g-particles and kick everyone. */ - for (int k = 0; k < gcount; k++) { - - /* Get a handle on the part. */ - struct gpart *restrict gp = &gparts[k]; - - /* If the g-particle has no counterpart */ - if (gp->id_or_neg_offset > 0) { - - /* First, finish the force calculation */ - gravity_end_force(gp, const_G); - - /* Kick the g-particle forward */ - kick_gpart(gp, new_dti, timeBase); - - /* Number of updated g-particles */ - g_updated++; - - /* Minimal time for next end of time-step */ - ti_end_min = min(gp->ti_end, ti_end_min); - ti_end_max = max(gp->ti_end, ti_end_max); - } - } - - /* Now do the hydro ones... */ - - /* Loop over the particles and kick everyone. */ - for (int k = 0; k < count; k++) { - - /* Get a handle on the part. */ - struct part *restrict p = &parts[k]; - struct xpart *restrict xp = &xparts[k]; - - /* First, finish the force loop */ - hydro_end_force(p); - if (p->gpart != NULL) gravity_end_force(p->gpart, const_G); - - /* Kick the particle forward */ - kick_part(p, xp, new_dti, timeBase); - - /* Number of updated particles */ - updated++; - if (p->gpart != NULL) g_updated++; - - /* Minimal time for next end of time-step */ - ti_end_min = min(p->ti_end, ti_end_min); - ti_end_max = max(p->ti_end, ti_end_max); - } - } - - /* Otherwise, aggregate data from children. */ - else { - - /* Loop over the progeny. */ - for (int k = 0; k < 8; k++) - if (c->progeny[k] != NULL) { - struct cell *restrict cp = c->progeny[k]; - - /* Recurse */ - runner_do_kick_fixdt(r, cp, 0); - - /* And aggregate */ - updated += cp->updated; - g_updated += cp->g_updated; - ti_end_min = min(cp->ti_end_min, ti_end_min); - ti_end_max = max(cp->ti_end_max, ti_end_max); - } - } - - /* Store the values. */ - c->updated = updated; - c->g_updated = g_updated; - c->ti_end_min = ti_end_min; - c->ti_end_max = ti_end_max; - - if (timer) TIMER_TOC(timer_kick); -} - /** * @brief Kick particles in momentum space and collect statistics (floating * time-step case) @@ -1013,27 +906,22 @@ void runner_do_kick(struct runner *r, struct cell *c, int timer) { const struct engine *e = r->e; const double timeBase = e->timeBase; - const int ti_current = r->e->ti_current; const int count = c->count; const int gcount = c->gcount; struct part *restrict parts = c->parts; struct xpart *restrict xparts = c->xparts; struct gpart *restrict gparts = c->gparts; - const double const_G = r->e->physical_constants->const_newton_G; + const double const_G = e->physical_constants->const_newton_G; TIMER_TIC; /* Anything to do here? */ - if (c->ti_end_min > ti_current) { + if (!cell_is_active(c, e)) { c->updated = 0; c->g_updated = 0; return; } -#ifdef TASK_VERBOSE - OUT; -#endif - int updated = 0, g_updated = 0; int ti_end_min = max_nr_timesteps, ti_end_max = 0; @@ -1049,7 +937,7 @@ void runner_do_kick(struct runner *r, struct cell *c, int timer) { /* If the g-particle has no counterpart and needs to be kicked */ if (gp->id_or_neg_offset > 0) { - if (gp->ti_end <= ti_current) { + if (gpart_is_active(gp, e)) { /* First, finish the force calculation */ gravity_end_force(gp, const_G); @@ -1080,7 +968,7 @@ void runner_do_kick(struct runner *r, struct cell *c, int timer) { struct xpart *restrict xp = &xparts[k]; /* If particle needs to be kicked */ - if (p->ti_end <= ti_current) { + if (part_is_active(p, e)) { /* First, finish the force loop */ hydro_end_force(p); @@ -1231,12 +1119,14 @@ void *runner_main(void *data) { /* Get the cells. */ struct cell *ci = t->ci; struct cell *cj = t->cj; +#ifdef SWIFT_DEBUG_TASKS t->rid = r->cpuid; +#endif /* Check that we haven't scheduled an inactive task */ #ifdef SWIFT_DEBUG_CHECKS if (cj == NULL) { /* self */ - if (ci->ti_end_min > e->ti_current && t->type != task_type_sort) + if (!cell_is_active(ci, e) && t->type != task_type_sort) error( "Task (type='%s/%s') should have been skipped ti_current=%d " "c->ti_end_min=%d", @@ -1244,7 +1134,7 @@ void *runner_main(void *data) { ci->ti_end_min); /* Special case for sorts */ - if (ci->ti_end_min > e->ti_current && t->type == task_type_sort && + if (!cell_is_active(ci, e) && t->type == task_type_sort && t->flags == 0) error( "Task (type='%s/%s') should have been skipped ti_current=%d " @@ -1253,7 +1143,7 @@ void *runner_main(void *data) { ci->ti_end_min, t->flags); } else { /* pair */ - if (ci->ti_end_min > e->ti_current && cj->ti_end_min > e->ti_current) + if (!cell_is_active(ci, e) && !cell_is_active(cj, e)) error( "Task (type='%s/%s') should have been skipped ti_current=%d " "ci->ti_end_min=%d cj->ti_end_min=%d", @@ -1277,7 +1167,7 @@ void *runner_main(void *data) { else if (t->subtype == task_subtype_external_grav) runner_do_grav_external(r, ci, 1); else - error("Unknown task subtype."); + error("Unknown/invalid task subtype (%d).", t->subtype); break; case task_type_pair: @@ -1292,7 +1182,7 @@ void *runner_main(void *data) { else if (t->subtype == task_subtype_grav) runner_dopair_grav(r, ci, cj, 1); else - error("Unknown task subtype."); + error("Unknown/invalid task subtype (%d).", t->subtype); break; case task_type_sub_self: @@ -1309,7 +1199,7 @@ void *runner_main(void *data) { else if (t->subtype == task_subtype_external_grav) runner_do_grav_external(r, ci, 1); else - error("Unknown task subtype."); + error("Unknown/invalid task subtype (%d).", t->subtype); break; case task_type_sub_pair: @@ -1324,7 +1214,7 @@ void *runner_main(void *data) { else if (t->subtype == task_subtype_grav) runner_dosub_grav(r, ci, cj, 1); else - error("Unknown task subtype."); + error("Unknown/invalid task subtype (%d).", t->subtype); break; case task_type_sort: @@ -1334,19 +1224,16 @@ void *runner_main(void *data) { runner_do_init(r, ci, 1); break; case task_type_ghost: - runner_do_ghost(r, ci); + runner_do_ghost(r, ci, 1); break; #ifdef EXTRA_HYDRO_LOOP case task_type_extra_ghost: - runner_do_extra_ghost(r, ci); + runner_do_extra_ghost(r, ci, 1); break; #endif case task_type_kick: runner_do_kick(r, ci, 1); break; - case task_type_kick_fixdt: - runner_do_kick_fixdt(r, ci, 1); - break; #ifdef WITH_MPI case task_type_send: if (t->subtype == task_subtype_tend) { @@ -1380,7 +1267,7 @@ void *runner_main(void *data) { runner_do_sourceterms(r, t->ci, 1); break; default: - error("Unknown task type."); + error("Unknown/invalid task type (%d).", t->type); } /* We're done with this task, see if we get a next one. */ diff --git a/src/runner.h b/src/runner.h index be19ab61b997f5730a04fa8c01c0787e8b99a8b2..a8caf24248c99438f16729e2cac3e1031535f62b 100644 --- a/src/runner.h +++ b/src/runner.h @@ -48,12 +48,13 @@ struct runner { }; /* Function prototypes. */ -void runner_do_ghost(struct runner *r, struct cell *c); +void runner_do_ghost(struct runner *r, struct cell *c, int timer); +void runner_do_extra_ghost(struct runner *r, struct cell *c, int timer); void runner_do_sort(struct runner *r, struct cell *c, int flag, int clock); void runner_do_kick(struct runner *r, struct cell *c, int timer); -void runner_do_kick_fixdt(struct runner *r, struct cell *c, int timer); void runner_do_init(struct runner *r, struct cell *c, int timer); void runner_do_cooling(struct runner *r, struct cell *c, int timer); +void runner_do_grav_external(struct runner *r, struct cell *c, int timer); void *runner_main(void *data); void runner_do_drift_mapper(void *map_data, int num_elements, void *extra_data); diff --git a/src/runner_doiact.h b/src/runner_doiact.h index 3c968cbf7d955198ad6bb44ab70e93af17735e99..c067d3bc9a576ee9c7dfb6e910eb1aa01012f755 100644 --- a/src/runner_doiact.h +++ b/src/runner_doiact.h @@ -109,7 +109,6 @@ void DOPAIR_NAIVE(struct runner *r, struct cell *restrict ci, struct cell *restrict cj) { const struct engine *e = r->e; - const int ti_current = e->ti_current; error("Don't use in actual runs ! Slow code !"); @@ -124,7 +123,7 @@ void DOPAIR_NAIVE(struct runner *r, struct cell *restrict ci, TIMER_TIC; /* Anything to do here? */ - if (ci->ti_end_min > ti_current && cj->ti_end_min > ti_current) return; + if (!cell_is_active(ci, e) && !cell_is_active(cj, e)) return; const int count_i = ci->count; const int count_j = cj->count; @@ -210,7 +209,7 @@ void DOPAIR_NAIVE(struct runner *r, struct cell *restrict ci, void DOSELF_NAIVE(struct runner *r, struct cell *restrict c) { - const int ti_current = r->e->ti_current; + const struct engine *e = r->e; error("Don't use in actual runs ! Slow code !"); @@ -226,7 +225,7 @@ void DOSELF_NAIVE(struct runner *r, struct cell *restrict c) { TIMER_TIC; /* Anything to do here? */ - if (c->ti_end_min > ti_current) return; + if (!cell_is_active(c, e)) return; const int count = c->count; struct part *restrict parts = c->parts; @@ -706,8 +705,7 @@ void DOSELF_SUBSET(struct runner *r, struct cell *restrict ci, */ void DOPAIR1(struct runner *r, struct cell *ci, struct cell *cj) { - struct engine *restrict e = r->e; - const int ti_current = e->ti_current; + const struct engine *restrict e = r->e; #ifdef WITH_VECTORIZATION int icount = 0; @@ -721,7 +719,7 @@ void DOPAIR1(struct runner *r, struct cell *ci, struct cell *cj) { TIMER_TIC; /* Anything to do here? */ - if (ci->ti_end_min > ti_current && cj->ti_end_min > ti_current) return; + if (!cell_is_active(ci, e) && !cell_is_active(cj, e)) return; /* Get the sort ID. */ double shift[3] = {0.0, 0.0, 0.0}; @@ -756,7 +754,7 @@ void DOPAIR1(struct runner *r, struct cell *ci, struct cell *cj) { /* Get a hold of the ith part in ci. */ struct part *restrict pi = &parts_i[sort_i[pid].i]; - if (pi->ti_end > ti_current) continue; + if (!part_is_active(pi, e)) continue; const float hi = pi->h; const double di = sort_i[pid].d + hi * kernel_gamma + dx_max - rshift; if (di < dj_min) continue; @@ -818,7 +816,7 @@ void DOPAIR1(struct runner *r, struct cell *ci, struct cell *cj) { /* Get a hold of the jth part in cj. */ struct part *restrict pj = &parts_j[sort_j[pjd].i]; - if (pj->ti_end > ti_current) continue; + if (!part_is_active(pj, e)) continue; const float hj = pj->h; const double dj = sort_j[pjd].d - hj * kernel_gamma - dx_max - rshift; if (dj > di_max) continue; @@ -894,7 +892,6 @@ void DOPAIR1(struct runner *r, struct cell *ci, struct cell *cj) { void DOPAIR2(struct runner *r, struct cell *ci, struct cell *cj) { struct engine *restrict e = r->e; - const int ti_current = e->ti_current; #ifdef WITH_VECTORIZATION int icount1 = 0; @@ -914,7 +911,7 @@ void DOPAIR2(struct runner *r, struct cell *ci, struct cell *cj) { TIMER_TIC; /* Anything to do here? */ - if (ci->ti_end_min > ti_current && cj->ti_end_min > ti_current) return; + if (!cell_is_active(ci, e) && !cell_is_active(cj, e)) return; /* Get the shift ID. */ double shift[3] = {0.0, 0.0, 0.0}; @@ -946,28 +943,28 @@ void DOPAIR2(struct runner *r, struct cell *ci, struct cell *cj) { /* Collect the number of parts left and right below dt. */ int countdt_i = 0, countdt_j = 0; struct entry *restrict sortdt_i = NULL, *restrict sortdt_j = NULL; - if (ci->ti_end_max <= ti_current) { + if (cell_is_all_active(ci, e)) { sortdt_i = sort_i; countdt_i = count_i; - } else if (ci->ti_end_min <= ti_current) { + } else if (cell_is_active(ci, e)) { if (posix_memalign((void *)&sortdt_i, VEC_SIZE * sizeof(float), sizeof(struct entry) * count_i) != 0) error("Failed to allocate dt sortlists."); for (int k = 0; k < count_i; k++) - if (parts_i[sort_i[k].i].ti_end <= ti_current) { + if (part_is_active(&parts_i[sort_i[k].i], e)) { sortdt_i[countdt_i] = sort_i[k]; countdt_i += 1; } } - if (cj->ti_end_max <= ti_current) { + if (cell_is_all_active(cj, e)) { sortdt_j = sort_j; countdt_j = count_j; - } else if (cj->ti_end_min <= ti_current) { + } else if (cell_is_active(cj, e)) { if (posix_memalign((void *)&sortdt_j, VEC_SIZE * sizeof(float), sizeof(struct entry) * count_j) != 0) error("Failed to allocate dt sortlists."); for (int k = 0; k < count_j; k++) - if (parts_j[sort_j[k].i].ti_end <= ti_current) { + if (part_is_active(&parts_j[sort_j[k].i], e)) { sortdt_j[countdt_j] = sort_j[k]; countdt_j += 1; } @@ -988,7 +985,7 @@ void DOPAIR2(struct runner *r, struct cell *ci, struct cell *cj) { const float hig2 = hi * hi * kernel_gamma2; /* Look at valid dt parts only? */ - if (pi->ti_end > ti_current) { + if (!part_is_active(pi, e)) { /* Loop over the parts in cj within dt. */ for (int pjd = 0; pjd < countdt_j && sortdt_j[pjd].d < di; pjd++) { @@ -1062,7 +1059,7 @@ void DOPAIR2(struct runner *r, struct cell *ci, struct cell *cj) { #ifndef WITH_VECTORIZATION /* Does pj need to be updated too? */ - if (pj->ti_end <= ti_current) + if (part_is_active(pj, e)) IACT(r2, dx, hi, hj, pi, pj); else IACT_NONSYM(r2, dx, hi, hj, pi, pj); @@ -1070,7 +1067,7 @@ void DOPAIR2(struct runner *r, struct cell *ci, struct cell *cj) { #else /* Does pj need to be updated too? */ - if (pj->ti_end <= ti_current) { + if (part_is_active(pj, e)) { /* Add this interaction to the symmetric queue. */ r2q2[icount2] = r2; @@ -1132,7 +1129,7 @@ void DOPAIR2(struct runner *r, struct cell *ci, struct cell *cj) { const float hjg2 = hj * hj * kernel_gamma2; /* Is this particle outside the dt? */ - if (pj->ti_end > ti_current) { + if (!part_is_active(pj, e)) { /* Loop over the parts in ci. */ for (int pid = countdt_i - 1; pid >= 0 && sortdt_i[pid].d > dj; pid--) { @@ -1205,7 +1202,7 @@ void DOPAIR2(struct runner *r, struct cell *ci, struct cell *cj) { #ifndef WITH_VECTORIZATION /* Does pi need to be updated too? */ - if (pi->ti_end <= ti_current) + if (part_is_active(pi, e)) IACT(r2, dx, hj, hi, pj, pi); else IACT_NONSYM(r2, dx, hj, hi, pj, pi); @@ -1213,7 +1210,7 @@ void DOPAIR2(struct runner *r, struct cell *ci, struct cell *cj) { #else /* Does pi need to be updated too? */ - if (pi->ti_end <= ti_current) { + if (part_is_active(pi, e)) { /* Add this interaction to the symmetric queue. */ r2q2[icount2] = r2; @@ -1270,10 +1267,9 @@ void DOPAIR2(struct runner *r, struct cell *ci, struct cell *cj) { IACT(r2q2[k], &dxq2[3 * k], hiq2[k], hjq2[k], piq2[k], pjq2[k]); #endif - if (ci->ti_end_max > ti_current && ci->ti_end_min <= ti_current) - free(sortdt_i); - if (cj->ti_end_max > ti_current && cj->ti_end_min <= ti_current) - free(sortdt_j); + /* Clean-up if necessary */ + if (cell_is_active(ci, e) && !cell_is_all_active(ci, e)) free(sortdt_i); + if (cell_is_active(cj, e) && !cell_is_all_active(cj, e)) free(sortdt_j); TIMER_TOC(TIMER_DOPAIR); } @@ -1286,7 +1282,7 @@ void DOPAIR2(struct runner *r, struct cell *ci, struct cell *cj) { */ void DOSELF1(struct runner *r, struct cell *restrict c) { - const int ti_current = r->e->ti_current; + const struct engine *e = r->e; #ifdef WITH_VECTORIZATION int icount1 = 0; @@ -1305,8 +1301,7 @@ void DOSELF1(struct runner *r, struct cell *restrict c) { TIMER_TIC; - if (c->ti_end_min > ti_current) return; - if (c->ti_end_max < ti_current) error("Cell in an impossible time-zone"); + if (!cell_is_active(c, e)) return; struct part *restrict parts = c->parts; const int count = c->count; @@ -1318,7 +1313,7 @@ void DOSELF1(struct runner *r, struct cell *restrict c) { count * sizeof(int)) != 0) error("Failed to allocate indt."); for (int k = 0; k < count; k++) - if (parts[k].ti_end <= ti_current) { + if (part_is_active(&parts[k], e)) { indt[countdt] = k; countdt += 1; } @@ -1336,7 +1331,7 @@ void DOSELF1(struct runner *r, struct cell *restrict c) { const float hig2 = hi * hi * kernel_gamma2; /* Is the ith particle inactive? */ - if (pi->ti_end > ti_current) { + if (!part_is_active(pi, e)) { /* Loop over the other particles .*/ for (int pjd = firstdt; pjd < countdt; pjd++) { @@ -1407,7 +1402,7 @@ void DOSELF1(struct runner *r, struct cell *restrict c) { r2 += dx[k] * dx[k]; } const int doj = - (pj->ti_end <= ti_current) && (r2 < hj * hj * kernel_gamma2); + (part_is_active(pj, e)) && (r2 < hj * hj * kernel_gamma2); /* Hit or miss? */ if (r2 < hig2 || doj) { @@ -1518,7 +1513,7 @@ void DOSELF1(struct runner *r, struct cell *restrict c) { */ void DOSELF2(struct runner *r, struct cell *restrict c) { - const int ti_current = r->e->ti_current; + const struct engine *e = r->e; #ifdef WITH_VECTORIZATION int icount1 = 0; @@ -1537,8 +1532,7 @@ void DOSELF2(struct runner *r, struct cell *restrict c) { TIMER_TIC; - if (c->ti_end_min > ti_current) return; - if (c->ti_end_max < ti_current) error("Cell in an impossible time-zone"); + if (!cell_is_active(c, e)) return; struct part *restrict parts = c->parts; const int count = c->count; @@ -1550,7 +1544,7 @@ void DOSELF2(struct runner *r, struct cell *restrict c) { count * sizeof(int)) != 0) error("Failed to allocate indt."); for (int k = 0; k < count; k++) - if (parts[k].ti_end <= ti_current) { + if (part_is_active(&parts[k], e)) { indt[countdt] = k; countdt += 1; } @@ -1568,7 +1562,7 @@ void DOSELF2(struct runner *r, struct cell *restrict c) { const float hig2 = hi * hi * kernel_gamma2; /* Is the ith particle not active? */ - if (pi->ti_end > ti_current) { + if (!part_is_active(pi, e)) { /* Loop over the other particles .*/ for (int pjd = firstdt; pjd < countdt; pjd++) { @@ -1645,7 +1639,7 @@ void DOSELF2(struct runner *r, struct cell *restrict c) { #ifndef WITH_VECTORIZATION /* Does pj need to be updated too? */ - if (pj->ti_end <= ti_current) + if (part_is_active(pj, e)) IACT(r2, dx, hi, hj, pi, pj); else IACT_NONSYM(r2, dx, hi, hj, pi, pj); @@ -1653,7 +1647,7 @@ void DOSELF2(struct runner *r, struct cell *restrict c) { #else /* Does pj need to be updated too? */ - if (pj->ti_end <= ti_current) { + if (part_is_active(pj, e)) { /* Add this interaction to the symmetric queue. */ r2q2[icount2] = r2; @@ -1731,12 +1725,12 @@ void DOSUB_PAIR1(struct runner *r, struct cell *ci, struct cell *cj, int sid, int gettimer) { struct space *s = r->e->s; - const int ti_current = r->e->ti_current; + const struct engine *e = r->e; TIMER_TIC; /* Should we even bother? */ - if (ci->ti_end_min > ti_current && cj->ti_end_min > ti_current) return; + if (!cell_is_active(ci, e) && !cell_is_active(cj, e)) return; /* Get the cell dimensions. */ const float h = min(ci->width[0], min(ci->width[1], ci->width[2])); @@ -1950,7 +1944,7 @@ void DOSUB_PAIR1(struct runner *r, struct cell *ci, struct cell *cj, int sid, } /* Otherwise, compute the pair directly. */ - else if (ci->ti_end_min <= ti_current || cj->ti_end_min <= ti_current) { + else if (cell_is_active(ci, e) || cell_is_active(cj, e)) { /* Do any of the cells need to be sorted first? */ if (!(ci->sorted & (1 << sid))) runner_do_sort(r, ci, (1 << sid), 1); @@ -1972,12 +1966,10 @@ void DOSUB_PAIR1(struct runner *r, struct cell *ci, struct cell *cj, int sid, */ void DOSUB_SELF1(struct runner *r, struct cell *ci, int gettimer) { - const int ti_current = r->e->ti_current; - TIMER_TIC; /* Should we even bother? */ - if (ci->ti_end_min > ti_current) return; + if (!cell_is_active(ci, r->e)) return; /* Recurse? */ if (ci->split) { @@ -2014,13 +2006,13 @@ void DOSUB_SELF1(struct runner *r, struct cell *ci, int gettimer) { void DOSUB_PAIR2(struct runner *r, struct cell *ci, struct cell *cj, int sid, int gettimer) { - struct space *s = r->e->s; - const int ti_current = r->e->ti_current; + const struct engine *e = r->e; + struct space *s = e->s; TIMER_TIC; /* Should we even bother? */ - if (ci->ti_end_min > ti_current && cj->ti_end_min > ti_current) return; + if (!cell_is_active(ci, e) && !cell_is_active(cj, e)) return; /* Get the cell dimensions. */ const float h = min(ci->width[0], min(ci->width[1], ci->width[2])); @@ -2234,7 +2226,7 @@ void DOSUB_PAIR2(struct runner *r, struct cell *ci, struct cell *cj, int sid, } /* Otherwise, compute the pair directly. */ - else if (ci->ti_end_min <= ti_current || cj->ti_end_min <= ti_current) { + else if (cell_is_active(ci, e) || cell_is_active(cj, e)) { /* Do any of the cells need to be sorted first? */ if (!(ci->sorted & (1 << sid))) runner_do_sort(r, ci, (1 << sid), 1); @@ -2256,12 +2248,10 @@ void DOSUB_PAIR2(struct runner *r, struct cell *ci, struct cell *cj, int sid, */ void DOSUB_SELF2(struct runner *r, struct cell *ci, int gettimer) { - const int ti_current = r->e->ti_current; - TIMER_TIC; /* Should we even bother? */ - if (ci->ti_end_min > ti_current) return; + if (!cell_is_active(ci, r->e)) return; /* Recurse? */ if (ci->split) { @@ -2287,8 +2277,8 @@ void DOSUB_SELF2(struct runner *r, struct cell *ci, int gettimer) { void DOSUB_SUBSET(struct runner *r, struct cell *ci, struct part *parts, int *ind, int count, struct cell *cj, int sid, int gettimer) { - struct space *s = r->e->s; - const int ti_current = r->e->ti_current; + const struct engine *e = r->e; + struct space *s = e->s; TIMER_TIC; @@ -2850,7 +2840,7 @@ void DOSUB_SUBSET(struct runner *r, struct cell *ci, struct part *parts, } /* Otherwise, compute the pair directly. */ - else if (ci->ti_end_min <= ti_current || cj->ti_end_min <= ti_current) { + else if (cell_is_active(ci, e) || cell_is_active(cj, e)) { /* Get the relative distance between the pairs, wrapping. */ double shift[3] = {0.0, 0.0, 0.0}; diff --git a/src/runner_doiact_grav.h b/src/runner_doiact_grav.h index 0fcd2d2e80a72b92588acd5b8275b9dafc68df45..59a5ae496680390c23458bde65b4bba321ffe7a1 100644 --- a/src/runner_doiact_grav.h +++ b/src/runner_doiact_grav.h @@ -71,7 +71,6 @@ __attribute__((always_inline)) INLINE static void runner_dopair_grav_pm( const int gcount = ci->gcount; struct gpart *restrict gparts = ci->gparts; const struct multipole multi = cj->multipole; - const int ti_current = e->ti_current; const float rlr_inv = 1. / (const_gravity_a_smooth * ci->super->width[0]); TIMER_TIC; @@ -84,7 +83,7 @@ __attribute__((always_inline)) INLINE static void runner_dopair_grav_pm( #endif /* Anything to do here? */ - if (ci->ti_end_min > ti_current) return; + if (!cell_is_active(ci, e)) return; #if ICHECK > 0 for (int pid = 0; pid < gcount; pid++) { @@ -105,7 +104,7 @@ __attribute__((always_inline)) INLINE static void runner_dopair_grav_pm( /* Get a hold of the ith part in ci. */ struct gpart *restrict gp = &gparts[pid]; - if (gp->ti_end > ti_current) continue; + if (!gpart_is_active(gp, e)) continue; /* Compute the pairwise distance. */ const float dx[3] = {multi.CoM[0] - gp->x[0], // x @@ -138,7 +137,6 @@ __attribute__((always_inline)) INLINE static void runner_dopair_grav_pp( const int gcount_j = cj->gcount; struct gpart *restrict gparts_i = ci->gparts; struct gpart *restrict gparts_j = cj->gparts; - const int ti_current = e->ti_current; const float rlr_inv = 1. / (const_gravity_a_smooth * ci->super->width[0]); TIMER_TIC; @@ -150,7 +148,7 @@ __attribute__((always_inline)) INLINE static void runner_dopair_grav_pp( #endif /* Anything to do here? */ - if (ci->ti_end_min > ti_current && cj->ti_end_min > ti_current) return; + if (!cell_is_active(ci, e) && !cell_is_active(cj, e)) return; #if ICHECK > 0 for (int pid = 0; pid < gcount_i; pid++) { @@ -195,17 +193,17 @@ __attribute__((always_inline)) INLINE static void runner_dopair_grav_pp( const float r2 = dx[0] * dx[0] + dx[1] * dx[1] + dx[2] * dx[2]; /* Interact ! */ - if (gpi->ti_end <= ti_current && gpj->ti_end <= ti_current) { + if (gpart_is_active(gpi, e) && gpart_is_active(gpj, e)) { runner_iact_grav_pp(rlr_inv, r2, dx, gpi, gpj); } else { - if (gpi->ti_end <= ti_current) { + if (gpart_is_active(gpi, e)) { runner_iact_grav_pp_nonsym(rlr_inv, r2, dx, gpi, gpj); - } else if (gpj->ti_end <= ti_current) { + } else if (gpart_is_active(gpj, e)) { dx[0] = -dx[0]; dx[1] = -dx[1]; @@ -233,7 +231,6 @@ __attribute__((always_inline)) INLINE static void runner_doself_grav_pp( const struct engine *e = r->e; const int gcount = c->gcount; struct gpart *restrict gparts = c->gparts; - const int ti_current = e->ti_current; const float rlr_inv = 1. / (const_gravity_a_smooth * c->super->width[0]); TIMER_TIC; @@ -244,7 +241,7 @@ __attribute__((always_inline)) INLINE static void runner_doself_grav_pp( #endif /* Anything to do here? */ - if (c->ti_end_min > ti_current) return; + if (!cell_is_active(c, e)) return; #if ICHECK > 0 for (int pid = 0; pid < gcount; pid++) { @@ -278,17 +275,17 @@ __attribute__((always_inline)) INLINE static void runner_doself_grav_pp( const float r2 = dx[0] * dx[0] + dx[1] * dx[1] + dx[2] * dx[2]; /* Interact ! */ - if (gpi->ti_end <= ti_current && gpj->ti_end <= ti_current) { + if (gpart_is_active(gpi, e) && gpart_is_active(gpj, e)) { runner_iact_grav_pp(rlr_inv, r2, dx, gpi, gpj); } else { - if (gpi->ti_end <= ti_current) { + if (gpart_is_active(gpi, e)) { runner_iact_grav_pp_nonsym(rlr_inv, r2, dx, gpi, gpj); - } else if (gpj->ti_end <= ti_current) { + } else if (gpart_is_active(gpj, e)) { dx[0] = -dx[0]; dx[1] = -dx[1]; @@ -490,14 +487,13 @@ static void runner_do_grav_mm(struct runner *r, struct cell *ci, int timer) { const struct engine *e = r->e; struct cell *cells = e->s->cells_top; const int nr_cells = e->s->nr_cells; - const int ti_current = e->ti_current; const double max_d = const_gravity_a_smooth * const_gravity_r_cut * ci->width[0]; const double max_d2 = max_d * max_d; const double pos_i[3] = {ci->loc[0], ci->loc[1], ci->loc[2]}; /* Anything to do here? */ - if (ci->ti_end_min > ti_current) return; + if (!cell_is_active(ci, e)) return; /* Loop over all the cells and go for a p-m interaction if far enough but not * too far */ diff --git a/src/scheduler.c b/src/scheduler.c index 44790fcd2fa5f67e6f325ba5849da19e35ab285a..13527d97599b9cdcff18a0143d6238559a3af450 100644 --- a/src/scheduler.c +++ b/src/scheduler.c @@ -42,6 +42,7 @@ #include "atomic.h" #include "const.h" #include "cycle.h" +#include "engine.h" #include "error.h" #include "intrinsics.h" #include "kernel_hydro.h" @@ -53,7 +54,6 @@ /** * @brief Re-set the list of active tasks. */ - void scheduler_clear_active(struct scheduler *s) { s->active_count = 0; } /** @@ -63,7 +63,6 @@ void scheduler_clear_active(struct scheduler *s) { s->active_count = 0; } * @param ta The unlocking #task. * @param tb The #task that will be unlocked. */ - void scheduler_addunlock(struct scheduler *s, struct task *ta, struct task *tb) { /* Get an index at which to store this unlock. */ @@ -113,7 +112,6 @@ void scheduler_addunlock(struct scheduler *s, struct task *ta, * @param t The #task * @param s The #scheduler we are working in. */ - static void scheduler_splittask(struct task *t, struct scheduler *s) { /* Static constants. */ @@ -183,16 +181,19 @@ static void scheduler_splittask(struct task *t, struct scheduler *s) { ci->progeny[k], NULL, 0), s); - /* Make a task for each pair of progeny. */ - for (int j = 0; j < 8; j++) - if (ci->progeny[j] != NULL) - for (int k = j + 1; k < 8; k++) - if (ci->progeny[k] != NULL) - scheduler_splittask( - scheduler_addtask(s, task_type_pair, t->subtype, - pts[j][k], 0, ci->progeny[j], - ci->progeny[k], 0), - s); + /* Make a task for each pair of progeny unless it's ext. gravity. */ + if (t->subtype != task_subtype_external_grav) { + + for (int j = 0; j < 8; j++) + if (ci->progeny[j] != NULL) + for (int k = j + 1; k < 8; k++) + if (ci->progeny[k] != NULL) + scheduler_splittask( + scheduler_addtask(s, task_type_pair, t->subtype, + pts[j][k], 0, ci->progeny[j], + ci->progeny[k], 0), + s); + } } } @@ -649,7 +650,6 @@ static void scheduler_splittask(struct task *t, struct scheduler *s) { * @param num_elements the number of tasks. * @param extra_data The #scheduler we are working in. */ - void scheduler_splittasks_mapper(void *map_data, int num_elements, void *extra_data) { @@ -663,6 +663,11 @@ void scheduler_splittasks_mapper(void *map_data, int num_elements, } } +/** + * @brief Splits all the tasks in the scheduler that are too large. + * + * @param s The #scheduler. + */ void scheduler_splittasks(struct scheduler *s) { /* Call the mapper on each current task. */ @@ -677,12 +682,11 @@ void scheduler_splittasks(struct scheduler *s) { * @param type The type of the task. * @param subtype The sub-type of the task. * @param flags The flags of the task. - * @param wait + * @param wait The number of unsatisfied dependencies of this task. * @param ci The first cell to interact. * @param cj The second cell to interact. * @param tight */ - struct task *scheduler_addtask(struct scheduler *s, enum task_types type, enum task_subtypes subtype, int flags, int wait, struct cell *ci, struct cell *cj, int tight) { @@ -708,10 +712,12 @@ struct task *scheduler_addtask(struct scheduler *s, enum task_types type, t->implicit = 0; t->weight = 0; t->rank = 0; - t->tic = 0; - t->toc = 0; t->nr_unlock_tasks = 0; +#ifdef SWIFT_DEBUG_TASKS t->rid = -1; + t->tic = 0; + t->toc = 0; +#endif /* Add an index for it. */ // lock_lock( &s->lock ); @@ -727,7 +733,6 @@ struct task *scheduler_addtask(struct scheduler *s, enum task_types type, * * @param s The #scheduler. */ - void scheduler_set_unlocks(struct scheduler *s) { /* Store the counts for each task. */ @@ -794,7 +799,6 @@ void scheduler_set_unlocks(struct scheduler *s) { * * @param s The #scheduler. */ - void scheduler_ranktasks(struct scheduler *s) { struct task *tasks = s->tasks; @@ -860,7 +864,6 @@ void scheduler_ranktasks(struct scheduler *s) { * @param s The #scheduler. * @param size The maximum number of tasks in the #scheduler. */ - void scheduler_reset(struct scheduler *s, int size) { /* Do we need to re-allocate? */ @@ -888,8 +891,6 @@ void scheduler_reset(struct scheduler *s, int size) { s->nr_tasks = 0; s->tasks_next = 0; s->waiting = 0; - s->mask = 0; - s->submask = 0; s->nr_unlocks = 0; s->completed_unlock_writes = 0; s->active_count = 0; @@ -904,7 +905,6 @@ void scheduler_reset(struct scheduler *s, int size) { * @param s The #scheduler. * @param verbose Are we talkative? */ - void scheduler_reweight(struct scheduler *s, int verbose) { const int nr_tasks = s->nr_tasks; @@ -924,55 +924,56 @@ void scheduler_reweight(struct scheduler *s, int verbose) { for (int j = 0; j < t->nr_unlock_tasks; j++) if (t->unlock_tasks[j]->weight > t->weight) t->weight = t->unlock_tasks[j]->weight; - if (!t->implicit && t->tic > 0) - t->weight += wscale * (t->toc - t->tic); - else - switch (t->type) { - case task_type_sort: - t->weight += wscale * intrinsics_popcount(t->flags) * t->ci->count * - (sizeof(int) * 8 - intrinsics_clz(t->ci->count)); - break; - case task_type_self: - t->weight += 1 * wscale * t->ci->count * t->ci->count; - break; - case task_type_pair: - if (t->ci->nodeID != nodeID || t->cj->nodeID != nodeID) - t->weight += + int cost = 0; + switch (t->type) { + case task_type_sort: + cost = wscale * intrinsics_popcount(t->flags) * t->ci->count * + (sizeof(int) * 8 - intrinsics_clz(t->ci->count)); + break; + case task_type_self: + cost = 1 * wscale * t->ci->count * t->ci->count; + break; + case task_type_pair: + if (t->ci->nodeID != nodeID || t->cj->nodeID != nodeID) + cost = 3 * wscale * t->ci->count * t->cj->count * sid_scale[t->flags]; + else + cost = 2 * wscale * t->ci->count * t->cj->count * sid_scale[t->flags]; + break; + case task_type_sub_pair: + if (t->ci->nodeID != nodeID || t->cj->nodeID != nodeID) { + if (t->flags < 0) + cost = 3 * wscale * t->ci->count * t->cj->count; + else + cost = 3 * wscale * t->ci->count * t->cj->count * sid_scale[t->flags]; + } else { + if (t->flags < 0) + cost = 2 * wscale * t->ci->count * t->cj->count; else - t->weight += + cost = 2 * wscale * t->ci->count * t->cj->count * sid_scale[t->flags]; - break; - case task_type_sub_pair: - if (t->ci->nodeID != nodeID || t->cj->nodeID != nodeID) { - if (t->flags < 0) - t->weight += 3 * wscale * t->ci->count * t->cj->count; - else - t->weight += 3 * wscale * t->ci->count * t->cj->count * - sid_scale[t->flags]; - } else { - if (t->flags < 0) - t->weight += 2 * wscale * t->ci->count * t->cj->count; - else - t->weight += 2 * wscale * t->ci->count * t->cj->count * - sid_scale[t->flags]; - } - break; - case task_type_sub_self: - t->weight += 1 * wscale * t->ci->count * t->ci->count; - break; - case task_type_ghost: - if (t->ci == t->ci->super) t->weight += wscale * t->ci->count; - break; - case task_type_kick: - t->weight += wscale * t->ci->count; - break; - case task_type_init: - t->weight += wscale * t->ci->count; - break; - default: - break; - } + } + break; + case task_type_sub_self: + cost = 1 * wscale * t->ci->count * t->ci->count; + break; + case task_type_ghost: + if (t->ci == t->ci->super) cost = wscale * t->ci->count; + break; + case task_type_kick: + cost = wscale * t->ci->count; + break; + case task_type_init: + cost = wscale * t->ci->count; + break; + default: + cost = 0; + break; + } +#if defined(WITH_MPI) && defined(HAVE_METIS) + t->cost = cost; +#endif + t->weight += cost; } if (verbose) @@ -992,19 +993,15 @@ void scheduler_reweight(struct scheduler *s, int verbose) { * @brief #threadpool_map function which runs through the task * graph and re-computes the task wait counters. */ - void scheduler_rewait_mapper(void *map_data, int num_elements, void *extra_data) { - struct scheduler *s = (struct scheduler *)extra_data; struct task *tasks = (struct task *)map_data; for (int ind = 0; ind < num_elements; ind++) { struct task *t = &tasks[ind]; - if (t->skip || !((1 << t->type) & s->mask) || - !((1 << t->subtype) & s->submask)) - continue; + if (t->skip) continue; /* Skip sort tasks that have already been performed */ if (t->type == task_type_sort && t->flags == 0) { @@ -1026,8 +1023,7 @@ void scheduler_enqueue_mapper(void *map_data, int num_elements, struct task *tasks = s->tasks; for (int ind = 0; ind < num_elements; ind++) { struct task *t = &tasks[tid[ind]]; - if (atomic_dec(&t->wait) == 1 && !t->skip && ((1 << t->type) & s->mask) && - ((1 << t->subtype) & s->submask)) { + if (atomic_dec(&t->wait) == 1 && !t->skip) { scheduler_enqueue(s, t); } } @@ -1038,79 +1034,66 @@ void scheduler_enqueue_mapper(void *map_data, int num_elements, * @brief Start the scheduler, i.e. fill the queues with ready tasks. * * @param s The #scheduler. - * @param mask The task types to enqueue. - * @param submask The sub-task types to enqueue. */ +void scheduler_start(struct scheduler *s) { -void scheduler_start(struct scheduler *s, unsigned int mask, - unsigned int submask) { - - /* Store the masks */ - s->mask = mask; - s->submask = submask | (1 << task_subtype_none); - - /* Clear all the waits, rids, and times. */ - for (int k = 0; k < s->nr_tasks; k++) { - s->tasks[k].wait = 1; - s->tasks[k].rid = -1; - s->tasks[k].tic = 0; - s->tasks[k].toc = 0; - if (((1 << s->tasks[k].type) & mask) == 0 || - ((1 << s->tasks[k].subtype) & s->submask) == 0) - s->tasks[k].skip = 1; - } + /* Clear all the waits. */ + for (int k = 0; k < s->nr_tasks; k++) s->tasks[k].wait = 1; /* Re-wait the tasks. */ threadpool_map(s->threadpool, scheduler_rewait_mapper, s->tasks, s->nr_tasks, - sizeof(struct task), 1000, s); + sizeof(struct task), 1000, NULL); /* Check we have not missed an active task */ #ifdef SWIFT_DEBUG_CHECKS const int ti_current = s->space->e->ti_current; - for (int k = 0; k < s->nr_tasks; k++) { - struct task *t = &s->tasks[k]; - struct cell *ci = t->ci; - struct cell *cj = t->cj; - - if (cj == NULL) { /* self */ - - if (ci->ti_end_min == ti_current && t->skip && t->type != task_type_sort) - error( - "Task (type='%s/%s') should not have been skipped ti_current=%d " - "c->ti_end_min=%d", - taskID_names[t->type], subtaskID_names[t->subtype], ti_current, - ci->ti_end_min); - - /* Special treatment for sort tasks */ - if (ci->ti_end_min == ti_current && t->skip && - t->type == task_type_sort && t->flags == 0) - error( - "Task (type='%s/%s') should not have been skipped ti_current=%d " - "c->ti_end_min=%d t->flags=%d", - taskID_names[t->type], subtaskID_names[t->subtype], ti_current, - ci->ti_end_min, t->flags); - - } else { /* pair */ - - if ((ci->ti_end_min == ti_current || cj->ti_end_min == ti_current) && - t->skip) - error( - "Task (type='%s/%s') should not have been skipped ti_current=%d " - "ci->ti_end_min=%d cj->ti_end_min=%d", - taskID_names[t->type], subtaskID_names[t->subtype], ti_current, - ci->ti_end_min, cj->ti_end_min); + if (ti_current > 0) { + + for (int k = 0; k < s->nr_tasks; k++) { + + struct task *t = &s->tasks[k]; + struct cell *ci = t->ci; + struct cell *cj = t->cj; + + if (cj == NULL) { /* self */ + + if (ci->ti_end_min == ti_current && t->skip && + t->type != task_type_sort) + error( + "Task (type='%s/%s') should not have been skipped ti_current=%d " + "c->ti_end_min=%d", + taskID_names[t->type], subtaskID_names[t->subtype], ti_current, + ci->ti_end_min); + + /* Special treatment for sort tasks */ + if (ci->ti_end_min == ti_current && t->skip && + t->type == task_type_sort && t->flags == 0) + error( + "Task (type='%s/%s') should not have been skipped ti_current=%d " + "c->ti_end_min=%d t->flags=%d", + taskID_names[t->type], subtaskID_names[t->subtype], ti_current, + ci->ti_end_min, t->flags); + + } else { /* pair */ + + if ((ci->ti_end_min == ti_current || cj->ti_end_min == ti_current) && + t->skip) + error( + "Task (type='%s/%s') should not have been skipped ti_current=%d " + "ci->ti_end_min=%d cj->ti_end_min=%d", + taskID_names[t->type], subtaskID_names[t->subtype], ti_current, + ci->ti_end_min, cj->ti_end_min); + } } } - #endif /* Loop over the tasks and enqueue whoever is ready. */ for (int k = 0; k < s->active_count; k++) { struct task *t = &s->tasks[s->tid_active[k]]; - if (atomic_dec(&t->wait) == 1 && !t->skip && ((1 << t->type) & s->mask) && - ((1 << t->subtype) & s->submask)) { + if (atomic_dec(&t->wait) == 1 && !t->skip) { scheduler_enqueue(s, t); pthread_cond_signal(&s->sleep_cond); } @@ -1131,20 +1114,13 @@ void scheduler_start(struct scheduler *s, unsigned int mask, * @param s The #scheduler. * @param t The #task. */ - void scheduler_enqueue(struct scheduler *s, struct task *t) { /* The target queue for this task. */ int qid = -1; - /* Fail if this task has already been enqueued before. */ - if (t->rid >= 0) error("Task has already been enqueued."); - - /* Ignore skipped tasks and tasks not in the masks. */ - if (t->skip || (1 << t->type) & ~(s->mask) || - (1 << t->subtype) & ~(s->submask)) { - return; - } + /* Ignore skipped tasks */ + if (t->skip) return; /* If this is an implicit task, just pretend it's done. */ if (t->implicit) { @@ -1247,7 +1223,6 @@ void scheduler_enqueue(struct scheduler *s, struct task *t) { * @return A pointer to the next task, if a suitable one has * been identified. */ - struct task *scheduler_done(struct scheduler *s, struct task *t) { /* Release whatever locks this task held. */ @@ -1268,7 +1243,9 @@ struct task *scheduler_done(struct scheduler *s, struct task *t) { /* Task definitely done, signal any sleeping runners. */ if (!t->implicit) { +#ifdef SWIFT_DEBUG_TASKS t->toc = getticks(); +#endif pthread_mutex_lock(&s->sleep_mutex); atomic_dec(&s->waiting); pthread_cond_broadcast(&s->sleep_cond); @@ -1293,7 +1270,6 @@ struct task *scheduler_done(struct scheduler *s, struct task *t) { * @return A pointer to the next task, if a suitable one has * been identified. */ - struct task *scheduler_unlock(struct scheduler *s, struct task *t) { /* Loop through the dependencies and add them to a queue if @@ -1310,7 +1286,9 @@ struct task *scheduler_unlock(struct scheduler *s, struct task *t) { /* Task definitely done. */ if (!t->implicit) { +#ifdef SWIFT_DEBUG_TASKS t->toc = getticks(); +#endif pthread_mutex_lock(&s->sleep_mutex); atomic_dec(&s->waiting); pthread_cond_broadcast(&s->sleep_cond); @@ -1332,7 +1310,6 @@ struct task *scheduler_unlock(struct scheduler *s, struct task *t) { * * @return A pointer to a #task or @c NULL if there are no available tasks. */ - struct task *scheduler_gettask(struct scheduler *s, int qid, const struct task *prev) { @@ -1381,10 +1358,11 @@ struct task *scheduler_gettask(struct scheduler *s, int qid, /* If we failed, take a short nap. */ #ifdef WITH_MPI - if (res == NULL && qid > 1) { + if (res == NULL && qid > 1) #else - if (res == NULL) { + if (res == NULL) #endif + { pthread_mutex_lock(&s->sleep_mutex); res = queue_gettask(&s->queues[qid], prev, 1); if (res == NULL && s->waiting > 0) { @@ -1394,11 +1372,13 @@ struct task *scheduler_gettask(struct scheduler *s, int qid, } } +#ifdef SWIFT_DEBUG_TASKS /* Start the timer on this task, if we got one. */ if (res != NULL) { res->tic = getticks(); res->rid = qid; } +#endif /* No milk today. */ return res; @@ -1415,7 +1395,6 @@ struct task *scheduler_gettask(struct scheduler *s, int qid, * @param nodeID The MPI rank * @param tp Parallel processing threadpool. */ - void scheduler_init(struct scheduler *s, struct space *space, int nr_tasks, int nr_queues, unsigned int flags, int nodeID, struct threadpool *tp) { diff --git a/src/scheduler.h b/src/scheduler.h index 22c83ae3c551d4dc7e601e23f7a5301241bd1fa4..8631d22cce6cc5925f154a8f3c875dc8d38d5c8b 100644 --- a/src/scheduler.h +++ b/src/scheduler.h @@ -60,12 +60,6 @@ struct scheduler { /* Scheduler flags. */ unsigned int flags; - /* Scheduler task mask */ - unsigned int mask; - - /* Scheduler sub-task mask */ - unsigned int submask; - /* Number of queues in this scheduler. */ int nr_queues; @@ -117,7 +111,6 @@ struct scheduler { * @param s The #scheduler. * @param t The task to be added. */ - __attribute__((always_inline)) INLINE static void scheduler_activate( struct scheduler *s, struct task *t) { if (atomic_cas(&t->skip, 1, 0)) { @@ -134,8 +127,7 @@ void scheduler_init(struct scheduler *s, struct space *space, int nr_tasks, struct task *scheduler_gettask(struct scheduler *s, int qid, const struct task *prev); void scheduler_enqueue(struct scheduler *s, struct task *t); -void scheduler_start(struct scheduler *s, unsigned int mask, - unsigned int submask); +void scheduler_start(struct scheduler *s); void scheduler_reset(struct scheduler *s, int nr_tasks); void scheduler_ranktasks(struct scheduler *s); void scheduler_reweight(struct scheduler *s, int verbose); diff --git a/src/sourceterms/sn_feedback/sn_feedback_struct.h b/src/sourceterms/sn_feedback/sn_feedback_struct.h index 2b4dbe97b0a687cc48d0ba7e12b105f306cb7e96..dd1842a6717c6c5a20352324cbe6b018c73e7b3e 100644 --- a/src/sourceterms/sn_feedback/sn_feedback_struct.h +++ b/src/sourceterms/sn_feedback/sn_feedback_struct.h @@ -42,4 +42,4 @@ struct supernova_struct { double x, y, z; enum supernova_status status; }; -#endif SWIFT_SN_FEEDBACK_STRUCT_H +#endif /* SWIFT_SN_FEEDBACK_STRUCT_H */ diff --git a/src/space.c b/src/space.c index 86c8cc36eacd58c89181831b3c5472026281043c..e04aad2207e736ac8fe4da28b7d22b7c7999765b 100644 --- a/src/space.c +++ b/src/space.c @@ -188,10 +188,9 @@ void space_rebuild_recycle(struct space *s, struct cell *c) { * @brief Re-build the top-level cell grid. * * @param s The #space. - * @param cell_max Maximum cell edge length. * @param verbose Print messages to stdout or not. */ -void space_regrid(struct space *s, double cell_max, int verbose) { +void space_regrid(struct space *s, int verbose) { const size_t nr_parts = s->nr_parts; const ticks tic = getticks(); @@ -226,13 +225,16 @@ void space_regrid(struct space *s, double cell_max, int verbose) { h_max = buff; } #endif - if (verbose) message("h_max is %.3e (cell_max=%.3e).", h_max, cell_max); + if (verbose) message("h_max is %.3e (cell_min=%.3e).", h_max, s->cell_min); /* Get the new putative cell dimensions. */ const int cdim[3] = { - floor(s->dim[0] / fmax(h_max * kernel_gamma * space_stretch, cell_max)), - floor(s->dim[1] / fmax(h_max * kernel_gamma * space_stretch, cell_max)), - floor(s->dim[2] / fmax(h_max * kernel_gamma * space_stretch, cell_max))}; + floor(s->dim[0] / + fmax(h_max * kernel_gamma * space_stretch, s->cell_min)), + floor(s->dim[1] / + fmax(h_max * kernel_gamma * space_stretch, s->cell_min)), + floor(s->dim[2] / + fmax(h_max * kernel_gamma * space_stretch, s->cell_min))}; /* Check if we have enough cells for periodicity. */ if (s->periodic && (cdim[0] < 3 || cdim[1] < 3 || cdim[2] < 3)) @@ -241,7 +243,8 @@ void space_regrid(struct space *s, double cell_max, int verbose) { "is switched on.\nThis error is often caused by any of the " "followings:\n" " - too few particles to generate a sensible grid,\n" - " - the initial value of 'SPH:max_smoothing_length' is too large,\n" + " - the initial value of 'Scheduler:max_top_level_cells' is too " + "small,\n" " - the (minimal) time-step is too large leading to particles with " "predicted smoothing lengths too large for the box size,\n" " - particle with velocities so large that they move by more than two " @@ -315,6 +318,8 @@ void space_regrid(struct space *s, double cell_max, int verbose) { s->nr_cells * sizeof(struct cell)) != 0) error("Failed to allocate cells."); bzero(s->cells_top, s->nr_cells * sizeof(struct cell)); + + /* Set the cells' locks */ for (int k = 0; k < s->nr_cells; k++) if (lock_init(&s->cells_top[k].lock) != 0) error("Failed to init spinlock."); @@ -343,7 +348,6 @@ void space_regrid(struct space *s, double cell_max, int verbose) { if (verbose) message("set cell dimensions to [ %i %i %i ].", cdim[0], cdim[1], cdim[2]); - fflush(stdout); #ifdef WITH_MPI if (oldnodeIDs != NULL) { @@ -392,10 +396,6 @@ void space_regrid(struct space *s, double cell_max, int verbose) { space_rebuild_recycle(s, &s->cells_top[k]); s->cells_top[k].sorts = NULL; s->cells_top[k].nr_tasks = 0; - s->cells_top[k].nr_density = 0; - s->cells_top[k].nr_gradient = 0; - s->cells_top[k].nr_force = 0; - s->cells_top[k].nr_grav = 0; s->cells_top[k].density = NULL; s->cells_top[k].gradient = NULL; s->cells_top[k].force = NULL; @@ -435,11 +435,10 @@ void space_regrid(struct space *s, double cell_max, int verbose) { * @brief Re-build the cells as well as the tasks. * * @param s The #space in which to update the cells. - * @param cell_max Maximal cell size. * @param verbose Print messages to stdout or not * */ -void space_rebuild(struct space *s, double cell_max, int verbose) { +void space_rebuild(struct space *s, int verbose) { const ticks tic = getticks(); @@ -447,7 +446,7 @@ void space_rebuild(struct space *s, double cell_max, int verbose) { // message("re)building space..."); fflush(stdout); /* Re-grid if necessary, or just re-set the cell data. */ - space_regrid(s, cell_max, verbose); + space_regrid(s, verbose); size_t nr_parts = s->nr_parts; size_t nr_gparts = s->nr_gparts; @@ -734,6 +733,8 @@ void space_split(struct space *s, struct cell *cells, int nr_cells, */ void space_sanitize(struct space *s) { + s->sanitized = 1; + for (int k = 0; k < s->nr_cells; k++) { struct cell *c = &s->cells_top[k]; @@ -1444,6 +1445,7 @@ void space_split_mapper(void *map_data, int num_cells, void *extra_data) { const int count = c->count; const int gcount = c->gcount; + const int depth = c->depth; int maxdepth = 0; float h_max = 0.0f; int ti_end_min = max_nr_timesteps, ti_end_max = 0; @@ -1453,8 +1455,8 @@ void space_split_mapper(void *map_data, int num_cells, void *extra_data) { struct xpart *xparts = c->xparts; /* Check the depth. */ - while (c->depth > (maxdepth = s->maxdepth)) { - atomic_cas(&s->maxdepth, maxdepth, c->depth); + while (depth > (maxdepth = s->maxdepth)) { + atomic_cas(&s->maxdepth, maxdepth, depth); } /* If the depth is too large, we have a problem and should stop. */ @@ -1562,6 +1564,15 @@ void space_split_mapper(void *map_data, int num_cells, void *extra_data) { else c->owner = 0; /* Ok, there is really nothing on this rank... */ } + +#ifdef SWIFT_DEBUG_CHECKS + /* All cells and particles should have consistent h_max values. */ + for (int ind = 0; ind < num_cells; ind++) { + int depth = 0; + if (!checkCellhdxmax(&cells_top[ind], &depth)) + message(" at cell depth %d", depth); + } +#endif } /** @@ -1740,6 +1751,7 @@ void space_init(struct space *s, const struct swift_params *params, s->dim[0] = dim[0]; s->dim[1] = dim[1]; s->dim[2] = dim[2]; + s->sanitized = 0; s->periodic = periodic; s->gravity = gravity; s->nr_parts = Npart; @@ -1748,9 +1760,24 @@ void space_init(struct space *s, const struct swift_params *params, s->nr_gparts = Ngpart; s->size_gparts = Ngpart; s->gparts = gparts; - s->cell_min = parser_get_param_double(params, "SPH:max_smoothing_length"); s->nr_queues = 1; /* Temporary value until engine construction */ + /* Decide on the minimal top-level cell size */ + const double dmax = max(max(dim[0], dim[1]), dim[2]); + int maxtcells = + parser_get_opt_param_int(params, "Scheduler:max_top_level_cells", + space_max_top_level_cells_default); + s->cell_min = 0.99 * dmax / maxtcells; + + /* Check that it is big enough. */ + const double dmin = min(min(dim[0], dim[1]), dim[2]); + int needtcells = 3 * dmax / dmin; + if (maxtcells < needtcells) + error( + "Scheduler:max_top_level_cells is too small %d, needs to be at " + "least %d", + maxtcells, needtcells); + /* Get the constants for the scheduler */ space_maxsize = parser_get_opt_param_int(params, "Scheduler:cell_max_size", space_maxsize_default); @@ -1764,14 +1791,6 @@ void space_init(struct space *s, const struct swift_params *params, message("max_size set to %d, sub_size set to %d, split_size set to %d", space_maxsize, space_subsize, space_splitsize); - /* Check that we have enough cells */ - if (s->cell_min * 3 > dim[0] || s->cell_min * 3 > dim[1] || - s->cell_min * 3 > dim[2]) - error( - "Maximal smoothing length (%e) too large. Needs to be " - "smaller than 1/3 the simulation box size [%e %e %e]", - s->cell_min, dim[0], dim[1], dim[2]); - /* Apply h scaling */ const double scaling = parser_get_opt_param_double(params, "InitialConditions:h_scaling", 1.0); @@ -1850,13 +1869,15 @@ void space_init(struct space *s, const struct swift_params *params, if (lock_init(&s->lock) != 0) error("Failed to create space spin-lock."); /* Build the cells and the tasks. */ - if (!dry_run) space_regrid(s, s->cell_min, verbose); + if (!dry_run) space_regrid(s, verbose); } /** * @brief Cleans-up all the cell links in the space * * Expensive funtion. Should only be used for debugging purposes. + * + * @param s The #space to clean. */ void space_link_cleanup(struct space *s) { @@ -1864,6 +1885,20 @@ void space_link_cleanup(struct space *s) { space_map_cells_pre(s, 1, cell_clean_links, NULL); } +/** + * @brief Checks that all cells have been drifted to the current point in time + * + * Expensive function. Should only be used for debugging purposes. + * + * @param s The #space to check. + * @param ti_current The (integer) time. + */ +void space_check_drift_point(struct space *s, int ti_current) { + + /* Recursively check all cells */ + space_map_cells_pre(s, 1, cell_check_drift_point, &ti_current); +} + /** * @brief Frees up the memory allocated for this #space */ diff --git a/src/space.h b/src/space.h index 011dfb71a6c3ac2b51093ce83bc6b65ceecc2821..53cf2d0c8fa548ae19aa7452abb38c3e3e028165 100644 --- a/src/space.h +++ b/src/space.h @@ -42,6 +42,7 @@ #define space_maxsize_default 8000000 #define space_subsize_default 64000000 #define space_maxcount_default 10000 +#define space_max_top_level_cells_default 12 #define space_stretch 1.10f #define space_maxreldx 0.25f @@ -122,6 +123,9 @@ struct space { /*! Number of queues in the system. */ int nr_queues; + /*! Has this space already been sanitized ? */ + int sanitized; + /*! The associated engine. */ struct engine *e; @@ -165,7 +169,7 @@ void space_parts_sort_mapper(void *map_data, int num_elements, void *extra_data); void space_gparts_sort_mapper(void *map_data, int num_elements, void *extra_data); -void space_rebuild(struct space *s, double h_max, int verbose); +void space_rebuild(struct space *s, int verbose); void space_recycle(struct space *s, struct cell *c); void space_split(struct space *s, struct cell *cells, int nr_cells, int verbose); @@ -179,6 +183,7 @@ void space_do_gparts_sort(); void space_init_parts(struct space *s); void space_init_gparts(struct space *s); void space_link_cleanup(struct space *s); +void space_check_drift_point(struct space *s, int ti_current); void space_clean(struct space *s); #endif /* SWIFT_SPACE_H */ diff --git a/src/statistics.c b/src/statistics.c index 0afca84f517ca201fc184de2abff40b9ce9d5711..7a567a447a7514634435823e03bec5e4ac157d4e 100644 --- a/src/statistics.c +++ b/src/statistics.c @@ -62,7 +62,8 @@ void stats_add(struct statistics *a, const struct statistics *b) { /* Add everything */ a->E_kin += b->E_kin; a->E_int += b->E_int; - a->E_pot += b->E_pot; + a->E_pot_self += b->E_pot_self; + a->E_pot_ext += b->E_pot_ext; a->E_rad += b->E_rad; a->entropy += b->entropy; a->mass += b->mass; @@ -107,6 +108,10 @@ void stats_collect_part_mapper(void *map_data, int nr_parts, void *extra_data) { const double timeBase = s->e->timeBase; struct statistics *const global_stats = data->stats; + /* Required for external potential energy */ + const struct external_potential *potential = s->e->external_potential; + const struct phys_const *phys_const = s->e->physical_constants; + /* Local accumulator */ struct statistics stats; stats_init(&stats); @@ -117,15 +122,16 @@ void stats_collect_part_mapper(void *map_data, int nr_parts, void *extra_data) { /* Get the particle */ const struct part *p = &parts[k]; const struct xpart *xp = &xparts[k]; + const struct gpart *gp = (p->gpart != NULL) ? gp = p->gpart : NULL; /* Get useful variables */ const float dt = (ti_current - (p->ti_begin + p->ti_end) / 2) * timeBase; const double x[3] = {p->x[0], p->x[1], p->x[2]}; float a_tot[3] = {p->a_hydro[0], p->a_hydro[1], p->a_hydro[2]}; - if (p->gpart != NULL) { - a_tot[0] += p->gpart->a_grav[0]; - a_tot[1] += p->gpart->a_grav[1]; - a_tot[2] += p->gpart->a_grav[2]; + if (gp != NULL) { + a_tot[0] += gp->a_grav[0]; + a_tot[1] += gp->a_grav[1]; + a_tot[2] += gp->a_grav[2]; } const float v[3] = {xp->v_full[0] + a_tot[0] * dt, xp->v_full[1] + a_tot[1] * dt, @@ -148,7 +154,10 @@ void stats_collect_part_mapper(void *map_data, int nr_parts, void *extra_data) { /* Collect energies. */ stats.E_kin += 0.5f * m * (v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); - stats.E_pot += 0.; + stats.E_pot_self += 0.f; + if (gp != NULL) + stats.E_pot_ext += + m * external_gravity_get_potential_energy(potential, phys_const, gp); stats.E_int += m * hydro_get_internal_energy(p, dt); stats.E_rad += cooling_get_radiated_energy(xp); @@ -179,6 +188,10 @@ void stats_collect_gpart_mapper(void *map_data, int nr_gparts, const double timeBase = s->e->timeBase; struct statistics *const global_stats = data->stats; + /* Required for external potential energy */ + const struct external_potential *potential = s->e->external_potential; + const struct phys_const *phys_const = s->e->physical_constants; + /* Local accumulator */ struct statistics stats; stats_init(&stats); @@ -216,7 +229,9 @@ void stats_collect_gpart_mapper(void *map_data, int nr_gparts, /* Collect energies. */ stats.E_kin += 0.5f * m * (v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); - stats.E_pot += 0.; + stats.E_pot_self += 0.f; + stats.E_pot_ext += + m * external_gravity_get_potential_energy(potential, phys_const, gp); } /* Now write back to memory */ @@ -258,15 +273,16 @@ void stats_collect(const struct space *s, struct statistics *stats) { void stats_print_to_file(FILE *file, const struct statistics *stats, double time) { - const double E_tot = stats->E_kin + stats->E_int + stats->E_pot; + const double E_pot = stats->E_pot_self + stats->E_pot_ext; + const double E_tot = stats->E_kin + stats->E_int + E_pot; fprintf(file, " %14e %14e %14e %14e %14e %14e %14e %14e %14e %14e %14e %14e %14e " - "%14e\n", - time, stats->mass, E_tot, stats->E_kin, stats->E_int, stats->E_pot, - stats->E_rad, stats->entropy, stats->mom[0], stats->mom[1], - stats->mom[2], stats->ang_mom[0], stats->ang_mom[1], - stats->ang_mom[2]); + "%14e %14e %14e\n", + time, stats->mass, E_tot, stats->E_kin, stats->E_int, E_pot, + stats->E_pot_self, stats->E_pot_ext, stats->E_rad, stats->entropy, + stats->mom[0], stats->mom[1], stats->mom[2], stats->ang_mom[0], + stats->ang_mom[1], stats->ang_mom[2]); fflush(file); } diff --git a/src/statistics.h b/src/statistics.h index ece1f813bb8aff2b5402753bafc031696cfa562d..b007d1314c458254986862f99b7cb1669d995545 100644 --- a/src/statistics.h +++ b/src/statistics.h @@ -37,8 +37,11 @@ struct statistics { /*! Internal energy */ double E_int; - /*! Potential energy */ - double E_pot; + /*! Self potential energy */ + double E_pot_self; + + /*! External potential energy */ + double E_pot_ext; /*! Radiative energy */ double E_rad; diff --git a/src/task.c b/src/task.c index 54b9363b7ac3d5c372b591c00b0b03cc274f66b5..ea97fdd1bb930d005889fa7c73a3f2cb7b5f054a 100644 --- a/src/task.c +++ b/src/task.c @@ -48,10 +48,10 @@ /* Task type names. */ const char *taskID_names[task_type_count] = { - "none", "sort", "self", "pair", "sub_self", - "sub_pair", "init", "ghost", "extra_ghost", "kick", - "kick_fixdt", "send", "recv", "grav_gather_m", "grav_fft", - "grav_mm", "grav_up", "cooling", "sourceterms"}; + "none", "sort", "self", "pair", "sub_self", + "sub_pair", "init", "ghost", "extra_ghost", "kick", + "send", "recv", "grav_gather_m", "grav_fft", "grav_mm", + "grav_up", "cooling", "sourceterms"}; const char *subtaskID_names[task_subtype_count] = { "none", "density", "gradient", "force", "grav", "external_grav", "tend"}; @@ -148,7 +148,6 @@ __attribute__((always_inline)) INLINE static enum task_actions task_acts_on( case task_type_init: case task_type_kick: - case task_type_kick_fixdt: case task_type_send: case task_type_recv: if (t->ci->count > 0 && t->ci->gcount > 0) @@ -372,32 +371,6 @@ int task_lock(struct task *t) { return 1; } -/** - * @brief Prints the list of tasks contained in a given mask - * - * @param mask The mask to analyse - */ -void task_print_mask(unsigned int mask) { - - printf("task_print_mask: The tasks to run are ["); - for (int k = 1; k < task_type_count; k++) - printf(" %s=%s", taskID_names[k], (mask & (1 << k)) ? "yes" : "no"); - printf(" ]\n"); -} - -/** - * @brief Prints the list of subtasks contained in a given submask - * - * @param submask The submask to analyse - */ -void task_print_submask(unsigned int submask) { - - printf("task_print_submask: The subtasks to run are ["); - for (int k = 1; k < task_subtype_count; k++) - printf(" %s=%s", subtaskID_names[k], (submask & (1 << k)) ? "yes" : "no"); - printf(" ]\n"); -} - /** * @brief Print basic information about a task. * diff --git a/src/task.h b/src/task.h index f840c0b4b8e807dce28f6f13479dbdf4995ab66d..c9425fdd137e2c1708dbd05436d1db685bdd3bfd 100644 --- a/src/task.h +++ b/src/task.h @@ -46,7 +46,6 @@ enum task_types { task_type_ghost, task_type_extra_ghost, task_type_kick, - task_type_kick_fixdt, task_type_send, task_type_recv, task_type_grav_gather_m, @@ -105,9 +104,6 @@ struct task { /*! List of tasks unlocked by this one */ struct task **unlock_tasks; - /*! Start and end time of this task */ - ticks tic, toc; - #ifdef WITH_MPI /*! Buffer for this task's communications */ @@ -127,8 +123,10 @@ struct task { /*! Weight of the task */ int weight; - /*! ID of the queue or runner owning this task */ - short int rid; +#if defined(WITH_MPI) && defined(HAVE_METIS) + /*! Individual cost estimate for this task. */ + int cost; +#endif /*! Number of tasks unlocked by this one */ short int nr_unlock_tasks; @@ -151,14 +149,20 @@ struct task { /*! Is this task implicit (i.e. does not do anything) ? */ char implicit; +#ifdef SWIFT_DEBUG_TASKS + /*! ID of the queue or runner owning this task */ + short int rid; + + /*! Start and end time of this task */ + ticks tic, toc; +#endif + } SWIFT_STRUCT_ALIGN; /* Function prototypes. */ void task_unlock(struct task *t); float task_overlap(const struct task *ta, const struct task *tb); int task_lock(struct task *t); -void task_print_mask(unsigned int mask); -void task_print_submask(unsigned int submask); void task_do_rewait(struct task *t); void task_print(const struct task *t); diff --git a/src/timers.h b/src/timers.h index d75508afd88cf2fd57d06f9530bff8607d79d127..bc877d4094425a4948290d2c7c099f49cbd44280 100644 --- a/src/timers.h +++ b/src/timers.h @@ -56,6 +56,7 @@ enum { timer_dosub_pair_grav, timer_dopair_subset, timer_do_ghost, + timer_do_extra_ghost, timer_dorecv_cell, timer_gettask, timer_qget, diff --git a/src/tools.c b/src/tools.c index 060bf1439f30dc6237938c060bc4ddc8d9be822b..e526bb1b838f6d97b72eadb4070f3f2a94938c04 100644 --- a/src/tools.c +++ b/src/tools.c @@ -481,7 +481,7 @@ void engine_single_density(double *dim, long long int pid, } /* Dump the result. */ - hydro_end_density(&p, 0); + hydro_end_density(&p); message("part %lli (h=%e) has wcount=%e, rho=%e.", p.id, p.h, p.density.wcount, hydro_get_density(&p)); fflush(stdout); diff --git a/src/units.c b/src/units.c index 2241d441ec9af9b6d5083191e8f61010ebaccb20..05b83a3427cc40efe8a9cc3a79aa48fec4af05c1 100644 --- a/src/units.c +++ b/src/units.c @@ -320,9 +320,15 @@ void units_get_base_unit_exponants_array(float baseUnitsExp[5], case UNIT_CONV_VOLUME: baseUnitsExp[UNIT_LENGTH] = 3.f; + break; case UNIT_CONV_INV_VOLUME: baseUnitsExp[UNIT_LENGTH] = -3.f; + break; + + default: + error("Invalid choice of pre-defined units"); + break; } } diff --git a/tests/test125cells.c b/tests/test125cells.c index d423efba3fda764310721586e14192afdee18a85..3ae80d952f78e8f50235cf38af493501c1c97634 100644 --- a/tests/test125cells.c +++ b/tests/test125cells.c @@ -269,12 +269,12 @@ struct cell *make_cell(size_t n, const double offset[3], double size, double h, set_velocity(part, vel, size); set_energy_state(part, press, size, density); + hydro_first_init_part(part, xpart); + part->id = ++(*partId); part->ti_begin = 0; part->ti_end = 1; - hydro_first_init_part(part, xpart); - #if defined(GIZMO_SPH) part->geometry.volume = part->conserved.mass / density; part->primitives.rho = density; @@ -311,6 +311,7 @@ struct cell *make_cell(size_t n, const double offset[3], double size, double h, cell->loc[1] = offset[1]; cell->loc[2] = offset[2]; + cell->ti_old = 1; cell->ti_end_min = 1; cell->ti_end_max = 1; @@ -617,7 +618,7 @@ int main(int argc, char *argv[]) { #endif /* Ghost to finish everything on the central cells */ - for (int j = 0; j < 27; ++j) runner_do_ghost(&runner, inner_cells[j]); + for (int j = 0; j < 27; ++j) runner_do_ghost(&runner, inner_cells[j], 0); /* Do the force calculation */ #if !(defined(MINIMAL_SPH) && defined(WITH_VECTORIZATION)) @@ -704,7 +705,7 @@ int main(int argc, char *argv[]) { #endif /* Ghost to finish everything on the central cells */ - for (int j = 0; j < 27; ++j) runner_do_ghost(&runner, inner_cells[j]); + for (int j = 0; j < 27; ++j) runner_do_ghost(&runner, inner_cells[j], 0); /* Do the force calculation */ #if !(defined(MINIMAL_SPH) && defined(WITH_VECTORIZATION)) diff --git a/tests/test27cells.c b/tests/test27cells.c index 22619af53c39218da34d771fab6ed2d10993689c..f58b4dc410637f3d91369dab1b442de0b7044c08 100644 --- a/tests/test27cells.c +++ b/tests/test27cells.c @@ -167,7 +167,7 @@ void zero_particle_fields(struct cell *c) { */ void end_calculation(struct cell *c) { for (int pid = 0; pid < c->count; pid++) { - hydro_end_density(&c->parts[pid], 1); + hydro_end_density(&c->parts[pid]); } }