diff --git a/.gitignore b/.gitignore index 3c643647a07a91402d4ca63e12ba7d17aaf975a4..cc936154b298d48a7661070b35dc7d2f326d56ce 100644 --- a/.gitignore +++ b/.gitignore @@ -48,6 +48,7 @@ tests/swift_dopair_standard.dat tests/brute_force_perturbed.dat tests/swift_dopair_perturbed.dat tests/test27cells +tests/test27cells_subset tests/testPeriodicBC tests/test125cells tests/brute_force_27_standard.dat @@ -121,6 +122,7 @@ theory/Multipoles/potential.pdf theory/Multipoles/potential_long.pdf theory/Multipoles/potential_short.pdf theory/Multipoles/force_short.pdf +theory/Cosmology/cosmology.pdf m4/libtool.m4 m4/ltoptions.m4 diff --git a/INSTALL.swift b/INSTALL.swift index e1efc945c83742cbd2cc2e9fe7afeec5cc9d1145..1782b75e34e2028110717d7873bc2c97365f8240 100644 --- a/INSTALL.swift +++ b/INSTALL.swift @@ -116,6 +116,8 @@ before you can build it. much like the CC one. Use this when your MPI compiler has a none-standard name. + - GSL: To use cosmological time integration, a version of the GSL + must be available. - libtool: The build system relies on libtool as well as the other autotools. diff --git a/configure.ac b/configure.ac index b027d5b2159ce9b63d01117f9a6f07efa39c6311..c95548229667a3a90941f723da93f997cb03b66e 100644 --- a/configure.ac +++ b/configure.ac @@ -407,6 +407,14 @@ AC_HEADER_STDC # Check for the libraries we will need. AC_CHECK_LIB(m,sqrt,,AC_MSG_ERROR(something is wrong with the math library!)) +# Check for GSL +have_gsl="no" +AC_CHECK_LIB([gslcblas], [cblas_dgemm]) +AC_CHECK_LIB([gsl], [gsl_integration_qag]) +if test "x$ac_cv_lib_gslcblas_cblas_dgemm" != "x"; then + have_gsl="yes" +fi + # Check for pthreads. AX_PTHREAD([LIBS="$PTHREAD_LIBS $LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" CC="$PTHREAD_CC" LDFLAGS="$LDFLAGS $PTHREAD_LIBS $LIBS"], @@ -1054,6 +1062,7 @@ AC_MSG_RESULT([ - parallel : $have_parallel_hdf5 Metis enabled : $have_metis FFTW3 enabled : $have_fftw3 + GSL enabled : $have_gsl libNUMA enabled : $have_numa GRACKLE enabled : $have_grackle Using tcmalloc : $have_tcmalloc diff --git a/examples/CosmologicalBox/cosmo.yml b/examples/CosmologicalBox/cosmo.yml new file mode 100644 index 0000000000000000000000000000000000000000..a82cc5610b3317076a908902efdbd5b87d94262a --- /dev/null +++ b/examples/CosmologicalBox/cosmo.yml @@ -0,0 +1,49 @@ +# Define the system of units to use internally. +InternalUnitSystem: + UnitMass_in_cgs: 1.989e43 # 10^10 M_sun in grams + UnitLength_in_cgs: 3.085678e24 # Mpc in centimeters + UnitVelocity_in_cgs: 1e5 # km/s in centimeters per second + UnitCurrent_in_cgs: 1 # Amperes + UnitTemp_in_cgs: 1 # Kelvin + +# UnitMass_in_cgs: 1 # Grams +# UnitLength_in_cgs: 1 # Centimeters +# UnitVelocity_in_cgs: 1 # Centimeters 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: 1. # 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 snapshots +Snapshots: + basename: uniformBox # Common part of the name of output files + time_first: 0. # Time of the first output (in internal units) + delta_time: 0.01 # Time difference between consecutive outputs (in internal units) + +# Parameters governing the conserved quantities statistics +Statistics: + delta_time: 1e-2 # Time between statistics output + +# Parameters for the hydrodynamics scheme +SPH: + resolution_eta: 1.2348 # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel). + CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. + +# Parameters related to the initial conditions +InitialConditions: + file_name: ./uniformBox.hdf5 # The file to read + +Cosmology: + Omega_m: 0.307 + Omega_lambda: 0.693 + Omega_b: 0.0455 + h: 0.6777 + a_begin: 0.0078125 + a_end: 1.0 + + diff --git a/examples/CosmologicalBox/makeIC.py b/examples/CosmologicalBox/makeIC.py new file mode 100644 index 0000000000000000000000000000000000000000..01e37c67b6e2eec2984d62f4ffd503b23b5bd9ec --- /dev/null +++ b/examples/CosmologicalBox/makeIC.py @@ -0,0 +1,109 @@ +############################################################################### + # This file is part of SWIFT. + # Copyright (c) 2013 Pedro Gonnet (pedro.gonnet@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/>. + # + ############################################################################## + +import h5py +import sys +from numpy import * + +# Generates a swift IC file containing a cartesian distribution of particles +# at a constant density and pressure in a cubic box + +# Parameters +periodic= 1 # 1 For periodic box +boxSize = 1. +L = int(sys.argv[1]) # Number of particles along one axis +rho = 2. # Density +P = 1. # Pressure +gamma = 5./3. # Gas adiabatic index +eta = 1.2349 # 48 ngbs with cubic spline kernel +fileName = "uniformBox.hdf5" + +#--------------------------------------------------- +numPart = L**3 +mass = boxSize**3 * rho / numPart +internalEnergy = P / ((gamma - 1.)*rho) + +#-------------------------------------------------- + +#File +file = h5py.File(fileName, 'w') + +# Header +grp = file.create_group("/Header") +grp.attrs["BoxSize"] = boxSize +grp.attrs["NumPart_Total"] = [numPart, 0, 0, 0, 0, 0] +grp.attrs["NumPart_Total_HighWord"] = [0, 0, 0, 0, 0, 0] +grp.attrs["NumPart_ThisFile"] = [numPart, 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 +grp.attrs["Dimension"] = 3 + +#Runtime parameters +grp = file.create_group("/RuntimePars") +grp.attrs["PeriodicBoundariesOn"] = periodic + +#Units +grp = file.create_group("/Units") +grp.attrs["Unit length in cgs (U_L)"] = 1. +grp.attrs["Unit mass in cgs (U_M)"] = 1. +grp.attrs["Unit time in cgs (U_t)"] = 1. +grp.attrs["Unit current in cgs (U_I)"] = 1. +grp.attrs["Unit temperature in cgs (U_T)"] = 1. + +#Particle group +grp = file.create_group("/PartType0") + +v = zeros((numPart, 3)) +ds = grp.create_dataset('Velocities', (numPart, 3), 'f') +ds[()] = v +v = zeros(1) + +m = full((numPart, 1), mass) +ds = grp.create_dataset('Masses', (numPart,1), 'f') +ds[()] = m +m = zeros(1) + +h = full((numPart, 1), eta * boxSize / L) +ds = grp.create_dataset('SmoothingLength', (numPart,1), 'f') +ds[()] = h +h = zeros(1) + +u = full((numPart, 1), internalEnergy) +ds = grp.create_dataset('InternalEnergy', (numPart,1), 'f') +ds[()] = u +u = zeros(1) + + +ids = linspace(0, numPart, numPart, endpoint=False).reshape((numPart,1)) +ds = grp.create_dataset('ParticleIDs', (numPart, 1), 'L') +ds[()] = ids + 1 +x = ids % L; +y = ((ids - x) / L) % L; +z = (ids - x - L * y) / L**2; +coords = zeros((numPart, 3)) +coords[:,0] = z[:,0] * boxSize / L + boxSize / (2*L) +coords[:,1] = y[:,0] * boxSize / L + boxSize / (2*L) +coords[:,2] = x[:,0] * boxSize / L + boxSize / (2*L) +ds = grp.create_dataset('Coordinates', (numPart, 3), 'd') +ds[()] = coords + +file.close() diff --git a/examples/EAGLE_12/eagle_12.yml b/examples/EAGLE_12/eagle_12.yml index 054356c2fb2e883ac4dcf49ecf477d076a17e658..af55da76ff513548bee52e51993fa8b78cfdc9e3 100644 --- a/examples/EAGLE_12/eagle_12.yml +++ b/examples/EAGLE_12/eagle_12.yml @@ -13,13 +13,22 @@ TimeIntegration: dt_min: 1e-10 # The minimal time-step size of the simulation (in internal units). dt_max: 1e-4 # The maximal time-step size of the simulation (in internal units). +# Cosmological parameters +Cosmology: + h: 0.6777 # Reduced Hubble constant + a_begin: 0.9090909 # Initial scale-factor of the simulation + a_end: 1.0 # Final scale factor of the simulation + Omega_m: 0.307 # Matter density parameter + Omega_lambda: 0.693 # Dark-energy density parameter + Omega_b: 0.0455 # Baryon density parameter + Scheduler: max_top_level_cells: 15 # Parameters governing the snapshots Snapshots: basename: eagle # Common part of the name of output files - time_first: 0. # Time of the first output (in internal units) + time_first: 1. # Time of the first output (in internal units) delta_time: 1e-3 # Time difference between consecutive outputs (in internal units) # Parameters governing the conserved quantities statistics diff --git a/examples/SedovBlast_1D/makeIC.py b/examples/SedovBlast_1D/makeIC.py index 0c3a311703651003dbf17da099e53bf8a607b881..7177f3a7670aa054e3d7341a11a7359b3d855837 100644 --- a/examples/SedovBlast_1D/makeIC.py +++ b/examples/SedovBlast_1D/makeIC.py @@ -23,7 +23,7 @@ from numpy import * # Generates a swift IC file for the Sedov blast test in a periodic cubic box # Parameters -numPart = 1000 +numPart = 1001 gamma = 5./3. # Gas adiabatic index rho0 = 1. # Background density P0 = 1.e-6 # Background pressure diff --git a/examples/main.c b/examples/main.c index 6244a7bb615d2a29002625a4ca233aec7ab11eeb..828bf871bb034ce76a1a2454ed7e7dbb43e01443 100644 --- a/examples/main.c +++ b/examples/main.c @@ -126,6 +126,7 @@ int main(int argc, char *argv[]) { * scope. */ struct chemistry_data chemistry; struct cooling_function_data cooling_func; + struct cosmology cosmo; struct external_potential potential; struct gpart *gparts = NULL; struct gravity_props gravity_properties; @@ -600,6 +601,13 @@ int main(int argc, char *argv[]) { phys_const_print(&prog_const); } + /* Initialise the cosmology */ + if (with_cosmology) + cosmology_init(params, &us, &prog_const, &cosmo); + else + cosmology_init_no_cosmo(&cosmo); + if (with_cosmology) cosmology_print(&cosmo); + /* Initialise the hydro properties */ if (with_hydro) hydro_props_init(&hydro_properties, params); if (with_hydro) eos_init(&eos, params); @@ -767,9 +775,9 @@ int main(int argc, char *argv[]) { /* Initialize the engine with the space and policies. */ if (myrank == 0) clocks_gettime(&tic); engine_init(&e, &s, params, N_total[0], N_total[1], engine_policies, - talking, &reparttype, &us, &prog_const, &hydro_properties, - &gravity_properties, &potential, &cooling_func, &chemistry, - &sourceterms); + talking, &reparttype, &us, &prog_const, &cosmo, + &hydro_properties, &gravity_properties, &potential, + &cooling_func, &chemistry, &sourceterms); engine_config(0, &e, params, nr_nodes, myrank, nr_threads, with_aff, talking, restart_file); if (myrank == 0) { @@ -790,7 +798,7 @@ int main(int argc, char *argv[]) { "from t=%.3e until t=%.3e with %d threads and %d queues " "(dt_min=%.3e, " "dt_max=%.3e)...", - e.timeBegin, e.timeEnd, e.nr_threads, e.sched.nr_queues, e.dt_min, + e.time_begin, e.time_end, e.nr_threads, e.sched.nr_queues, e.dt_min, e.dt_max); fflush(stdout); } @@ -837,9 +845,10 @@ int main(int argc, char *argv[]) { /* Legend */ if (myrank == 0) - printf("# %6s %14s %14s %12s %12s %12s %16s [%s] %6s\n", "Step", "Time", - "Time-step", "Updates", "g-Updates", "s-Updates", "Wall-clock time", - clocks_getunit(), "Props"); + printf("# %6s %14s %14s %14s %9s %12s %12s %12s %16s [%s] %6s\n", "Step", + "Time", "Scale-factor", "Time-step", "Time-bins", "Updates", + "g-Updates", "s-Updates", "Wall-clock time", clocks_getunit(), + "Props"); /* File for the timers */ if (with_verbose_timers) timers_open_file(myrank); @@ -865,8 +874,7 @@ int main(int argc, char *argv[]) { if (with_verbose_timers) timers_print(e.step); /* Every so often allow the user to stop the application and dump the - * restart - * files. */ + * restart files. */ if (j % restart_stop_steps == 0) { force_stop = restart_stop_now(restart_dir, 0); if (myrank == 0 && force_stop) @@ -874,8 +882,7 @@ int main(int argc, char *argv[]) { } /* Also if using nsteps to exit, will not have saved any restarts on exit, - * make - * sure we do that (useful in testing only). */ + * make sure we do that (useful in testing only). */ if (force_stop || (e.restart_onexit && e.step - 1 == nsteps)) engine_dump_restarts(&e, 0, 1); diff --git a/examples/parameter_example.yml b/examples/parameter_example.yml index e304639cb579e0bdec9926775c45fb445da18b80..4784a877a21e698af28f72aab473ac9c3cad605e 100644 --- a/examples/parameter_example.yml +++ b/examples/parameter_example.yml @@ -10,6 +10,36 @@ InternalUnitSystem: PhysicalConstants: G: 6.67408e-8 # (Optional) Overwrite the value of Newton's constant used internally by the code. +# Cosmological parameters +Cosmology: + h: 0.6777 # Reduced Hubble constant + a_begin: 0.0078125 # Initial scale-factor of the simulation + a_end: 1.0 # Final scale factor of the simulation + Omega_m: 0.307 # Matter density parameter + Omega_lambda: 0.693 # Dark-energy density parameter + Omega_b: 0.0455 # Baryon density parameter + Omega_r: 0. # (Optional) Radiation density parameter + w_0: -1.0 # (Optional) Dark-energy equation-of-state parameter at z=0. + w_a: 0. # (Optional) Dark-energy equation-of-state time evolution parameter. + +# Parameters for the hydrodynamics scheme +SPH: + resolution_eta: 1.2348 # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel). + CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. + h_tolerance: 1e-4 # (Optional) Relative accuracy of the Netwon-Raphson scheme for the smoothing lengths. + h_max: 10. # (Optional) Maximal allowed smoothing length in internal units. Defaults to FLT_MAX if unspecified. + max_volume_change: 1.4 # (Optional) Maximal allowed change of kernel volume over one time-step. + max_ghost_iterations: 30 # (Optional) Maximal number of iterations allowed to converge towards the smoothing length. + +# Parameters for the self-gravity scheme +Gravity: + eta: 0.025 # Constant dimensionless multiplier for time integration. + theta: 0.7 # Opening angle (Multipole acceptance criterion) + epsilon: 0.1 # Softening length (in internal units). + a_smooth: 1.25 # (Optional) Smoothing scale in top-level cell sizes to smooth the long-range forces over (this is the default value). + r_cut_max: 4.5 # (Optional) Cut-off in number of top-level cells beyond which no FMM forces are computed (this is the default value). + r_cut_min: 0.1 # (Optional) Cut-off in number of top-level cells below which no truncation of FMM forces are performed (this is the default value). + # Parameters for the task scheduling Scheduler: nr_queues: 0 # (Optional) The number of task queues to use. Use 0 to let the system decide. @@ -48,27 +78,6 @@ Statistics: energy_file_name: energy # (Optional) File name for energy output timestep_file_name: timesteps # (Optional) File name for timing information output. Note: No underscores "_" allowed in file name -# Parameters for the hydrodynamics scheme -SPH: - resolution_eta: 1.2348 # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel). - CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. - h_tolerance: 1e-4 # (Optional) Relative accuracy of the Netwon-Raphson scheme for the smoothing lengths. - h_max: 10. # (Optional) Maximal allowed smoothing length in internal units. Defaults to FLT_MAX if unspecified. - max_volume_change: 1.4 # (Optional) Maximal allowed change of kernel volume over one time-step. - max_ghost_iterations: 30 # (Optional) Maximal number of iterations allowed to converge towards the smoothing length. - -EoS: - isothermal_internal_energy: 20.26784 # Thermal energy per unit mass for the case of isothermal equation of state (in internal units). - -# Parameters for the self-gravity scheme -Gravity: - eta: 0.025 # Constant dimensionless multiplier for time integration. - theta: 0.7 # Opening angle (Multipole acceptance criterion) - epsilon: 0.1 # Softening length (in internal units). - a_smooth: 1.25 # (Optional) Smoothing scale in top-level cell sizes to smooth the long-range forces over (this is the default value). - r_cut_max: 4.5 # (Optional) Cut-off in number of top-level cells beyond which no FMM forces are computed (this is the default value). - r_cut_min: 0.1 # (Optional) Cut-off in number of top-level cells below which no truncation of FMM forces are performed (this is the default value). - # Parameters related to the initial conditions InitialConditions: file_name: SedovBlast/sedov.hdf5 # The file to read @@ -108,6 +117,11 @@ DomainDecomposition: minfrac: 0.9 # (Optional) Fractional of all particles that should be updated in previous step when # using CPU time trigger +# Parameters related to the equation of state ------------------------------------------ + +EoS: + isothermal_internal_energy: 20.26784 # Thermal energy per unit mass for the case of isothermal equation of state (in internal units). + # Parameters related to external potentials -------------------------------------------- # Point mass external potentials diff --git a/examples/plot_scaling_results.py b/examples/plot_scaling_results.py index 9e938c720f81dcf2246d2e48922ec5b4dd404f3e..e39f0d2d0c00eecf7680b2f090bd2c0aa29ed8bb 100755 --- a/examples/plot_scaling_results.py +++ b/examples/plot_scaling_results.py @@ -148,8 +148,8 @@ def parse_files(): # Loop over all files for a given series and load the times for j in range(0,len(file_list)): - times = np.loadtxt(file_list[j],usecols=(6,)) - updates = np.loadtxt(file_list[j],usecols=(3,)) + times = np.loadtxt(file_list[j],usecols=(9,)) + updates = np.loadtxt(file_list[j],usecols=(6,)) totalTime[i].append(np.sum(times)) sumTotal.append(np.sum(totalTime[i])) diff --git a/examples/plot_scaling_results_breakdown.py b/examples/plot_scaling_results_breakdown.py index 92a9564c326b9a4d33c047a87f7792d257c96b69..6a87e42bcd393d543187e768e31a15bc56f1ae6a 100755 --- a/examples/plot_scaling_results_breakdown.py +++ b/examples/plot_scaling_results_breakdown.py @@ -149,8 +149,8 @@ def parse_files(): # Loop over all files for a given series and load the times for j in range(0,len(file_list)): - times = np.loadtxt(file_list[j],usecols=(6,), skiprows=11) - updates = np.loadtxt(file_list[j],usecols=(3,), skiprows=11) + times = np.loadtxt(file_list[j],usecols=(9,)) + updates = np.loadtxt(file_list[j],usecols=(6,)) totalTime[i].append(np.sum(times)) sumTotal.append(np.sum(totalTime[i])) diff --git a/src/Makefile.am b/src/Makefile.am index 7b216af3ad083379f182fb6e8d887b4767837bc5..0c8b53de3cca4ad4836834d13c9710ccce0cce00 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -47,7 +47,7 @@ include_HEADERS = space.h runner.h queue.h task.h lock.h cell.h part.h const.h \ sourceterms_struct.h statistics.h memswap.h cache.h runner_doiact_vec.h profiler.h \ dump.h logger.h active.h timeline.h xmf.h gravity_properties.h gravity_derivatives.h \ gravity_softened_derivatives.h vector_power.h collectgroup.h hydro_space.h sort_part.h \ - chemistry.h chemistry_io.h chemistry_struct.h restart.h + chemistry.h chemistry_io.h chemistry_struct.h cosmology.h restart.h # Common source files AM_SOURCES = space.c runner.c queue.c task.c cell.c engine.c \ @@ -59,7 +59,7 @@ AM_SOURCES = space.c runner.c queue.c task.c cell.c engine.c \ statistics.c runner_doiact_vec.c profiler.c dump.c logger.c \ part_type.c xmf.c gravity_properties.c gravity.c \ collectgroup.c hydro_space.c equation_of_state.c \ - chemistry.c restart.c + chemistry.c cosmology.c restart.c # Include files for distribution, not installation. nobase_noinst_HEADERS = align.h approx_math.h atomic.h barrier.h cycle.h error.h inline.h kernel_hydro.h kernel_gravity.h \ diff --git a/src/active.h b/src/active.h index 9eb4123392f4b1b6bca2f68d59991ff90b92614d..3fe52a86b373ff0b33b88eca0dac9b7c6b58a216 100644 --- a/src/active.h +++ b/src/active.h @@ -42,9 +42,9 @@ __attribute__((always_inline)) INLINE static int cell_are_part_drifted( if (c->ti_old_part > e->ti_current) error( "Cell has been drifted too far forward in time! c->ti_old=%lld (t=%e) " - "and e->ti_current=%lld (t=%e)", - c->ti_old_part, c->ti_old_part * e->timeBase, e->ti_current, - e->ti_current * e->timeBase); + "and e->ti_current=%lld (t=%e, a=%e)", + c->ti_old_part, c->ti_old_part * e->time_base, e->ti_current, + e->ti_current * e->time_base, e->cosmology->a); #endif return (c->ti_old_part == e->ti_current); @@ -66,8 +66,8 @@ __attribute__((always_inline)) INLINE static int cell_are_gpart_drifted( error( "Cell has been drifted too far forward in time! c->ti_old=%lld (t=%e) " "and e->ti_current=%lld (t=%e)", - c->ti_old_gpart, c->ti_old_gpart * e->timeBase, e->ti_current, - e->ti_current * e->timeBase); + c->ti_old_gpart, c->ti_old_gpart * e->time_base, e->ti_current, + e->ti_current * e->time_base); #endif return (c->ti_old_gpart == e->ti_current); @@ -89,9 +89,9 @@ __attribute__((always_inline)) INLINE static int cell_is_active_hydro( if (c->ti_hydro_end_min < e->ti_current) error( "cell in an impossible time-zone! c->ti_end_min=%lld (t=%e) and " - "e->ti_current=%lld (t=%e)", - c->ti_hydro_end_min, c->ti_hydro_end_min * e->timeBase, e->ti_current, - e->ti_current * e->timeBase); + "e->ti_current=%lld (t=%e, a=%e)", + c->ti_hydro_end_min, c->ti_hydro_end_min * e->time_base, e->ti_current, + e->ti_current * e->time_base, e->cosmology->a); #endif return (c->ti_hydro_end_min == e->ti_current); @@ -132,9 +132,9 @@ __attribute__((always_inline)) INLINE static int cell_is_active_gravity( if (c->ti_gravity_end_min < e->ti_current) error( "cell in an impossible time-zone! c->ti_end_min=%lld (t=%e) and " - "e->ti_current=%lld (t=%e)", - c->ti_gravity_end_min, c->ti_gravity_end_min * e->timeBase, - e->ti_current, e->ti_current * e->timeBase); + "e->ti_current=%lld (t=%e, a=%e)", + c->ti_gravity_end_min, c->ti_gravity_end_min * e->time_base, + e->ti_current, e->ti_current * e->time_base, e->cosmology->a); #endif return (c->ti_gravity_end_min == e->ti_current); @@ -265,9 +265,9 @@ __attribute__((always_inline)) INLINE static int cell_is_starting_hydro( if (c->ti_hydro_beg_max > e->ti_current) error( "cell in an impossible time-zone! c->ti_beg_max=%lld (t=%e) and " - "e->ti_current=%lld (t=%e)", - c->ti_hydro_beg_max, c->ti_hydro_beg_max * e->timeBase, e->ti_current, - e->ti_current * e->timeBase); + "e->ti_current=%lld (t=%e, a=%e)", + c->ti_hydro_beg_max, c->ti_hydro_beg_max * e->time_base, e->ti_current, + e->ti_current * e->time_base, e->cosmology->a); #endif return (c->ti_hydro_beg_max == e->ti_current); @@ -287,9 +287,9 @@ __attribute__((always_inline)) INLINE static int cell_is_starting_gravity( if (c->ti_gravity_beg_max > e->ti_current) error( "cell in an impossible time-zone! c->ti_beg_max=%lld (t=%e) and " - "e->ti_current=%lld (t=%e)", - c->ti_gravity_beg_max, c->ti_gravity_beg_max * e->timeBase, - e->ti_current, e->ti_current * e->timeBase); + "e->ti_current=%lld (t=%e, a=%e)", + c->ti_gravity_beg_max, c->ti_gravity_beg_max * e->time_base, + e->ti_current, e->ti_current * e->time_base, e->cosmology->a); #endif return (c->ti_gravity_beg_max == e->ti_current); diff --git a/src/adiabatic_index.h b/src/adiabatic_index.h index 94504af18b7b9ae99fc8c7abaf097e985cb53ab6..e7798f7be6e28536191475f3c940c6f84a92bdad 100644 --- a/src/adiabatic_index.h +++ b/src/adiabatic_index.h @@ -431,4 +431,73 @@ __attribute__((always_inline)) INLINE static float pow_one_over_gamma(float x) { #endif } +/** + * @brief Return the argument to the power three adiabatic index minus two. + * + * Computes \f$x^{3\gamma - 2}\f$. + * + * @param x Argument + */ +__attribute__((always_inline)) INLINE static float pow_three_gamma_minus_two( + float x) { + +#if defined(HYDRO_GAMMA_5_3) + + return x * x * x; /* x^(3) */ + +#elif defined(HYDRO_GAMMA_7_5) + + return powf(x, 2.2f); /* x^(11/5) */ + +#elif defined(HYDRO_GAMMA_4_3) + + return x * x; /* x^(2) */ + +#elif defined(HYDRO_GAMMA_2_1) + + return x * x * x * x; /* x^(4) */ + +#else + + error("The adiabatic index is not defined !"); + return 0.f; + +#endif +} + +/** + * @brief Return the argument to the power three adiabatic index minus five over + * two. + * + * Computes \f$x^{(3\gamma - 5)/2}\f$. + * + * @param x Argument + */ +__attribute__((always_inline)) INLINE static float +pow_three_gamma_minus_five_over_two(float x) { + +#if defined(HYDRO_GAMMA_5_3) + + return 1.f; /* x^(0) */ + +#elif defined(HYDRO_GAMMA_7_5) + + return powf(x, -0.4f); /* x^(-2/5) */ + +#elif defined(HYDRO_GAMMA_4_3) + + return 1.f / sqrtf(x); /* x^(-1/2) */ + +#elif defined(HYDRO_GAMMA_2_1) + + return sqrtf(x); /* x^(1/2) */ + +#else + + error("The adiabatic index is not defined !"); + return 0.f; + +#endif +} + #endif /* SWIFT_ADIABATIC_INDEX_H */ diff --git a/src/cell.c b/src/cell.c index d5745d532d6a5e9f1581d21b687b9572238f2e4e..78a50141779d368fae646d4727f63633bbef3683 100644 --- a/src/cell.c +++ b/src/cell.c @@ -2280,14 +2280,11 @@ int cell_has_tasks(struct cell *c) { void cell_drift_part(struct cell *c, const struct engine *e, int force) { const float hydro_h_max = e->hydro_properties->h_max; - const double timeBase = e->timeBase; const integertime_t ti_old_part = c->ti_old_part; const integertime_t ti_current = e->ti_current; struct part *const parts = c->parts; struct xpart *const xparts = c->xparts; - /* Drift from the last time the cell was drifted to the current time */ - const double dt = (ti_current - ti_old_part) * timeBase; float dx_max = 0.f, dx2_max = 0.f; float dx_max_sort = 0.0f, dx2_max_sort = 0.f; float cell_h_max = 0.f; @@ -2307,7 +2304,7 @@ void cell_drift_part(struct cell *c, const struct engine *e, int force) { if (c->split && (force || c->do_sub_drift)) { /* Loop over the progeny and collect their data. */ - for (int k = 0; k < 8; k++) + for (int k = 0; k < 8; k++) { if (c->progeny[k] != NULL) { struct cell *cp = c->progeny[k]; @@ -2319,6 +2316,7 @@ void cell_drift_part(struct cell *c, const struct engine *e, int force) { dx_max_sort = max(dx_max_sort, cp->dx_max_sort); cell_h_max = max(cell_h_max, cp->h_max); } + } /* Store the values */ c->h_max = cell_h_max; @@ -2330,6 +2328,24 @@ void cell_drift_part(struct cell *c, const struct engine *e, int force) { } else if (!c->split && force && ti_current > ti_old_part) { + /* Drift from the last time the cell was drifted to the current time */ + double dt_drift, dt_kick_grav, dt_kick_hydro, dt_therm; + if (e->policy & engine_policy_cosmology) { + dt_drift = + cosmology_get_drift_factor(e->cosmology, ti_old_part, ti_current); + dt_kick_grav = + cosmology_get_grav_kick_factor(e->cosmology, ti_old_part, ti_current); + dt_kick_hydro = cosmology_get_hydro_kick_factor(e->cosmology, ti_old_part, + ti_current); + dt_therm = cosmology_get_therm_kick_factor(e->cosmology, ti_old_part, + ti_current); + } else { + dt_drift = (ti_current - ti_old_part) * e->time_base; + dt_kick_grav = (ti_current - ti_old_part) * e->time_base; + dt_kick_hydro = (ti_current - ti_old_part) * e->time_base; + dt_therm = (ti_current - ti_old_part) * e->time_base; + } + /* Loop over all the gas particles in the cell */ const size_t nr_parts = c->count; for (size_t k = 0; k < nr_parts; k++) { @@ -2339,7 +2355,8 @@ void cell_drift_part(struct cell *c, const struct engine *e, int force) { struct xpart *const xp = &xparts[k]; /* Drift... */ - drift_part(p, xp, dt, timeBase, ti_old_part, ti_current); + drift_part(p, xp, dt_drift, dt_kick_hydro, dt_kick_grav, dt_therm, + ti_old_part, ti_current); /* Limit h to within the allowed range */ p->h = min(p->h, hydro_h_max); @@ -2391,14 +2408,11 @@ void cell_drift_part(struct cell *c, const struct engine *e, int force) { */ void cell_drift_gpart(struct cell *c, const struct engine *e, int force) { - const double timeBase = e->timeBase; const integertime_t ti_old_gpart = c->ti_old_gpart; const integertime_t ti_current = e->ti_current; struct gpart *const gparts = c->gparts; struct spart *const sparts = c->sparts; - /* Drift from the last time the cell was drifted to the current time */ - const double dt = (ti_current - ti_old_gpart) * timeBase; float dx_max = 0.f, dx2_max = 0.f; /* Drift irrespective of cell flags? */ @@ -2416,7 +2430,7 @@ void cell_drift_gpart(struct cell *c, const struct engine *e, int force) { if (c->split && (force || c->do_grav_sub_drift)) { /* Loop over the progeny and collect their data. */ - for (int k = 0; k < 8; k++) + for (int k = 0; k < 8; k++) { if (c->progeny[k] != NULL) { struct cell *cp = c->progeny[k]; @@ -2426,6 +2440,7 @@ void cell_drift_gpart(struct cell *c, const struct engine *e, int force) { /* Update */ dx_max = max(dx_max, cp->dx_max_gpart); } + } /* Store the values */ c->dx_max_gpart = dx_max; @@ -2435,6 +2450,14 @@ void cell_drift_gpart(struct cell *c, const struct engine *e, int force) { } else if (!c->split && force && ti_current > ti_old_gpart) { + /* Drift from the last time the cell was drifted to the current time */ + double dt_drift; + if (e->policy & engine_policy_cosmology) + dt_drift = + cosmology_get_drift_factor(e->cosmology, ti_old_gpart, ti_current); + else + dt_drift = (ti_current - ti_old_gpart) * e->time_base; + /* Loop over all the g-particles in the cell */ const size_t nr_gparts = c->gcount; for (size_t k = 0; k < nr_gparts; k++) { @@ -2443,7 +2466,7 @@ void cell_drift_gpart(struct cell *c, const struct engine *e, int force) { struct gpart *const gp = &gparts[k]; /* Drift... */ - drift_gpart(gp, dt, timeBase, ti_old_gpart, ti_current); + drift_gpart(gp, dt_drift, ti_old_gpart, ti_current); /* Compute (square of) motion since last cell construction */ const float dx2 = gp->x_diff[0] * gp->x_diff[0] + @@ -2465,7 +2488,7 @@ void cell_drift_gpart(struct cell *c, const struct engine *e, int force) { struct spart *const sp = &sparts[k]; /* Drift... */ - drift_spart(sp, dt, timeBase, ti_old_gpart, ti_current); + drift_spart(sp, dt_drift, ti_old_gpart, ti_current); /* Note: no need to compute dx_max as all spart have a gpart */ } @@ -2493,19 +2516,25 @@ void cell_drift_gpart(struct cell *c, const struct engine *e, int force) { */ void cell_drift_all_multipoles(struct cell *c, const struct engine *e) { - const double timeBase = e->timeBase; const integertime_t ti_old_multipole = c->ti_old_multipole; const integertime_t ti_current = e->ti_current; - /* Drift from the last time the cell was drifted to the current time */ - const double dt = (ti_current - ti_old_multipole) * timeBase; - +#ifdef SWIFT_DEBUG_CHECKS /* Check that we are actually going to move forward. */ if (ti_current < ti_old_multipole) error("Attempt to drift to the past"); +#endif + + /* Drift from the last time the cell was drifted to the current time */ + double dt_drift; + if (e->policy & engine_policy_cosmology) + dt_drift = + cosmology_get_drift_factor(e->cosmology, ti_old_multipole, ti_current); + else + dt_drift = (ti_current - ti_old_multipole) * e->time_base; /* Drift the multipole */ if (ti_current > ti_old_multipole) - gravity_drift(c->multipole, dt, c->dx_max_gpart); + gravity_drift(c->multipole, dt_drift, c->dx_max_gpart); /* Are we not in a leaf ? */ if (c->split) { @@ -2530,18 +2559,24 @@ void cell_drift_all_multipoles(struct cell *c, const struct engine *e) { */ void cell_drift_multipole(struct cell *c, const struct engine *e) { - const double timeBase = e->timeBase; const integertime_t ti_old_multipole = c->ti_old_multipole; const integertime_t ti_current = e->ti_current; - /* Drift from the last time the cell was drifted to the current time */ - const double dt = (ti_current - ti_old_multipole) * timeBase; - +#ifdef SWIFT_DEBUG_CHECKS /* Check that we are actually going to move forward. */ if (ti_current < ti_old_multipole) error("Attempt to drift to the past"); +#endif + + /* Drift from the last time the cell was drifted to the current time */ + double dt_drift; + if (e->policy & engine_policy_cosmology) + dt_drift = + cosmology_get_drift_factor(e->cosmology, ti_old_multipole, ti_current); + else + dt_drift = (ti_current - ti_old_multipole) * e->time_base; if (ti_current > ti_old_multipole) - gravity_drift(c->multipole, dt, c->dx_max_gpart); + gravity_drift(c->multipole, dt_drift, c->dx_max_gpart); /* Update the time of the last drift */ c->ti_old_multipole = ti_current; diff --git a/src/chemistry.c b/src/chemistry.c index 35a30d8301d92120498da3aa358c1cc3d617eee4..091a0b363d16507894f3dcbba2ca79860f3cbaa9 100644 --- a/src/chemistry.c +++ b/src/chemistry.c @@ -51,3 +51,28 @@ void chemistry_init(const struct swift_params* parameter_file, void chemistry_print(const struct chemistry_data* data) { chemistry_print_backend(data); } + +/** + * @brief Write a chemistry struct to the given FILE as a stream of bytes. + * + * @param chemistry the struct + * @param stream the file stream + */ +void chemistry_struct_dump(const struct chemistry_data* chemistry, + FILE* stream) { + restart_write_blocks((void*)chemistry, sizeof(struct chemistry_data), 1, + stream, "chemistry", "chemistry function"); +} + +/** + * @brief Restore a hydro_props struct from the given FILE as a stream of + * bytes. + * + * @param chemistry the struct + * @param stream the file stream + */ +void chemistry_struct_restore(const struct chemistry_data* chemistry, + FILE* stream) { + restart_read_blocks((void*)chemistry, sizeof(struct chemistry_data), 1, + stream, NULL, "chemistry function"); +} diff --git a/src/chemistry.h b/src/chemistry.h index 25de507d60d8aa4bbb9cc4f0f6499dc52aeb93d4..a5cbd77efbaab99e98ca5f031512e7e5bef0a613 100644 --- a/src/chemistry.h +++ b/src/chemistry.h @@ -50,4 +50,10 @@ void chemistry_init(const struct swift_params* parameter_file, void chemistry_print(const struct chemistry_data* data); +/* Dump/restore. */ +void chemistry_struct_dump(const struct chemistry_data* chemistry, + FILE* stream); +void chemistry_struct_restore(const struct chemistry_data* chemistry, + FILE* stream); + #endif /* SWIFT_CHEMISTRY_H */ diff --git a/src/chemistry/EAGLE/chemistry.h b/src/chemistry/EAGLE/chemistry.h index 0ee4d2a2bfc54b1fe4b9b64f321cc23862841952..ae333252426f5fb79cc1fd1cee818754483214f8 100644 --- a/src/chemistry/EAGLE/chemistry.h +++ b/src/chemistry/EAGLE/chemistry.h @@ -72,9 +72,11 @@ __attribute__((always_inline)) INLINE static void chemistry_init_part( * * @param p The particle to act upon. * @param cd #chemistry_data containing chemistry informations. + * @param cosmo The current cosmological model. */ __attribute__((always_inline)) INLINE static void chemistry_end_density( - struct part* restrict p, const struct chemistry_data* cd) {} + struct part* restrict p, const struct chemistry_data* cd, + const struct cosmology* cosmo) {} /** * @brief Sets the chemistry properties of the (x-)particles to a valid start diff --git a/src/chemistry/EAGLE/chemistry_iact.h b/src/chemistry/EAGLE/chemistry_iact.h index a00938e3557e68b0007e1464be2f05baefaf554a..bdbb8ac9bf7d260e29468b8bee0a84416b668d6a 100644 --- a/src/chemistry/EAGLE/chemistry_iact.h +++ b/src/chemistry/EAGLE/chemistry_iact.h @@ -24,36 +24,38 @@ * @brief Smooth metal interaction functions following the EAGLE model. */ -#include "chemistry_struct.h" - /** - * @brief Do chemistry computation after the runner_iact_density (symmetric + * @brief do chemistry computation after the runner_iact_density (symmetric * version) * - * @param r2 Distance squared between particles - * @param dx Distance between particles - * @param hi Smoothing length of i - * @param hj Smoothing length of j - * @param pi #part i - * @param pj #part j + * @param r2 Comoving square distance between the two particles. + * @param dx Comoving vector separating both particles (pi - pj). + * @param hi Comoving smoothing-length of particle i. + * @param hj Comoving smoothing-length of particle j. + * @param pi First particle. + * @param pj Second particle. + * @param a Current scale factor. + * @param H Current Hubble parameter. */ __attribute__((always_inline)) INLINE static void runner_iact_chemistry( - float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) { -} + float r2, const float *dx, float hi, float hj, struct part *restrict pi, + struct part *restrict pj, float a, float H) {} /** - * @brief Do chemistry computation after the runner_iact_density (non-symmetric + * @brief do chemistry computation after the runner_iact_density (non symmetric * version) * - * @param r2 Distance squared between particles - * @param dx Distance between particles - * @param hi Smoothing length of i - * @param hj Smoothing length of j - * @param pi #part i - * @param pj #part j + * @param r2 Comoving square distance between the two particles. + * @param dx Comoving vector separating both particles (pi - pj). + * @param hi Comoving smoothing-length of particle i. + * @param hj Comoving smoothing-length of particle j. + * @param pi First particle. + * @param pj Second particle (not updated). + * @param a Current scale factor. + * @param H Current Hubble parameter. */ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_chemistry( - float r2, float *dx, float hi, float hj, struct part *pi, - const struct part *pj) {} + float r2, const float *dx, float hi, float hj, struct part *restrict pi, + const struct part *restrict pj, float a, float H) {} #endif /* SWIFT_EAGLE_CHEMISTRY_IACT_H */ diff --git a/src/chemistry/EAGLE/chemistry_io.h b/src/chemistry/EAGLE/chemistry_io.h index 70c62a1bbdcd646b7ec79f41943f8c6a7da2dea8..aab8ec240207a47289e35a711af8b245bf2b40fa 100644 --- a/src/chemistry/EAGLE/chemistry_io.h +++ b/src/chemistry/EAGLE/chemistry_io.h @@ -95,6 +95,8 @@ int chemistry_write_particles(const struct part* parts, struct io_props* list) { return 12; } +#ifdef HAVE_HDF5 + /** * @brief Writes the current model of SPH to the file * @param h_grpsph The HDF5 group in which to write @@ -108,5 +110,6 @@ void chemistry_write_flavour(hid_t h_grp) { io_write_attribute_s(h_grp, buffer, chemistry_get_element_name(elem)); } } +#endif #endif /* SWIFT_CHEMISTRY_IO_EAGLE_H */ diff --git a/src/chemistry/gear/chemistry.h b/src/chemistry/gear/chemistry.h index 5dc7a48939cdb298233abbe358473f59fc7e72f4..e9d3d00febe2438c52728f94d0136fb72ff8dc3b 100644 --- a/src/chemistry/gear/chemistry.h +++ b/src/chemistry/gear/chemistry.h @@ -103,9 +103,11 @@ __attribute__((always_inline)) INLINE static void chemistry_init_part( * * @param p The particle to act upon. * @param cd #chemistry_data containing chemistry informations. + * @param cosmo The current cosmological model. */ __attribute__((always_inline)) INLINE static void chemistry_end_density( - struct part* restrict p, const struct chemistry_data* cd) { + struct part* restrict p, const struct chemistry_data* cd, + const struct cosmology* cosmo) { /* Some smoothing length multiples. */ const float h = p->h; diff --git a/src/chemistry/gear/chemistry_iact.h b/src/chemistry/gear/chemistry_iact.h index 269d33e35fc7a2ba4f93c018c0c942fe99fb944c..f1d724b680574cf1d78848ef242a0e0e5b0cc8e3 100644 --- a/src/chemistry/gear/chemistry_iact.h +++ b/src/chemistry/gear/chemistry_iact.h @@ -29,21 +29,22 @@ * al. 2009 */ -#include "chemistry_struct.h" - /** * @brief do chemistry computation after the runner_iact_density (symmetric * version) * - * @param r2 Distance squared between particles - * @param dx Distance between particles - * @param hi Smoothing length of i - * @param hj Smoothing length of j - * @param pi #part i - * @param pj #part j + * @param r2 Comoving square distance between the two particles. + * @param dx Comoving vector separating both particles (pi - pj). + * @param hi Comoving smoothing-length of particle i. + * @param hj Comoving smoothing-length of particle j. + * @param pi First particle. + * @param pj Second particle. + * @param a Current scale factor. + * @param H Current Hubble parameter. */ __attribute__((always_inline)) INLINE static void runner_iact_chemistry( - float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) { + float r2, const float *dx, float hi, float hj, struct part *restrict pi, + struct part *restrict pj, float a, float H) { struct chemistry_part_data *chi = &pi->chemistry_data; struct chemistry_part_data *chj = &pj->chemistry_data; @@ -79,16 +80,18 @@ __attribute__((always_inline)) INLINE static void runner_iact_chemistry( * @brief do chemistry computation after the runner_iact_density (non symmetric * version) * - * @param r2 Distance squared between particles - * @param dx Distance between particles - * @param hi Smoothing length of i - * @param hj Smoothing length of j - * @param pi #part i - * @param pj #part j + * @param r2 Comoving square distance between the two particles. + * @param dx Comoving vector separating both particles (pi - pj). + * @param hi Comoving smoothing-length of particle i. + * @param hj Comoving smoothing-length of particle j. + * @param pi First particle. + * @param pj Second particle (not updated). + * @param a Current scale factor. + * @param H Current Hubble parameter. */ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_chemistry( - float r2, float *dx, float hi, float hj, struct part *pi, - const struct part *pj) { + float r2, const float *dx, float hi, float hj, struct part *restrict pi, + const struct part *restrict pj, float a, float H) { struct chemistry_part_data *chi = &pi->chemistry_data; const struct chemistry_part_data *chj = &pj->chemistry_data; diff --git a/src/chemistry/gear/chemistry_io.h b/src/chemistry/gear/chemistry_io.h index 07933245e258306cd5c342c1280ecac36f677b5a..9b0852fa2d23c8dd3e4d36406b55f4353d23b807 100644 --- a/src/chemistry/gear/chemistry_io.h +++ b/src/chemistry/gear/chemistry_io.h @@ -62,6 +62,8 @@ int chemistry_write_particles(const struct part* parts, struct io_props* list) { return 2; } +#ifdef HAVE_HDF5 + /** * @brief Writes the current model of SPH to the file * @param h_grp The HDF5 group in which to write @@ -76,5 +78,6 @@ void chemistry_write_flavour(hid_t h_grp) { io_write_attribute_s(h_grp, buffer, chemistry_get_element_name(i)); } } +#endif #endif /* SWIFT_CHEMISTRY_IO_GEAR_H */ diff --git a/src/chemistry/none/chemistry.h b/src/chemistry/none/chemistry.h index f6f826d580502f3c65bf56480ef0c04ddff1ee37..7fb83339bed6fc2db007e58a5b8372f003186db5 100644 --- a/src/chemistry/none/chemistry.h +++ b/src/chemistry/none/chemistry.h @@ -30,6 +30,7 @@ /* Local includes. */ #include "chemistry_struct.h" +#include "cosmology.h" #include "error.h" #include "hydro.h" #include "parser.h" @@ -77,9 +78,11 @@ static INLINE void chemistry_print_backend(const struct chemistry_data* data) { * * @param p The particle to act upon * @param cd The global chemistry information. + * @param cosmo The current cosmological model. */ __attribute__((always_inline)) INLINE static void chemistry_end_density( - struct part* restrict p, const struct chemistry_data* cd) {} + struct part* restrict p, const struct chemistry_data* cd, + const struct cosmology* cosmo) {} /** * @brief Sets the chemistry properties of the (x-)particles to a valid start diff --git a/src/chemistry/none/chemistry_iact.h b/src/chemistry/none/chemistry_iact.h index d963e4310e529f1a0f3202bc1f3ee68f605e811e..52499c5e5cc3d5749904251cc967193d875579b9 100644 --- a/src/chemistry/none/chemistry_iact.h +++ b/src/chemistry/none/chemistry_iact.h @@ -25,38 +25,38 @@ * @brief Density computation */ -#include "cache.h" -#include "chemistry_struct.h" -#include "minmax.h" - /** * @brief do chemistry computation after the runner_iact_density (symmetric * version) * - * @param r2 Distance squared between particles - * @param dx Distance between particles - * @param hi Smoothing length of i - * @param hj Smoothing length of j - * @param pi #part i - * @param pj #part j + * @param r2 Comoving square distance between the two particles. + * @param dx Comoving vector separating both particles (pi - pj). + * @param hi Comoving smoothing-length of particle i. + * @param hj Comoving smoothing-length of particle j. + * @param pi First particle. + * @param pj Second particle. + * @param a Current scale factor. + * @param H Current Hubble parameter. */ __attribute__((always_inline)) INLINE static void runner_iact_chemistry( - float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) { -} + float r2, const float *dx, float hi, float hj, struct part *restrict pi, + struct part *restrict pj, float a, float H) {} /** * @brief do chemistry computation after the runner_iact_density (non symmetric * version) * - * @param r2 Distance squared between particles - * @param dx Distance between particles - * @param hi Smoothing length of i - * @param hj Smoothing length of j - * @param pi #part i - * @param pj #part j + * @param r2 Comoving square distance between the two particles. + * @param dx Comoving vector separating both particles (pi - pj). + * @param hi Comoving smoothing-length of particle i. + * @param hj Comoving smoothing-length of particle j. + * @param pi First particle. + * @param pj Second particle (not updated). + * @param a Current scale factor. + * @param H Current Hubble parameter. */ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_chemistry( - float r2, float *dx, float hi, float hj, struct part *pi, - const struct part *pj) {} + float r2, const float *dx, float hi, float hj, struct part *restrict pi, + const struct part *restrict pj, float a, float H) {} #endif /* SWIFT_NONE_CHEMISTRY_IACT_H */ diff --git a/src/chemistry/none/chemistry_io.h b/src/chemistry/none/chemistry_io.h index 3f1d3329e9745c21dbc61c7ae9024f69722084e5..142d2f75ce1487393e8689edbb9a6fdb1b1e85cd 100644 --- a/src/chemistry/none/chemistry_io.h +++ b/src/chemistry/none/chemistry_io.h @@ -53,13 +53,16 @@ int chemistry_write_particles(const struct part* parts, struct io_props* list) { return 0; } +#ifdef HAVE_HDF5 + /** * @brief Writes the current model of SPH to the file - * @param h_grpsph The HDF5 group in which to write + * @param h_grp The HDF5 group in which to write */ -void chemistry_write_flavour(hid_t h_grpsph) { +void chemistry_write_flavour(hid_t h_grp) { - io_write_attribute_s(h_grpsph, "Chemistry Model", "None"); + io_write_attribute_s(h_grp, "Chemistry Model", "None"); } +#endif #endif /* SWIFT_CHEMISTRY_IO_NONE_H */ diff --git a/src/common_io.c b/src/common_io.c index 22e5fd9289cdca52435c001be7a26105b9e5ca80..67326817397118568e060f5dff49421bb32fba4d 100644 --- a/src/common_io.c +++ b/src/common_io.c @@ -375,9 +375,8 @@ void io_write_unit_system(hid_t h_file, const struct unit_system* us, * @param h_file The (opened) HDF5 file in which to write */ void io_write_code_description(hid_t h_file) { - hid_t h_grpcode = 0; - h_grpcode = H5Gcreate1(h_file, "/Code", 0); + const hid_t h_grpcode = H5Gcreate1(h_file, "/Code", 0); if (h_grpcode < 0) error("Error while creating code group"); io_write_attribute_s(h_grpcode, "Code", "SWIFT"); @@ -395,6 +394,9 @@ void io_write_code_description(hid_t h_file) { #ifdef HAVE_FFTW io_write_attribute_s(h_grpcode, "FFTW library version", fftw3_version()); #endif +#ifdef HAVE_LIBGSL + io_write_attribute_s(h_grpcode, "GSL library version", libgsl_version()); +#endif #ifdef WITH_MPI io_write_attribute_s(h_grpcode, "MPI library", mpi_version()); #ifdef HAVE_METIS @@ -406,6 +408,25 @@ void io_write_code_description(hid_t h_file) { H5Gclose(h_grpcode); } +/** + * @brief Write the #engine policy to the file. + * @param h_file File to write to. + * @param e The #engine to read the policy from. + */ +void io_write_engine_policy(hid_t h_file, const struct engine* e) { + + const hid_t h_grp = H5Gcreate1(h_file, "/Policy", 0); + if (h_grp < 0) error("Error while creating policy group"); + + for (int i = 1; i <= engine_maxpolicy; ++i) + if (e->policy & (1 << i)) + io_write_attribute_i(h_grp, engine_policy_names[i + 1], 1); + else + io_write_attribute_i(h_grp, engine_policy_names[i + 1], 0); + + H5Gclose(h_grp); +} + #endif /* HAVE_HDF5 */ /** diff --git a/src/common_io.h b/src/common_io.h index c317238160e45a9d141619d313e47c715adf8537..49358d8a374553d803de144f1135df6eee80cf15 100644 --- a/src/common_io.h +++ b/src/common_io.h @@ -73,6 +73,7 @@ void io_write_attribute_l(hid_t grp, const char* name, long data); void io_write_attribute_s(hid_t grp, const char* name, const char* str); void io_write_code_description(hid_t h_file); +void io_write_engine_policy(hid_t h_file, const struct engine* e); void io_read_unit_system(hid_t h_file, struct unit_system* us, int mpi_rank); void io_write_unit_system(hid_t h_grp, const struct unit_system* us, diff --git a/src/cooling.c b/src/cooling.c index 89a04b30f8ce3f106d90a6db1364a3caadba6deb..57d1928a5d59ac2ff46c6cd20a45d69dec25ec60 100644 --- a/src/cooling.c +++ b/src/cooling.c @@ -55,7 +55,7 @@ void cooling_print(const struct cooling_function_data* cooling) { } /** - * @brief Write a hydro_props struct to the given FILE as a stream of bytes. + * @brief Write a cooling struct to the given FILE as a stream of bytes. * * @param cooling the struct * @param stream the file stream diff --git a/src/cooling/EAGLE/cooling.h b/src/cooling/EAGLE/cooling.h index aca68ec39b677333a0e8a2b65604f2c12c96678f..62d1cc9b72681fe96c901185a10efe5523b206e3 100644 --- a/src/cooling/EAGLE/cooling.h +++ b/src/cooling/EAGLE/cooling.h @@ -37,6 +37,8 @@ #include "physical_constants.h" #include "units.h" +#ifdef HAVE_HDF5 + /** * @brief Writes the current model of SPH to the file * @param h_grpsph The HDF5 group in which to write @@ -46,12 +48,14 @@ __attribute__((always_inline)) INLINE static void cooling_write_flavour( io_write_attribute_s(h_grpsph, "Cooling Model", "EAGLE"); } +#endif /** * @brief Apply the cooling function to a particle. * * @param phys_const The physical constants in internal units. * @param us The internal system of units. + * @param cosmo The current cosmological model. * @param cooling The #cooling_function_data used in the run. * @param p Pointer to the particle data. * @param xp Pointer to the extended particle data. @@ -60,6 +64,7 @@ __attribute__((always_inline)) INLINE static void cooling_write_flavour( __attribute__((always_inline)) INLINE static void cooling_cool_part( const struct phys_const* restrict phys_const, const struct unit_system* restrict us, + const struct cosmology* restrict cosmo, const struct cooling_function_data* restrict cooling, struct part* restrict p, struct xpart* restrict xp, float dt) {} @@ -69,11 +74,13 @@ __attribute__((always_inline)) INLINE static void cooling_cool_part( * @param cooling The #cooling_function_data used in the run. * @param phys_const The physical constants in internal units. * @param us The internal system of units. + * @param cosmo The current cosmological model. * @param p Pointer to the particle data. */ __attribute__((always_inline)) INLINE static float cooling_timestep( const struct cooling_function_data* restrict cooling, const struct phys_const* restrict phys_const, + const struct cosmology* restrict cosmo, const struct unit_system* restrict us, const struct part* restrict p) { return FLT_MAX; diff --git a/src/cooling/const_du/cooling.h b/src/cooling/const_du/cooling.h index 6881e7d0093583b8ba60b3d9723a2214ef677f8a..25aa974e47b277d0dfcc21077e5041a49e8168c8 100644 --- a/src/cooling/const_du/cooling.h +++ b/src/cooling/const_du/cooling.h @@ -44,6 +44,8 @@ #include "physical_constants.h" #include "units.h" +#ifdef HAVE_HDF5 + /** * @brief Writes the current model of SPH to the file * @param h_grpsph The HDF5 group in which to write @@ -53,6 +55,7 @@ __attribute__((always_inline)) INLINE static void cooling_write_flavour( io_write_attribute_s(h_grpsph, "Cooling Model", "Constant du/dt"); } +#endif /** * @brief Apply the cooling function to a particle. @@ -62,6 +65,7 @@ __attribute__((always_inline)) INLINE static void cooling_write_flavour( * * @param phys_const The physical constants in internal units. * @param us The internal system of units. + * @param cosmo The current cosmological model. * @param cooling The #cooling_function_data used in the run. * @param p Pointer to the particle data. * @param xp Pointer to the extended particle data. @@ -70,6 +74,7 @@ __attribute__((always_inline)) INLINE static void cooling_write_flavour( __attribute__((always_inline)) INLINE static void cooling_cool_part( const struct phys_const* restrict phys_const, const struct unit_system* restrict us, + const struct cosmology* restrict cosmo, const struct cooling_function_data* restrict cooling, struct part* restrict p, struct xpart* restrict xp, float dt) { @@ -77,7 +82,7 @@ __attribute__((always_inline)) INLINE static void cooling_cool_part( const float u_floor = cooling->min_energy; /* Get current internal energy */ - const float u_old = hydro_get_internal_energy(p); + const float u_old = hydro_get_physical_internal_energy(p, cosmo); /* Current du_dt */ const float hydro_du_dt = hydro_get_internal_energy_dt(p); @@ -108,16 +113,18 @@ __attribute__((always_inline)) INLINE static void cooling_cool_part( * * @param cooling The #cooling_function_data used in the run. * @param phys_const The physical constants in internal units. + * @param cosmo The current cosmological model. * @param us The internal system of units. * @param p Pointer to the particle data. */ __attribute__((always_inline)) INLINE static float cooling_timestep( const struct cooling_function_data* restrict cooling, const struct phys_const* restrict phys_const, + const struct cosmology* restrict cosmo, const struct unit_system* restrict us, const struct part* restrict p) { const float cooling_rate = cooling->cooling_rate; - const float internal_energy = hydro_get_internal_energy(p); + const float internal_energy = hydro_get_physical_internal_energy(p, cosmo); 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 f4fe4ac4df16af53c88a901edc97e5d70f4ae806..a402b749300e64ef79253764c402d41f5a214d82 100644 --- a/src/cooling/const_lambda/cooling.h +++ b/src/cooling/const_lambda/cooling.h @@ -37,6 +37,8 @@ #include "physical_constants.h" #include "units.h" +#ifdef HAVE_HDF5 + /** * @brief Writes the current model of SPH to the file * @param h_grpsph The HDF5 group in which to write @@ -46,21 +48,24 @@ __attribute__((always_inline)) INLINE static void cooling_write_flavour( io_write_attribute_s(h_grpsph, "Cooling Model", "Constant Lambda"); } +#endif /** * @brief Calculates du/dt in code units for a particle. * * @param phys_const The physical constants in internal units. * @param us The internal system of units. + * @param cosmo The current cosmological model. * @param cooling The #cooling_function_data used in the run. * @param p Pointer to the particle data.. */ __attribute__((always_inline)) INLINE static float cooling_rate( const struct phys_const* const phys_const, const struct unit_system* us, + const struct cosmology* restrict cosmo, const struct cooling_function_data* cooling, const struct part* p) { /* Get particle density */ - const float rho = hydro_get_density(p); + const float rho = hydro_get_physical_density(p, cosmo); /* Get cooling function properties */ const float X_H = cooling->hydrogen_mass_abundance; @@ -77,6 +82,7 @@ __attribute__((always_inline)) INLINE static float cooling_rate( * * @param phys_const The physical constants in internal units. * @param us The internal system of units. + * @param cosmo The current cosmological model. * @param cooling The #cooling_function_data used in the run. * @param p Pointer to the particle data. * @param dt The time-step of this particle. @@ -84,6 +90,7 @@ __attribute__((always_inline)) INLINE static float cooling_rate( __attribute__((always_inline)) INLINE static void cooling_cool_part( const struct phys_const* restrict phys_const, const struct unit_system* restrict us, + const struct cosmology* restrict cosmo, const struct cooling_function_data* restrict cooling, struct part* restrict p, struct xpart* restrict xp, float dt) { @@ -91,13 +98,13 @@ __attribute__((always_inline)) INLINE static void cooling_cool_part( const float u_floor = cooling->min_energy; /* Current energy */ - const float u_old = hydro_get_internal_energy(p); + const float u_old = hydro_get_physical_internal_energy(p, cosmo); /* Current du_dt */ const float hydro_du_dt = hydro_get_internal_energy_dt(p); /* Calculate cooling du_dt */ - float cooling_du_dt = cooling_rate(phys_const, us, cooling, p); + float cooling_du_dt = cooling_rate(phys_const, us, cosmo, cooling, p); /* Integrate cooling equation to enforce energy floor */ /* Factor of 1.5 included since timestep could potentially double */ @@ -117,17 +124,19 @@ __attribute__((always_inline)) INLINE static void cooling_cool_part( * * @param cooling The #cooling_function_data used in the run. * @param phys_const The physical constants in internal units. + * @param cosmo The current cosmological model. * @param us The internal system of units. * @param p Pointer to the particle data. */ __attribute__((always_inline)) INLINE static float cooling_timestep( const struct cooling_function_data* restrict cooling, const struct phys_const* restrict phys_const, + const struct cosmology* restrict cosmo, const struct unit_system* restrict us, const struct part* restrict p) { /* Get current internal energy */ - const float u = hydro_get_internal_energy(p); - const float du_dt = cooling_rate(phys_const, us, cooling, p); + const float u = hydro_get_physical_internal_energy(p, cosmo); + const float du_dt = cooling_rate(phys_const, us, cosmo, cooling, p); /* If we are close to (or below) the energy floor, we ignore the condition */ if (u < 1.01f * cooling->min_energy) diff --git a/src/cooling/grackle/cooling.h b/src/cooling/grackle/cooling.h index 29e00435e16751f01bdb58fe26af151b422bd5a1..d1da52300121ca56feea4114d74322120bd501ce 100644 --- a/src/cooling/grackle/cooling.h +++ b/src/cooling/grackle/cooling.h @@ -42,6 +42,8 @@ #define GRACKLE_NPART 1 #define GRACKLE_RANK 3 +#ifdef HAVE_HDF5 + /** * @brief Writes the current model of SPH to the file * @param h_grpsph The HDF5 group in which to write @@ -51,6 +53,7 @@ __attribute__((always_inline)) INLINE static void cooling_write_flavour( io_write_attribute_s(h_grpsph, "Cooling Model", "Grackle"); } +#endif /** * @brief Sets the cooling properties of the (x-)particles to a valid start @@ -120,6 +123,7 @@ __attribute__((always_inline)) INLINE static void cooling_print_backend( __attribute__((always_inline)) INLINE static double cooling_rate( const struct phys_const* restrict phys_const, const struct unit_system* restrict us, + const struct cosmology* restrict cosmo, const struct cooling_function_data* restrict cooling, struct part* restrict p, float dt) { @@ -147,8 +151,8 @@ __attribute__((always_inline)) INLINE static double cooling_rate( data.grid_end = grid_end; /* general particle data */ - gr_float density = hydro_get_density(p); - const double energy_before = hydro_get_internal_energy(p); + gr_float density = hydro_get_physical_density(p, cosmo); + const double energy_before = hydro_get_physical_internal_energy(p, cosmo); gr_float energy = energy_before; gr_float vx = 0; gr_float vy = 0; @@ -221,6 +225,7 @@ __attribute__((always_inline)) INLINE static double cooling_rate( * * @param phys_const The physical constants in internal units. * @param us The internal system of units. + * @param cosmo The current cosmological model. * @param cooling The #cooling_function_data used in the run. * @param p Pointer to the particle data. * @param dt The time-step of this particle. @@ -228,6 +233,7 @@ __attribute__((always_inline)) INLINE static double cooling_rate( __attribute__((always_inline)) INLINE static void cooling_cool_part( const struct phys_const* restrict phys_const, const struct unit_system* restrict us, + const struct cosmology* restrict cosmo, const struct cooling_function_data* restrict cooling, struct part* restrict p, struct xpart* restrict xp, float dt) { @@ -237,7 +243,7 @@ __attribute__((always_inline)) INLINE static void cooling_cool_part( const float hydro_du_dt = hydro_get_internal_energy_dt(p); /* compute cooling rate */ - const float du_dt = cooling_rate(phys_const, us, cooling, p, dt); + const float du_dt = cooling_rate(phys_const, us, cosmo, cooling, p, dt); /* record energy lost */ xp->cooling_data.radiated_energy += -du_dt * dt * hydro_get_mass(p); @@ -253,12 +259,14 @@ __attribute__((always_inline)) INLINE static void cooling_cool_part( * * @param cooling The #cooling_function_data used in the run. * @param phys_const The physical constants in internal units. + * @param cosmo The current cosmological model. * @param us The internal system of units. * @param p Pointer to the particle data. */ __attribute__((always_inline)) INLINE static float cooling_timestep( const struct cooling_function_data* restrict cooling, const struct phys_const* restrict phys_const, + const struct cosmology* restrict cosmo, const struct unit_system* restrict us, const struct part* restrict p) { return FLT_MAX; diff --git a/src/cooling/none/cooling.h b/src/cooling/none/cooling.h index 861159ec1022fcf6f7617fc6ca0c9b470aa6e7fa..a1cc6491115a38d6971a57603fef413c35b52027 100644 --- a/src/cooling/none/cooling.h +++ b/src/cooling/none/cooling.h @@ -37,6 +37,8 @@ #include "physical_constants.h" #include "units.h" +#ifdef HAVE_HDF5 + /** * @brief Writes the current model of SPH to the file * @param h_grpsph The HDF5 group in which to write @@ -46,6 +48,7 @@ __attribute__((always_inline)) INLINE static void cooling_write_flavour( io_write_attribute_s(h_grpsph, "Cooling Model", "None"); } +#endif /** * @brief Apply the cooling function to a particle. @@ -54,6 +57,7 @@ __attribute__((always_inline)) INLINE static void cooling_write_flavour( * * @param phys_const The physical constants in internal units. * @param us The internal system of units. + * @param cosmo The current cosmological model. * @param cooling The #cooling_function_data used in the run. * @param p Pointer to the particle data. * @param xp Pointer to the extended particle data. @@ -62,6 +66,7 @@ __attribute__((always_inline)) INLINE static void cooling_write_flavour( __attribute__((always_inline)) INLINE static void cooling_cool_part( const struct phys_const* restrict phys_const, const struct unit_system* restrict us, + const struct cosmology* restrict cosmo, const struct cooling_function_data* restrict cooling, struct part* restrict p, struct xpart* restrict xp, float dt) {} @@ -72,12 +77,14 @@ __attribute__((always_inline)) INLINE static void cooling_cool_part( * * @param cooling The #cooling_function_data used in the run. * @param phys_const The physical constants in internal units. + * @param cosmo The current cosmological model. * @param us The internal system of units. * @param p Pointer to the particle data. */ __attribute__((always_inline)) INLINE static float cooling_timestep( const struct cooling_function_data* restrict cooling, const struct phys_const* restrict phys_const, + const struct cosmology* restrict cosmo, const struct unit_system* restrict us, const struct part* restrict p) { return FLT_MAX; diff --git a/src/cosmology.c b/src/cosmology.c new file mode 100644 index 0000000000000000000000000000000000000000..9b301388e08ca0f4aa2a7d5d8f351ab88682c8ba --- /dev/null +++ b/src/cosmology.c @@ -0,0 +1,679 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2017 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/>. + * + ******************************************************************************/ + +/** + * @file cosmology.c + * @brief Functions relating cosmological parameters + */ + +/* This object's header. */ +#include "cosmology.h" + +/* Some standard headers */ +#include <math.h> + +/* Local headers */ +#include "adiabatic_index.h" +#include "common_io.h" +#include "inline.h" +#include "restart.h" + +#ifdef HAVE_LIBGSL +#include <gsl/gsl_integration.h> +#endif + +/*! Number of values stored in the cosmological interpolation tables */ +const int cosmology_table_length = 10000; + +#ifdef HAVE_LIBGSL +/*! Size of the GSL workspace */ +const size_t GSL_workspace_size = 100000; +#endif + +/** + * @brief Returns the interpolated value from a table. + * + * Uses linear interpolation. + * + * @brief table The table of value to interpolate from (should be of length + * cosmology_table_length). + * @brief x The value to interpolate at. + * @brief x_min The mininum of the range of x. + * @brief x_max The maximum of the range of x. + */ +static INLINE double interp_table(double *table, double x, double x_min, + double x_max) { + + const double xx = ((x - x_min) / (x_max - x_min)) * cosmology_table_length; + const int i = (int)xx; + const int ii = (i >= cosmology_table_length) ? cosmology_table_length - 1 : i; + + if (ii <= 1) + return table[0] * xx; + else + return table[ii - 1] + (table[ii] - table[ii - 1]) * (xx - ii); +} + +/** + * @brief Computes the dark-energy equation of state at a given scale-factor a. + * + * We follow the convention of Linder & Jenkins, MNRAS, 346, 573, 2003 + * + * @param a The current scale-factor + * @param w_0 The equation of state parameter at z=0 + * @param w_a The equation of state evolution parameter + */ +static INLINE double cosmology_dark_energy_EoS(double a, double w_0, + double w_a) { + + return w_0 + w_a * (1. - a); +} + +/** + * @brief Computes the integral of the dark-energy equation of state + * up to a scale-factor a. + * + * We follow the convention of Linder & Jenkins, MNRAS, 346, 573, 2003 + * and compute \f$ \tilde{w}(a) = \int_0^a\frac{1 + w(z)}{1+z}dz \f$. + * + * @param a The current scale-factor. + * @param w0 The equation of state parameter at z=0 + * @param wa The equation of state evolution parameter + */ +static INLINE double w_tilde(double a, double w0, double wa) { + return (a - 1.) * wa - (1. + w0 + wa) * log(a); +} + +/** + * @brief Compute \f$ E(z) \f$. + */ +static INLINE double E(double Or, double Om, double Ok, double Ol, double w0, + double wa, double a) { + const double a_inv = 1. / a; + return sqrt(Or * a_inv * a_inv * a_inv * a_inv + Om * a_inv * a_inv * a_inv + + Ok * a_inv * a_inv + Ol * exp(3. * w_tilde(a, w0, wa))); +} + +/** + * @brief Returns the time (in internal units) since Big Bang at a given + * scale-factor. + * + * @param c The current #cosmology. + * @param a Scale-factor of interest. + */ +double cosmology_get_time_since_big_bang(const struct cosmology *c, double a) { + + /* Time between a_begin and a */ + const double delta_t = + interp_table(c->time_interp_table, log(a), c->log_a_begin, c->log_a_end); + + return c->time_interp_table_offset + delta_t; +} + +/** + * @brief Update the cosmological parameters to the current simulation time. + * + * @param c The #cosmology struct. + * @param ti_current The current (integer) time. + */ +void cosmology_update(struct cosmology *c, integertime_t ti_current) { + + /* Get scale factor and powers of it */ + const double a = c->a_begin * exp(ti_current * c->time_base); + const double a_inv = 1. / a; + c->a = a; + c->a_inv = a_inv; + c->a2_inv = a_inv * a_inv; + c->a3_inv = a_inv * a_inv * a_inv; + c->a_factor_internal_energy = + pow(a, -3. * hydro_gamma_minus_one); /* a^{3*(1-gamma)} */ + c->a_factor_pressure = pow(a, -3. * hydro_gamma); /* a^{-3*gamma} */ + c->a_factor_sound_speed = + pow(a, -1.5 * hydro_gamma_minus_one); /* a^{3*(1-gamma)/2} */ + c->a_factor_grav_accel = a_inv * a_inv; /* 1 / a^2 */ + c->a_factor_hydro_accel = + pow(a, -3. * hydro_gamma + 2.); /* 1 / a^(3*gamma - 2) */ + c->a_factor_mu = + pow(a, 0.5 * (3. * hydro_gamma - 5.)); /* a^{(3*gamma - 5) / 2} */ + + /* Redshift */ + c->z = a_inv - 1.; + + /* Dark-energy equation of state */ + c->w = cosmology_dark_energy_EoS(a, c->w_0, c->w_a); + + /* E(z) */ + const double Omega_r = c->Omega_r; + const double Omega_m = c->Omega_m; + const double Omega_k = c->Omega_k; + const double Omega_l = c->Omega_lambda; + const double w0 = c->w_0; + const double wa = c->w_a; + const double E_z = E(Omega_r, Omega_m, Omega_k, Omega_l, w0, wa, a); + + /* H(z) */ + c->H = c->H0 * E_z; + + /* Expansion rate */ + c->a_dot = c->H * c->a; + + /* Time-step conversion factor */ + c->time_step_factor = c->H; + + /* Time */ + c->time = cosmology_get_time_since_big_bang(c, a); + c->lookback_time = c->universe_age_at_present_day - c->time; +} + +/** + * @brief Computes \f$ dt / a^2 \f$ for the current cosmology. + * + * @param a The scale-factor of interest. + * @param param The current #cosmology. + */ +double drift_integrand(double a, void *param) { + + const struct cosmology *c = (const struct cosmology *)param; + const double Omega_r = c->Omega_r; + const double Omega_m = c->Omega_m; + const double Omega_k = c->Omega_k; + const double Omega_l = c->Omega_lambda; + const double w_0 = c->w_0; + const double w_a = c->w_a; + const double H0 = c->H0; + + const double a_inv = 1. / a; + const double E_z = E(Omega_r, Omega_m, Omega_k, Omega_l, w_0, w_a, a); + const double H = H0 * E_z; + + return (1. / H) * a_inv * a_inv * a_inv; +} + +/** + * @brief Computes \f$ dt / a \f$ for the current cosmology. + * + * @param a The scale-factor of interest. + * @param param The current #cosmology. + */ +double gravity_kick_integrand(double a, void *param) { + + const struct cosmology *c = (const struct cosmology *)param; + const double Omega_r = c->Omega_r; + const double Omega_m = c->Omega_m; + const double Omega_k = c->Omega_k; + const double Omega_l = c->Omega_lambda; + const double w_0 = c->w_0; + const double w_a = c->w_a; + const double H0 = c->H0; + + const double a_inv = 1. / a; + const double E_z = E(Omega_r, Omega_m, Omega_k, Omega_l, w_0, w_a, a); + const double H = H0 * E_z; + + return (1. / H) * a_inv * a_inv; +} + +/** + * @brief Computes \f$ dt / a^{3(\gamma - 1) + 1} \f$ for the current cosmology. + * + * @param a The scale-factor of interest. + * @param param The current #cosmology. + */ +double hydro_kick_integrand(double a, void *param) { + + const struct cosmology *c = (const struct cosmology *)param; + const double Omega_r = c->Omega_r; + const double Omega_m = c->Omega_m; + const double Omega_k = c->Omega_k; + const double Omega_l = c->Omega_lambda; + const double w_0 = c->w_0; + const double w_a = c->w_a; + const double H0 = c->H0; + + const double a_inv = 1. / a; + const double E_z = E(Omega_r, Omega_m, Omega_k, Omega_l, w_0, w_a, a); + const double H = H0 * E_z; + + /* Note: we can't use the pre-defined pow_gamma_xxx() function as + as we need double precision accuracy for the GSL routine. */ + return (1. / H) * pow(a_inv, 3. * hydro_gamma_minus_one) * a_inv; +} + +/** + * @brief Computes \f$ dt \f$ for the current cosmology. + * + * @param a The scale-factor of interest. + * @param param The current #cosmology. + */ +double time_integrand(double a, void *param) { + + const struct cosmology *c = (const struct cosmology *)param; + const double Omega_r = c->Omega_r; + const double Omega_m = c->Omega_m; + const double Omega_k = c->Omega_k; + const double Omega_l = c->Omega_lambda; + const double w_0 = c->w_0; + const double w_a = c->w_a; + const double H0 = c->H0; + + const double a_inv = 1. / a; + const double E_z = E(Omega_r, Omega_m, Omega_k, Omega_l, w_0, w_a, a); + const double H = H0 * E_z; + + return (1. / H) * a_inv; +} + +/** + * @brief Initialise the interpolation tables for the integrals. + */ +void cosmology_init_tables(struct cosmology *c) { + + const ticks tic = getticks(); + +#ifdef HAVE_LIBGSL + + /* Retrieve some constants */ + const double a_begin = c->a_begin; + + /* Allocate memory for the interpolation tables */ + c->drift_fac_interp_table = + (double *)malloc(cosmology_table_length * sizeof(double)); + c->grav_kick_fac_interp_table = + (double *)malloc(cosmology_table_length * sizeof(double)); + c->hydro_kick_fac_interp_table = + (double *)malloc(cosmology_table_length * sizeof(double)); + c->time_interp_table = + (double *)malloc(cosmology_table_length * sizeof(double)); + + /* Prepare a table of scale factors for the integral bounds */ + const double delta_a = + (c->log_a_end - c->log_a_begin) / cosmology_table_length; + double *a_table = (double *)malloc(cosmology_table_length * sizeof(double)); + for (int i = 0; i < cosmology_table_length; i++) + a_table[i] = exp(c->log_a_begin + delta_a * (i + 1)); + + /* Initalise the GSL workspace */ + gsl_integration_workspace *space = + gsl_integration_workspace_alloc(GSL_workspace_size); + + double result, abserr; + + /* Integrate the drift factor \int_{a_begin}^{a_table[i]} dt/a^2 */ + gsl_function F = {&drift_integrand, c}; + for (int i = 0; i < cosmology_table_length; i++) { + gsl_integration_qag(&F, a_begin, a_table[i], 0, 1.0e-10, GSL_workspace_size, + GSL_INTEG_GAUSS61, space, &result, &abserr); + + /* Store result */ + c->drift_fac_interp_table[i] = result; + } + + /* Integrate the kick factor \int_{a_begin}^{a_table[i]} dt/a */ + F.function = &gravity_kick_integrand; + for (int i = 0; i < cosmology_table_length; i++) { + gsl_integration_qag(&F, a_begin, a_table[i], 0, 1.0e-10, GSL_workspace_size, + GSL_INTEG_GAUSS61, space, &result, &abserr); + + /* Store result */ + c->grav_kick_fac_interp_table[i] = result; + } + + /* Integrate the kick factor \int_{a_begin}^{a_table[i]} dt/a^(3(g-1)+1) */ + F.function = &hydro_kick_integrand; + for (int i = 0; i < cosmology_table_length; i++) { + gsl_integration_qag(&F, a_begin, a_table[i], 0, 1.0e-10, GSL_workspace_size, + GSL_INTEG_GAUSS61, space, &result, &abserr); + + /* Store result */ + c->hydro_kick_fac_interp_table[i] = result; + } + + /* Integrate the time \int_{a_begin}^{a_table[i]} dt */ + F.function = &time_integrand; + for (int i = 0; i < cosmology_table_length; i++) { + gsl_integration_qag(&F, a_begin, a_table[i], 0, 1.0e-10, GSL_workspace_size, + GSL_INTEG_GAUSS61, space, &result, &abserr); + + /* Store result */ + c->time_interp_table[i] = result; + } + + /* Integrate the time \int_{0}^{a_begin} dt */ + gsl_integration_qag(&F, 0., a_begin, 0, 1.0e-10, GSL_workspace_size, + GSL_INTEG_GAUSS61, space, &result, &abserr); + c->time_interp_table_offset = result; + + /* Integrate the time \int_{0}^{1} dt */ + gsl_integration_qag(&F, 0., 1, 0, 1.0e-13, GSL_workspace_size, + GSL_INTEG_GAUSS61, space, &result, &abserr); + c->universe_age_at_present_day = result; + + /* Free the workspace and temp array */ + gsl_integration_workspace_free(space); + free(a_table); + +#else + + error("Code not compiled with GSL. Can't compute cosmology integrals."); + +#endif + + message("took %.3f %s.", clocks_from_ticks(getticks() - tic), + clocks_getunit()); +} + +/** + * @brief Initialises the #cosmology from the values read in the parameter file. + * + * @param params The parsed values. + * @param us The current internal system of units. + * @param phys_const The physical constants in the current system of units. + * @param c The #cosmology to initialise. + */ +void cosmology_init(const struct swift_params *params, + const struct unit_system *us, + const struct phys_const *phys_const, struct cosmology *c) { + + /* Read in the cosmological parameters */ + c->Omega_m = parser_get_param_double(params, "Cosmology:Omega_m"); + c->Omega_r = parser_get_opt_param_double(params, "Cosmology:Omega_r", 0.); + c->Omega_lambda = parser_get_param_double(params, "Cosmology:Omega_lambda"); + c->Omega_b = parser_get_param_double(params, "Cosmology:Omega_b"); + c->w_0 = parser_get_opt_param_double(params, "Cosmology:w_0", -1.); + c->w_a = parser_get_opt_param_double(params, "Cosmology:w_a", 0.); + c->h = parser_get_param_double(params, "Cosmology:h"); + + /* Read the start and end of the simulation */ + c->a_begin = parser_get_param_double(params, "Cosmology:a_begin"); + c->a_end = parser_get_param_double(params, "Cosmology:a_end"); + c->log_a_begin = log(c->a_begin); + c->log_a_end = log(c->a_end); + c->time_base = (c->log_a_end - c->log_a_begin) / max_nr_timesteps; + c->time_base_inv = 1. / c->time_base; + + /* Construct derived quantities */ + + /* Curvature density (for closure) */ + c->Omega_k = 1. - (c->Omega_m + c->Omega_r + c->Omega_lambda); + + /* Dark-energy equation of state */ + c->w = cosmology_dark_energy_EoS(c->a_begin, c->w_0, c->w_a); + + /* Hubble constant in internal units */ + const double km = 1.e5 / units_cgs_conversion_factor(us, UNIT_CONV_LENGTH); + const double H0_cgs = + 100. * c->h * (km / (1.e6 * phys_const->const_parsec)); /* s^-1 */ + c->H0 = H0_cgs * units_cgs_conversion_factor(us, UNIT_CONV_TIME); + c->Hubble_time = 1. / c->H0; + + /* Initialise the interpolation tables */ + c->drift_fac_interp_table = NULL; + c->grav_kick_fac_interp_table = NULL; + c->hydro_kick_fac_interp_table = NULL; + c->time_interp_table = NULL; + c->time_interp_table_offset = 0.; + cosmology_init_tables(c); + + /* Set remaining variables to alid values */ + cosmology_update(c, 0); + + /* Update the times */ + c->time_begin = cosmology_get_time_since_big_bang(c, c->a_begin); + c->time_end = cosmology_get_time_since_big_bang(c, c->a_end); +} + +/** + * @brief Initialise the #cosmology for non-cosmological time-integration + * + * Essentially sets all constants to 1 or 0. + * + * @param c The #cosmology to initialise. + */ +void cosmology_init_no_cosmo(struct cosmology *c) { + + c->Omega_m = 0.; + c->Omega_r = 0.; + c->Omega_k = 0.; + c->Omega_lambda = 0.; + c->Omega_b = 0.; + c->w_0 = 0.; + c->w_a = 0.; + c->h = 0.; + c->w = 0.; + + c->a_begin = 1.; + c->a_end = 1.; + c->log_a_begin = 0.; + c->log_a_end = 0.; + + c->H = 0.; + c->a = 1.; + c->a_inv = 1.; + c->a2_inv = 1.; + c->a3_inv = 1.; + c->a_factor_internal_energy = 1.; + c->a_factor_pressure = 1.; + c->a_factor_sound_speed = 1.; + c->a_factor_mu = 1.; + c->a_factor_hydro_accel = 1.; + c->a_factor_grav_accel = 1.; + + c->time_step_factor = 1.; + + c->a_dot = 0.; + c->time = 0.; + c->universe_age_at_present_day = 0.; + + /* Initialise the interpolation tables */ + c->drift_fac_interp_table = NULL; + c->grav_kick_fac_interp_table = NULL; + c->hydro_kick_fac_interp_table = NULL; + c->time_interp_table = NULL; + c->time_interp_table_offset = 0.; + + c->time_begin = 0.; + c->time_end = 0.; +} + +/** + * @brief Computes the cosmology factor that enters the drift operator. + * + * Computes \f$ \int_{a_start}^{a_end} dt/a^2 \f$ using the interpolation table. + * + * @param c The current #cosmology. + * @param ti_start the (integer) time of the start of the drift. + * @param ti_end the (integer) time of the end of the drift. + */ +double cosmology_get_drift_factor(const struct cosmology *c, + integertime_t ti_start, + integertime_t ti_end) { + + const double a_start = c->log_a_begin + ti_start * c->time_base; + const double a_end = c->log_a_begin + ti_end * c->time_base; + + const double int_start = interp_table(c->drift_fac_interp_table, a_start, + c->log_a_begin, c->log_a_end); + const double int_end = interp_table(c->drift_fac_interp_table, a_end, + c->log_a_begin, c->log_a_end); + + return int_end - int_start; +} + +/** + * @brief Computes the cosmology factor that enters the gravity kick operator. + * + * Computes \f$ \int_{a_start}^{a_end} dt/a \f$ using the interpolation table. + * + * @param c The current #cosmology. + * @param ti_start the (integer) time of the start of the drift. + * @param ti_end the (integer) time of the end of the drift. + */ +double cosmology_get_grav_kick_factor(const struct cosmology *c, + integertime_t ti_start, + integertime_t ti_end) { + + const double a_start = c->log_a_begin + ti_start * c->time_base; + const double a_end = c->log_a_begin + ti_end * c->time_base; + + const double int_start = interp_table(c->grav_kick_fac_interp_table, a_start, + c->log_a_begin, c->log_a_end); + const double int_end = interp_table(c->grav_kick_fac_interp_table, a_end, + c->log_a_begin, c->log_a_end); + + return int_end - int_start; +} + +/** + * @brief Computes the cosmology factor that enters the hydro kick operator. + * + * Computes \f$ \int_{a_start}^{a_end} dt/a \f$ using the interpolation table. + * + * @param c The current #cosmology. + * @param ti_start the (integer) time of the start of the drift. + * @param ti_end the (integer) time of the end of the drift. + */ +double cosmology_get_hydro_kick_factor(const struct cosmology *c, + integertime_t ti_start, + integertime_t ti_end) { + + const double a_start = c->log_a_begin + ti_start * c->time_base; + const double a_end = c->log_a_begin + ti_end * c->time_base; + + const double int_start = interp_table(c->drift_fac_interp_table, a_start, + c->log_a_begin, c->log_a_end); + const double int_end = interp_table(c->drift_fac_interp_table, a_end, + c->log_a_begin, c->log_a_end); + + return int_end - int_start; +} + +/** + * @brief Computes the cosmology factor that enters the thermal variable kick + * operator. + * + * Computes \f$ \int_{a_start}^{a_end} dt/a^2 \f$ using the interpolation table. + * + * @param c The current #cosmology. + * @param ti_start the (integer) time of the start of the drift. + * @param ti_end the (integer) time of the end of the drift. + */ +double cosmology_get_therm_kick_factor(const struct cosmology *c, + integertime_t ti_start, + integertime_t ti_end) { + + const double a_start = c->log_a_begin + ti_start * c->time_base; + const double a_end = c->log_a_begin + ti_end * c->time_base; + + const double int_start = interp_table(c->hydro_kick_fac_interp_table, a_start, + c->log_a_begin, c->log_a_end); + const double int_end = interp_table(c->hydro_kick_fac_interp_table, a_end, + c->log_a_begin, c->log_a_end); + + return int_end - int_start; +} + +/** + * @brief Compute the cosmic time (in internal units) between two scale-factors. + * + * @brief c The current #cosmology. + * @brief a1 The first scale-factor. + * @brief a2 The second scale-factor. + */ +double cosmology_get_delta_time(const struct cosmology *c, double a1, + double a2) { + + /* Time between a_begin and a1 */ + const double t1 = + interp_table(c->time_interp_table, log(a1), c->log_a_begin, c->log_a_end); + + /* Time between a_begin and a1 */ + const double t2 = + interp_table(c->time_interp_table, log(a2), c->log_a_begin, c->log_a_end); + + return t2 - t1; +} + +/** + * @brief Prints the #cosmology model to stdout. + */ +void cosmology_print(const struct cosmology *c) { + + message( + "Density parameters: [O_m, O_l, O_b, O_k, O_r] = [%f, %f, %f, %f, %f]", + c->Omega_m, c->Omega_lambda, c->Omega_b, c->Omega_k, c->Omega_r); + message("Dark energy equation of state: w_0=%f w_a=%f", c->w_0, c->w_a); + message("Hubble constant: h = %f, H_0 = %e U_t^(-1)", c->h, c->H0); + message("Hubble time: 1/H0 = %e U_t", c->Hubble_time); + message("Universe age at present day: %e U_t", + c->universe_age_at_present_day); +} + +void cosmology_clean(struct cosmology *c) { + + free(c->drift_fac_interp_table); + free(c->grav_kick_fac_interp_table); + free(c->hydro_kick_fac_interp_table); + free(c->time_interp_table); +} + +#ifdef HAVE_HDF5 +void cosmology_write_model(hid_t h_grp, const struct cosmology *c) { + + io_write_attribute_d(h_grp, "a_beg", c->a_begin); + io_write_attribute_d(h_grp, "a_end", c->a_end); + io_write_attribute_d(h_grp, "time_beg [internal units]", c->time_begin); + io_write_attribute_d(h_grp, "time_end [internal units]", c->time_end); + io_write_attribute_d(h_grp, "h", c->h); + io_write_attribute_d(h_grp, "H0 [internal units]", c->H0); + io_write_attribute_d(h_grp, "Hubble time [internal units]", c->Hubble_time); + io_write_attribute_d(h_grp, "Omega_m", c->Omega_m); + io_write_attribute_d(h_grp, "Omega_r", c->Omega_r); + io_write_attribute_d(h_grp, "Omega_b", c->Omega_b); + io_write_attribute_d(h_grp, "Omega_k", c->Omega_k); + io_write_attribute_d(h_grp, "Omega_lambda", c->Omega_lambda); + io_write_attribute_d(h_grp, "w_0", c->w_0); + io_write_attribute_d(h_grp, "w_a", c->w_a); +} +#endif + +/** + * @brief Write a cosmology struct to the given FILE as a stream of bytes. + * + * @param cosmology the struct + * @param stream the file stream + */ +void cosmology_struct_dump(const struct cosmology *cosmology, FILE *stream) { + restart_write_blocks((void *)cosmology, sizeof(struct cosmology), 1, stream, + "cosmology", "cosmology function"); +} + +/** + * @brief Restore a cosmology struct from the given FILE as a stream of + * bytes. + * + * @param cosmology the struct + * @param stream the file stream + */ +void cosmology_struct_restore(struct cosmology *cosmology, FILE *stream) { + restart_read_blocks((void *)cosmology, sizeof(struct cosmology), 1, stream, + NULL, "cosmology function"); + + /* Re-initialise the tables */ + cosmology_init_tables(cosmology); +} diff --git a/src/cosmology.h b/src/cosmology.h new file mode 100644 index 0000000000000000000000000000000000000000..b1b33930bad7a49c0f2abe3a2201d71c9be57305 --- /dev/null +++ b/src/cosmology.h @@ -0,0 +1,197 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2017 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_COSMOLOGY_H +#define SWIFT_COSMOLOGY_H + +/* Config parameters. */ +#include "../config.h" + +#include "parser.h" +#include "physical_constants.h" +#include "timeline.h" +#include "units.h" + +/** + * @brief Cosmological parameters + */ +struct cosmology { + + /*! Current expansion factor of the Universe */ + double a; + + /*! Inverse of the current expansion factor of the Universe */ + double a_inv; + + /*! Inverse square of the current expansion factor of the Universe */ + double a2_inv; + + /*! Inverse cube of the current expansion factor of the Universe */ + double a3_inv; + + /*! Power of the scale-factor used for internal energy conversion to physical + */ + double a_factor_internal_energy; + + /*! Power of the scale-factor used for pressure conversion to physical */ + double a_factor_pressure; + + /*! Power of the scale-factor used for sound-speed conversion to physical */ + double a_factor_sound_speed; + + /*! Power of the scale-factor used for relative velocities in viscosity term + */ + double a_factor_mu; + + /*! Power of the scale-factor used for gravity accelerations */ + double a_factor_grav_accel; + + /*! Power of the scale-factor used for hydro accelerations */ + double a_factor_hydro_accel; + + /*! Current redshift */ + double z; + + /*! Hubble constant at the current redshift (in internal units) */ + double H; + + /*! Conversion factor from internal time-step size to cosmological step */ + double time_step_factor; + + /*! Expansion rate at the current redshift (in internal units) */ + double a_dot; + + /*! Time (in internal units) since the Big Bang */ + double time; + + /*! Lookback time (in internal units) */ + double lookback_time; + + /*! Dark-energy equation of state at the current time */ + double w; + + /*------------------------------------------------------------------ */ + + /*! Starting expansion factor */ + double a_begin; + + /*! Final expansion factor */ + double a_end; + + /*! Time (in internal units) since the Big Bang at the start */ + double time_begin; + + /*! Time (in internal units) since the Big Bang at the end */ + double time_end; + + /*! Conversion factor from integer time-line to \f$ d\log{a} \f$ */ + double time_base; + + /*! Inverse of conversion factor from integer time-line to \f$ d\log{a} \f$ */ + double time_base_inv; + + /*! Reduced Hubble constant (H0 / (100km/s/Mpc)) */ + double h; + + /*! Hubble constant at z = 0 (in internal units) */ + double H0; + + /*! Hubble time 1/H0 */ + double Hubble_time; + + /*! Matter density parameter */ + double Omega_m; + + /*! Baryon density parameter */ + double Omega_b; + + /*! Radiation constant density parameter */ + double Omega_lambda; + + /*! Cosmological constant density parameter */ + double Omega_r; + + /*! Curvature density parameter */ + double Omega_k; + + /*! Dark-energy equation of state at z=0 */ + double w_0; + + /*! Dark-energy evolution parameter */ + double w_a; + + /*! Log of starting expansion factor */ + double log_a_begin; + + /*! Log of final expansion factor */ + double log_a_end; + + /*! Drift factor interpolation table */ + double *drift_fac_interp_table; + + /*! Kick factor (gravity) interpolation table */ + double *grav_kick_fac_interp_table; + + /*! Kick factor (hydro) interpolation table */ + double *hydro_kick_fac_interp_table; + + /*! Time interpolation table */ + double *time_interp_table; + + /*! Time between Big Bang and first entry in the table */ + double time_interp_table_offset; + + /*! Time at the present-day (a=1) */ + double universe_age_at_present_day; +}; + +void cosmology_update(struct cosmology *c, integertime_t ti_current); + +double cosmology_get_drift_factor(const struct cosmology *cosmo, + integertime_t ti_start, integertime_t ti_end); +double cosmology_get_grav_kick_factor(const struct cosmology *cosmo, + integertime_t ti_start, + integertime_t ti_end); +double cosmology_get_hydro_kick_factor(const struct cosmology *cosmo, + integertime_t ti_start, + integertime_t ti_end); +double cosmology_get_therm_kick_factor(const struct cosmology *cosmo, + integertime_t ti_start, + integertime_t ti_end); + +double cosmology_get_delta_time(const struct cosmology *c, double a1, + double a2); + +void cosmology_init(const struct swift_params *params, + const struct unit_system *us, + const struct phys_const *phys_const, struct cosmology *c); + +void cosmology_init_no_cosmo(struct cosmology *c); + +void cosmology_print(const struct cosmology *c); +void cosmology_clean(struct cosmology *c); + +#ifdef HAVE_HDF5 +void cosmology_write_model(hid_t h_grp, const struct cosmology *c); +#endif + +/* Dump/restore. */ +void cosmology_struct_dump(const struct cosmology *cosmology, FILE *stream); +void cosmology_struct_restore(struct cosmology *cosmology, FILE *stream); + +#endif /* SWIFT_COSMOLOGY_H */ diff --git a/src/drift.h b/src/drift.h index e86d290cb796153d3c3fc43c21b25d2c7e435657..b7d5e3abe648e327f1560641676685b2d038ce3b 100644 --- a/src/drift.h +++ b/src/drift.h @@ -30,16 +30,15 @@ #include "part.h" /** - * @brief Perform the 'drift' operation on a #gpart + * @brief Perform the 'drift' operation on a #gpart. * * @param gp The #gpart to drift. - * @param dt The drift time-step - * @param timeBase The minimal allowed time-step size. - * @param ti_old Integer start of time-step - * @param ti_current Integer end of time-step + * @param dt_drift The drift time-step. + * @param ti_old Integer start of time-step (for debugging checks). + * @param ti_current Integer end of time-step (for debugging checks). */ __attribute__((always_inline)) INLINE static void drift_gpart( - struct gpart *restrict gp, double dt, double timeBase, integertime_t ti_old, + struct gpart *restrict gp, double dt_drift, integertime_t ti_old, integertime_t ti_current) { #ifdef SWIFT_DEBUG_CHECKS @@ -54,14 +53,14 @@ __attribute__((always_inline)) INLINE static void drift_gpart( #endif /* Drift... */ - gp->x[0] += gp->v_full[0] * dt; - gp->x[1] += gp->v_full[1] * dt; - gp->x[2] += gp->v_full[2] * dt; + gp->x[0] += gp->v_full[0] * dt_drift; + gp->x[1] += gp->v_full[1] * dt_drift; + gp->x[2] += gp->v_full[2] * dt_drift; /* Compute offset since last cell construction */ - gp->x_diff[0] -= gp->v_full[0] * dt; - gp->x_diff[1] -= gp->v_full[1] * dt; - gp->x_diff[2] -= gp->v_full[2] * dt; + gp->x_diff[0] -= gp->v_full[0] * dt_drift; + gp->x_diff[1] -= gp->v_full[1] * dt_drift; + gp->x_diff[2] -= gp->v_full[2] * dt_drift; } /** @@ -69,14 +68,17 @@ __attribute__((always_inline)) INLINE static void drift_gpart( * * @param p The #part to drift. * @param xp The #xpart of the particle. - * @param dt The drift time-step - * @param timeBase The minimal allowed time-step size. - * @param ti_old Integer start of time-step - * @param ti_current Integer end of time-step + * @param dt_drift The drift time-step + * @param dt_kick_grav The kick time-step for gravity accelerations. + * @param dt_kick_hydro The kick time-step for hydro accelerations. + * @param dt_therm The drift time-step for thermodynamic quantities. + * @param ti_old Integer start of time-step (for debugging checks). + * @param ti_current Integer end of time-step (for debugging checks). */ __attribute__((always_inline)) INLINE static void drift_part( - struct part *restrict p, struct xpart *restrict xp, double dt, - double timeBase, integertime_t ti_old, integertime_t ti_current) { + struct part *restrict p, struct xpart *restrict xp, double dt_drift, + double dt_kick_hydro, double dt_kick_grav, double dt_therm, + integertime_t ti_old, integertime_t ti_current) { #ifdef SWIFT_DEBUG_CHECKS if (p->ti_drift != ti_old) @@ -89,21 +91,25 @@ __attribute__((always_inline)) INLINE static void drift_part( #endif /* Drift... */ - p->x[0] += xp->v_full[0] * dt; - p->x[1] += xp->v_full[1] * dt; - p->x[2] += xp->v_full[2] * dt; + p->x[0] += xp->v_full[0] * dt_drift; + p->x[1] += xp->v_full[1] * dt_drift; + p->x[2] += xp->v_full[2] * dt_drift; /* Predict velocities (for hydro terms) */ - p->v[0] += p->a_hydro[0] * dt; - p->v[1] += p->a_hydro[1] * dt; - p->v[2] += p->a_hydro[2] * dt; + p->v[0] += p->a_hydro[0] * dt_kick_hydro; + p->v[1] += p->a_hydro[1] * dt_kick_hydro; + p->v[2] += p->a_hydro[2] * dt_kick_hydro; + + p->v[0] += xp->a_grav[0] * dt_kick_grav; + p->v[1] += xp->a_grav[1] * dt_kick_grav; + p->v[2] += xp->a_grav[2] * dt_kick_grav; /* Predict the values of the extra fields */ - hydro_predict_extra(p, xp, dt); + hydro_predict_extra(p, xp, dt_drift, dt_therm); /* Compute offsets since last cell construction */ for (int k = 0; k < 3; k++) { - const float dx = xp->v_full[k] * dt; + const float dx = xp->v_full[k] * dt_drift; xp->x_diff[k] -= dx; xp->x_diff_sort[k] -= dx; } @@ -113,13 +119,12 @@ __attribute__((always_inline)) INLINE static void drift_part( * @brief Perform the 'drift' operation on a #spart * * @param sp The #spart to drift. - * @param dt The drift time-step - * @param timeBase The minimal allowed time-step size. - * @param ti_old Integer start of time-step - * @param ti_current Integer end of time-step + * @param dt_drift The drift time-step. + * @param ti_old Integer start of time-step (for debugging checks). + * @param ti_current Integer end of time-step (for debugging checks). */ __attribute__((always_inline)) INLINE static void drift_spart( - struct spart *restrict sp, double dt, double timeBase, integertime_t ti_old, + struct spart *restrict sp, double dt_drift, integertime_t ti_old, integertime_t ti_current) { #ifdef SWIFT_DEBUG_CHECKS @@ -134,9 +139,9 @@ __attribute__((always_inline)) INLINE static void drift_spart( #endif /* Drift... */ - sp->x[0] += sp->v[0] * dt; - sp->x[1] += sp->v[1] * dt; - sp->x[2] += sp->v[2] * dt; + sp->x[0] += sp->v[0] * dt_drift; + sp->x[1] += sp->v[1] * dt_drift; + sp->x[2] += sp->v[2] * dt_drift; } #endif /* SWIFT_DRIFT_H */ diff --git a/src/engine.c b/src/engine.c index 3d33fda917b27222a46802285d7f07665c4b352c..c52c4b21cd9bb4d3222edb3e804507ee747bae0f 100644 --- a/src/engine.c +++ b/src/engine.c @@ -51,8 +51,10 @@ #include "active.h" #include "atomic.h" #include "cell.h" +#include "chemistry.h" #include "clocks.h" #include "cooling.h" +#include "cosmology.h" #include "cycle.h" #include "debug.h" #include "error.h" @@ -85,15 +87,15 @@ const char *engine_policy_names[] = {"none", "steal", "keep", "block", - "cpu_tight", + "cpu tight", "mpi", - "numa_affinity", + "numa affinity", "hydro", - "self_gravity", - "external_gravity", - "cosmology_integration", - "drift_all", - "reconstruct_mpoles", + "self gravity", + "external gravity", + "cosmological integration", + "drift everything", + "reconstruct multi-poles", "cooling", "sourceterms", "stars"}; @@ -4374,14 +4376,17 @@ void engine_step(struct engine *e) { if (e->nodeID == 0) { /* Print some information to the screen */ - printf(" %6d %14e %14e %12zu %12zu %12zu %21.3f %6d\n", e->step, e->time, - e->timeStep, e->updates, e->g_updates, e->s_updates, + printf(" %6d %14e %14e %14e %4d %4d %12zu %12zu %12zu %21.3f %6d\n", + e->step, e->time, e->cosmology->a, e->time_step, e->min_active_bin, + e->max_active_bin, e->updates, e->g_updates, e->s_updates, e->wallclock_time, e->step_props); fflush(stdout); - fprintf(e->file_timesteps, " %6d %14e %14e %12zu %12zu %12zu %21.3f %6d\n", - e->step, e->time, e->timeStep, e->updates, e->g_updates, - e->s_updates, e->wallclock_time, e->step_props); + fprintf(e->file_timesteps, + " %6d %14e %14e %14e %4d %4d %12zu %12zu %12zu %21.3f %6d\n", + e->step, e->time, e->cosmology->a, e->time_step, e->min_active_bin, + e->max_active_bin, e->updates, e->g_updates, e->s_updates, + e->wallclock_time, e->step_props); fflush(e->file_timesteps); } @@ -4389,12 +4394,21 @@ void engine_step(struct engine *e) { e->ti_old = e->ti_current; e->ti_current = e->ti_end_min; e->max_active_bin = get_max_active_bin(e->ti_end_min); + e->min_active_bin = get_min_active_bin(e->ti_current, e->ti_old); e->step += 1; - e->time = e->ti_current * e->timeBase + e->timeBegin; - e->timeOld = e->ti_old * e->timeBase + e->timeBegin; - e->timeStep = (e->ti_current - e->ti_old) * e->timeBase; e->step_props = engine_step_prop_none; + if (e->policy & engine_policy_cosmology) { + e->time_old = e->time; + cosmology_update(e->cosmology, e->ti_current); + e->time = e->cosmology->time; + e->time_step = e->time - e->time_old; + } else { + e->time = e->ti_current * e->time_base + e->time_begin; + e->time_old = e->ti_old * e->time_base + e->time_begin; + e->time_step = (e->ti_current - e->ti_old) * e->time_base; + } + /* Prepare the tasks to be launched, rebuild or repartition if needed. */ engine_prepare(e); @@ -5171,6 +5185,7 @@ void engine_unpin() { * @param reparttype What type of repartition algorithm are we using ? * @param internal_units The system of units used internally. * @param physical_constants The #phys_const used for this run. + * @param cosmo The #cosmology used for this run. * @param hydro The #hydro_props used for this run. * @param gravity The #gravity_props used for this run. * @param potential The properties of the external potential. @@ -5182,7 +5197,7 @@ void engine_init( struct engine *e, struct space *s, const struct swift_params *params, long long Ngas, long long Ndm, int policy, int verbose, struct repartition *reparttype, const struct unit_system *internal_units, - const struct phys_const *physical_constants, + const struct phys_const *physical_constants, struct cosmology *cosmo, const struct hydro_props *hydro, const struct gravity_props *gravity, const struct external_potential *potential, const struct cooling_function_data *cooling_func, @@ -5200,16 +5215,15 @@ void engine_init( e->proxy_ind = NULL; e->nr_proxies = 0; e->reparttype = reparttype; - e->timeBegin = parser_get_param_double(params, "TimeIntegration:time_begin"); - e->timeEnd = parser_get_param_double(params, "TimeIntegration:time_end"); - e->timeOld = e->timeBegin; - e->time = e->timeBegin; e->ti_old = 0; e->ti_current = 0; + e->time_step = 0.; + e->time_base = 0.; + e->time_base_inv = 0.; + e->time_begin = 0.; + e->time_end = 0.; e->max_active_bin = num_time_bins; - e->timeStep = 0.; - e->timeBase = 0.; - e->timeBase_inv = 0.; + e->min_active_bin = 1; e->internal_units = internal_units; e->timeFirstSnapshot = parser_get_param_double(params, "Snapshots:time_first"); @@ -5231,6 +5245,7 @@ void engine_init( e->count_step = 0; e->wallclock_time = 0.f; e->physical_constants = physical_constants; + e->cosmology = cosmo; e->hydro_properties = hydro; e->gravity_properties = gravity; e->external_potential = potential; @@ -5246,10 +5261,29 @@ void engine_init( /* Make the space link back to the engine. */ s->e = e; - /* Setup the timestep */ - e->timeBase = (e->timeEnd - e->timeBegin) / max_nr_timesteps; - e->timeBase_inv = 1.0 / e->timeBase; - e->ti_current = 0; + /* Setup the timestep if non-cosmological */ + if (!(e->policy & engine_policy_cosmology)) { + e->time_begin = + parser_get_param_double(params, "TimeIntegration:time_begin"); + e->time_end = parser_get_param_double(params, "TimeIntegration:time_end"); + e->time_old = e->time_begin; + e->time = e->time_begin; + + e->time_base = (e->time_end - e->time_begin) / max_nr_timesteps; + e->time_base_inv = 1.0 / e->time_base; + e->ti_current = 0; + } else { + + e->time_begin = e->cosmology->time_begin; + e->time_end = e->cosmology->time_end; + e->time_old = e->time_begin; + e->time = e->time_begin; + + /* Copy the relevent information from the cosmology model */ + e->time_base = e->cosmology->time_base; + e->time_base_inv = e->cosmology->time_base_inv; + e->ti_current = 0; + } } /** @@ -5485,12 +5519,13 @@ void engine_config(int restart, struct engine *e, "Version: %s \n# " "Number of threads: %d\n# Number of MPI ranks: %d\n# Hydrodynamic " "scheme: %s\n# Hydrodynamic kernel: %s\n# No. of neighbours: %.2f " - "+/- %.4f\n# Eta: %f\n", + "+/- %.4f\n# Eta: %f\n# Config: %s\n# CFLAGS: %s\n", hostname(), git_branch(), git_revision(), compiler_name(), compiler_version(), e->nr_threads, e->nr_nodes, SPH_IMPLEMENTATION, kernel_name, e->hydro_properties->target_neighbours, e->hydro_properties->delta_neighbours, - e->hydro_properties->eta_neighbours); + e->hydro_properties->eta_neighbours, configuration_options(), + compilation_cflags()); fprintf(e->file_timesteps, "# Step Properties: Rebuild=%d, Redistribute=%d, Repartition=%d, " @@ -5500,9 +5535,10 @@ void engine_config(int restart, struct engine *e, engine_step_prop_snapshot, engine_step_prop_restarts); fprintf(e->file_timesteps, - "# %6s %14s %14s %12s %12s %12s %16s [%s] %6s\n", "Step", "Time", - "Time-step", "Updates", "g-Updates", "s-Updates", - "Wall-clock time", clocks_getunit(), "Props"); + "# %6s %14s %14s %14s %9s %12s %12s %12s %16s [%s] %6s\n", "Step", + "Time", "Scale-factor", "Time-step", "Time-bins", "Updates", + "g-Updates", "s-Updates", "Wall-clock time", clocks_getunit(), + "Props"); fflush(e->file_timesteps); } } @@ -5519,11 +5555,11 @@ void engine_config(int restart, struct engine *e, if (e->nodeID == 0) gravity_props_print(e->gravity_properties); /* Check we have sensible time bounds */ - if (e->timeBegin >= e->timeEnd) + if (e->time_begin >= e->time_end) error( "Final simulation time (t_end = %e) must be larger than the start time " "(t_beg = %e)", - e->timeEnd, e->timeBegin); + e->time_end, e->time_begin); /* Check we have sensible time-step values */ if (e->dt_min > e->dt_max) @@ -5532,47 +5568,40 @@ void engine_config(int restart, struct engine *e, "size (%e)", e->dt_min, e->dt_max); - /* Deal with timestep */ - if (!restart) { - e->timeBase = (e->timeEnd - e->timeBegin) / max_nr_timesteps; - e->timeBase_inv = 1.0 / e->timeBase; - e->ti_current = 0; - } - /* Info about time-steps */ if (e->nodeID == 0) { - message("Absolute minimal timestep size: %e", e->timeBase); + message("Absolute minimal timestep size: %e", e->time_base); - float dt_min = e->timeEnd - e->timeBegin; + float dt_min = e->time_end - e->time_begin; while (dt_min > e->dt_min) dt_min /= 2.f; message("Minimal timestep size (on time-line): %e", dt_min); - float dt_max = e->timeEnd - e->timeBegin; + float dt_max = e->time_end - e->time_begin; while (dt_max > e->dt_max) dt_max /= 2.f; message("Maximal timestep size (on time-line): %e", dt_max); } - if (e->dt_min < e->timeBase && e->nodeID == 0) + if (e->dt_min < e->time_base && e->nodeID == 0) error( "Minimal time-step size smaller than the absolute possible minimum " "dt=%e", - e->timeBase); + e->time_base); - if (e->dt_max > (e->timeEnd - e->timeBegin) && e->nodeID == 0) + if (e->dt_max > (e->time_end - e->time_begin) && e->nodeID == 0) error("Maximal time-step size larger than the simulation run time t=%e", - e->timeEnd - e->timeBegin); + e->time_end - e->time_begin); /* Deal with outputs */ if (e->deltaTimeSnapshot < 0.) error("Time between snapshots (%e) must be positive.", e->deltaTimeSnapshot); - if (e->timeFirstSnapshot < e->timeBegin) + if (e->timeFirstSnapshot < e->time_begin) error( "Time of first snapshot (%e) must be after the simulation start t=%e.", - e->timeFirstSnapshot, e->timeBegin); + e->timeFirstSnapshot, e->time_begin); /* Find the time of the first output */ engine_compute_next_snapshot_time(e); @@ -5737,7 +5766,7 @@ void engine_print_policy(struct engine *e) { printf("[0000] %s engine_policy: engine policies are [ ", clocks_get_timesincestart()); for (int k = 0; k <= engine_maxpolicy; k++) - if (e->policy & (1 << k)) printf(" %s ", engine_policy_names[k + 1]); + if (e->policy & (1 << k)) printf(" '%s' ", engine_policy_names[k + 1]); printf(" ]\n"); fflush(stdout); } @@ -5745,7 +5774,7 @@ void engine_print_policy(struct engine *e) { printf("%s engine_policy: engine policies are [ ", clocks_get_timesincestart()); for (int k = 0; k <= engine_maxpolicy; k++) - if (e->policy & (1 << k)) printf(" %s ", engine_policy_names[k + 1]); + if (e->policy & (1 << k)) printf(" '%s' ", engine_policy_names[k + 1]); printf(" ]\n"); fflush(stdout); #endif @@ -5758,13 +5787,30 @@ void engine_print_policy(struct engine *e) { */ void engine_compute_next_snapshot_time(struct engine *e) { - for (double time = e->timeFirstSnapshot; - time < e->timeEnd + e->deltaTimeSnapshot; time += e->deltaTimeSnapshot) { + /* Find upper-bound on last output */ + double time_end; + if (e->policy & engine_policy_cosmology) + time_end = e->cosmology->a_end * e->deltaTimeSnapshot; + else + time_end = e->time_end + e->deltaTimeSnapshot; + + /* Find next snasphot above current time */ + double time = e->timeFirstSnapshot; + while (time < time_end) { /* Output time on the integer timeline */ - e->ti_nextSnapshot = (time - e->timeBegin) / e->timeBase; + if (e->policy & engine_policy_cosmology) + e->ti_nextSnapshot = log(time / e->cosmology->a_begin) / e->time_base; + else + e->ti_nextSnapshot = (time - e->time_begin) / e->time_base; + /* Found it? */ if (e->ti_nextSnapshot > e->ti_current) break; + + if (e->policy & engine_policy_cosmology) + time *= e->deltaTimeSnapshot; + else + time += e->deltaTimeSnapshot; } /* Deal with last snapshot */ @@ -5774,10 +5820,15 @@ void engine_compute_next_snapshot_time(struct engine *e) { } else { /* Be nice, talk... */ - const float next_snapshot_time = - e->ti_nextSnapshot * e->timeBase + e->timeBegin; - if (e->verbose) + if (e->policy & engine_policy_cosmology) { + const float next_snapshot_time = + exp(e->ti_nextSnapshot * e->time_base) * e->cosmology->a_begin; + message("Next output time set to a=%e.", next_snapshot_time); + } else { + const float next_snapshot_time = + e->ti_nextSnapshot * e->time_base + e->time_begin; message("Next output time set to t=%e.", next_snapshot_time); + } } } @@ -5820,6 +5871,7 @@ void engine_struct_dump(struct engine *e, FILE *stream) { space_struct_dump(e->s, stream); units_struct_dump(e->internal_units, stream); units_struct_dump(e->snapshotUnits, stream); + cosmology_struct_dump(e->cosmology, stream); #ifdef WITH_MPI /* Save the partition for restoration. */ @@ -5832,6 +5884,7 @@ void engine_struct_dump(struct engine *e, FILE *stream) { gravity_props_struct_dump(e->gravity_properties, stream); potential_struct_dump(e->external_potential, stream); cooling_struct_dump(e->cooling_func, stream); + chemistry_struct_dump(e->chemistry, stream); sourceterms_struct_dump(e->sourceterms, stream); parser_struct_dump(e->parameter_file, stream); } @@ -5871,6 +5924,11 @@ void engine_struct_restore(struct engine *e, FILE *stream) { units_struct_restore(us, stream); e->snapshotUnits = us; + struct cosmology *cosmo = + (struct cosmology *)malloc(sizeof(struct cosmology)); + cosmology_struct_restore(cosmo, stream); + e->cosmology = cosmo; + #ifdef WITH_MPI struct repartition *reparttype = (struct repartition *)malloc(sizeof(struct repartition)); @@ -5904,6 +5962,11 @@ void engine_struct_restore(struct engine *e, FILE *stream) { cooling_struct_restore(cooling_func, stream); e->cooling_func = cooling_func; + struct chemistry_data *chemistry = + (struct chemistry_data *)malloc(sizeof(struct chemistry_data)); + chemistry_struct_restore(chemistry, stream); + e->chemistry = chemistry; + struct sourceterms *sourceterms = (struct sourceterms *)malloc(sizeof(struct sourceterms)); sourceterms_struct_restore(sourceterms, stream); diff --git a/src/engine.h b/src/engine.h index 67ca66c12fc56b55fd25091b24635c837c567f92..0fa8ca93b84760d0d92d9494f6e8e6224e3d1d9a 100644 --- a/src/engine.h +++ b/src/engine.h @@ -126,13 +126,13 @@ struct engine { double dt_min, dt_max; /* Time of the simulation beginning */ - double timeBegin; + double time_begin; /* Time of the simulation end */ - double timeEnd; + double time_end; /* The previous system time. */ - double timeOld; + double time_old; integertime_t ti_old; /* The current system time. */ @@ -142,12 +142,15 @@ struct engine { /* The highest active bin at this time */ timebin_t max_active_bin; + /* The lowest active bin at this time */ + timebin_t min_active_bin; + /* Time step */ - double timeStep; + double time_step; /* Time base */ - double timeBase; - double timeBase_inv; + double time_base; + double time_base_inv; /* Minimal hydro ti_end for the next time-step */ integertime_t ti_hydro_end_min; @@ -268,6 +271,9 @@ struct engine { /* Physical constants definition */ const struct phys_const *physical_constants; + /* The cosmological model */ + struct cosmology *cosmology; + /* Properties of the hydro scheme */ const struct hydro_props *hydro_properties; @@ -328,7 +334,7 @@ void engine_init( struct engine *e, struct space *s, const struct swift_params *params, long long Ngas, long long Ndm, int policy, int verbose, struct repartition *reparttype, const struct unit_system *internal_units, - const struct phys_const *physical_constants, + const struct phys_const *physical_constants, struct cosmology *cosmo, const struct hydro_props *hydro, const struct gravity_props *gravity, const struct external_potential *potential, const struct cooling_function_data *cooling_func, diff --git a/src/gravity/Default/gravity.h b/src/gravity/Default/gravity.h index 94192321440cd6fcb49722a5c69f1f121f24cd1e..bc06b17188f99785404a1162d46384ee26c884ea 100644 --- a/src/gravity/Default/gravity.h +++ b/src/gravity/Default/gravity.h @@ -21,6 +21,7 @@ #define SWIFT_DEFAULT_GRAVITY_H #include <float.h> +#include "cosmology.h" #include "gravity_properties.h" #include "minmax.h" @@ -63,22 +64,37 @@ __attribute__((always_inline)) INLINE static float gravity_get_potential( * We use Gadget-2's type 0 time-step criterion. * * @param gp Pointer to the g-particle data. + * @param a_hydro The accelerations coming from the hydro scheme (can be 0). * @param grav_props Constants used in the gravity scheme. + * @param cosmo The current cosmological model. */ __attribute__((always_inline)) INLINE static float gravity_compute_timestep_self(const struct gpart* const gp, - const struct gravity_props* restrict grav_props) { + const float a_hydro[3], + const struct gravity_props* restrict grav_props, + const struct cosmology* cosmo) { - const float ac2 = gp->a_grav[0] * gp->a_grav[0] + - gp->a_grav[1] * gp->a_grav[1] + - gp->a_grav[2] * gp->a_grav[2]; + /* Get physical acceleration (gravity contribution) */ + float a_phys_x = gp->a_grav[0] * cosmo->a_factor_grav_accel; + float a_phys_y = gp->a_grav[1] * cosmo->a_factor_grav_accel; + float a_phys_z = gp->a_grav[2] * cosmo->a_factor_grav_accel; + + /* Get physical acceleration (hydro contribution) */ + a_phys_x += a_hydro[0] * cosmo->a_factor_hydro_accel; + a_phys_y += a_hydro[1] * cosmo->a_factor_hydro_accel; + a_phys_z += a_hydro[2] * cosmo->a_factor_hydro_accel; + + const float ac2 = + a_phys_x * a_phys_x + a_phys_y * a_phys_y + a_phys_z * a_phys_z; const float ac_inv = (ac2 > 0.f) ? 1.f / sqrtf(ac2) : FLT_MAX; + // MATTHIEU cosmological evolution of the softening? const float epsilon = gravity_get_softening(gp); /* Note that 0.66666667 = 2. (from Gadget) / 3. (Plummer softening) */ - const float dt = sqrtf(0.66666667f * grav_props->eta * epsilon * ac_inv); + const float dt = + sqrtf(0.66666667f * cosmo->a * grav_props->eta * epsilon * ac_inv); return dt; } diff --git a/src/hydro/Default/hydro.h b/src/hydro/Default/hydro.h index 890380b23ac1496854dc5359f9249993c166d2c3..1228aa69abfe812e5b2e73f066bb13be3292aa20 100644 --- a/src/hydro/Default/hydro.h +++ b/src/hydro/Default/hydro.h @@ -21,71 +21,134 @@ #include "adiabatic_index.h" #include "approx_math.h" +#include "cosmology.h" +#include "dimension.h" #include "equation_of_state.h" #include "hydro_space.h" +#include "kernel_hydro.h" #include "minmax.h" #include <float.h> /** - * @brief Returns the internal energy of a particle + * @brief Returns the comoving internal energy of a particle * * @param p The particle of interest - * @param dt Time since the last kick */ -__attribute__((always_inline)) INLINE static float hydro_get_internal_energy( - const struct part *restrict p) { +__attribute__((always_inline)) INLINE static float +hydro_get_comoving_internal_energy(const struct part *restrict p) { return p->u; } /** - * @brief Returns the pressure of a particle + * @brief Returns the physical internal energy of a particle + * + * @param p The particle of interest + * @param cosmo The cosmological model. + */ +__attribute__((always_inline)) INLINE static float +hydro_get_physical_internal_energy(const struct part *restrict p, + const struct cosmology *cosmo) { + + return cosmo->a_factor_internal_energy * p->u; +} + +/** + * @brief Returns the comoving pressure of a particle * * @param p The particle of interest - * @param dt Time since the last kick */ -__attribute__((always_inline)) INLINE static float hydro_get_pressure( +__attribute__((always_inline)) INLINE static float hydro_get_comoving_pressure( const struct part *restrict p) { return gas_pressure_from_internal_energy(p->rho, p->u); } /** - * @brief Returns the entropy of a particle + * @brief Returns the physical pressure of a particle + * + * @param p The particle of interest + * @param cosmo The cosmological model. + */ +__attribute__((always_inline)) INLINE static float hydro_get_physical_pressure( + const struct part *restrict p, const struct cosmology *cosmo) { + + return cosmo->a_factor_pressure * + gas_pressure_from_internal_energy(p->rho, p->u); +} + +/** + * @brief Returns the comoving entropy of a particle * * @param p The particle of interest - * @param dt Time since the last kick */ -__attribute__((always_inline)) INLINE static float hydro_get_entropy( +__attribute__((always_inline)) INLINE static float hydro_get_comoving_entropy( const struct part *restrict p) { return gas_entropy_from_internal_energy(p->rho, p->u); } /** - * @brief Returns the sound speed of a particle + * @brief Returns the physical entropy of a particle * * @param p The particle of interest - * @param dt Time since the last kick + * @param cosmo The cosmological model. */ -__attribute__((always_inline)) INLINE static float hydro_get_soundspeed( - const struct part *restrict p) { +__attribute__((always_inline)) INLINE static float hydro_get_physical_entropy( + const struct part *restrict p, const struct cosmology *cosmo) { + + /* Note: no cosmological conversion required here with our choice of + * coordinates. */ + return gas_entropy_from_internal_energy(p->rho, p->u); +} + +/** + * @brief Returns the comoving sound speed of a particle + * + * @param p The particle of interest + */ +__attribute__((always_inline)) INLINE static float +hydro_get_comoving_soundspeed(const struct part *restrict p) { return p->force.soundspeed; } /** - * @brief Returns the density of a particle + * @brief Returns the physical sound speed of a particle * * @param p The particle of interest + * @param cosmo The cosmological model. */ -__attribute__((always_inline)) INLINE static float hydro_get_density( +__attribute__((always_inline)) INLINE static float +hydro_get_physical_soundspeed(const struct part *restrict p, + const struct cosmology *cosmo) { + + return cosmo->a_factor_sound_speed * p->force.soundspeed; +} + +/** + * @brief Returns the comoving density of a particle + * + * @param p The particle of interest + */ +__attribute__((always_inline)) INLINE static float hydro_get_comoving_density( const struct part *restrict p) { return p->rho; } +/** + * @brief Returns the physical density of a particle + * + * @param p The particle of interest + */ +__attribute__((always_inline)) INLINE static float hydro_get_physical_density( + const struct part *restrict p, const struct cosmology *cosmo) { + + return p->rho * cosmo->a3_inv; +} + /** * @brief Returns the mass of a particle * @@ -102,16 +165,20 @@ __attribute__((always_inline)) INLINE static float hydro_get_mass( * * @param p The particle of interest * @param xp The extended data of the particle. - * @param dt The time since the last kick. + * @param dt_kick_hydro The time (for hydro accelerations) since the last kick. + * @param dt_kick_grav The time (for gravity accelerations) since the last kick. * @param v (return) The velocities at the current time. */ __attribute__((always_inline)) INLINE static void hydro_get_drifted_velocities( - const struct part *restrict p, const struct xpart *xp, float dt, - float v[3]) { - - v[0] = xp->v_full[0] + p->a_hydro[0] * dt; - v[1] = xp->v_full[1] + p->a_hydro[1] * dt; - v[2] = xp->v_full[2] + p->a_hydro[2] * dt; + const struct part *restrict p, const struct xpart *xp, float dt_kick_hydro, + float dt_kick_grav, float v[3]) { + + v[0] = xp->v_full[0] + p->a_hydro[0] * dt_kick_hydro + + xp->a_grav[0] * dt_kick_grav; + v[1] = xp->v_full[1] + p->a_hydro[1] * dt_kick_hydro + + xp->a_grav[1] * dt_kick_grav; + v[2] = xp->v_full[2] + p->a_hydro[2] * dt_kick_hydro + + xp->a_grav[2] * dt_kick_grav; } /** @@ -146,17 +213,19 @@ __attribute__((always_inline)) INLINE static void hydro_set_internal_energy_dt( * * @param p Pointer to the particle data * @param xp Pointer to the extended particle data - * + * @param hydro_properties The constants used in the scheme + * @param cosmo The cosmological model. */ __attribute__((always_inline)) INLINE static float hydro_compute_timestep( const struct part *restrict p, const struct xpart *restrict xp, - const struct hydro_props *restrict hydro_properties) { + const struct hydro_props *restrict hydro_properties, + const struct cosmology *restrict cosmo) { - const float CFL_condition = hydro_properties->CFL_condition; + const float CFL = hydro_properties->CFL_condition; /* CFL condition */ - const float dt_cfl = - 2.f * kernel_gamma * CFL_condition * p->h / p->force.v_sig; + const float dt_cfl = 2.f * kernel_gamma * CFL * cosmo->a * p->h / + (cosmo->a_factor_sound_speed * p->force.v_sig); /* Limit change in u */ const float dt_u_change = @@ -187,6 +256,7 @@ __attribute__((always_inline)) INLINE static void hydro_timestep_extra( */ __attribute__((always_inline)) INLINE static void hydro_init_part( struct part *restrict p, const struct hydro_space *hs) { + p->density.wcount = 0.f; p->density.wcount_dh = 0.f; p->rho = 0.f; @@ -204,9 +274,10 @@ __attribute__((always_inline)) INLINE static void hydro_init_part( * and add the self-contribution term. * * @param p The particle to act upon + * @param cosmo The current cosmological model. */ __attribute__((always_inline)) INLINE static void hydro_end_density( - struct part *restrict p) { + struct part *restrict p, const struct cosmology *cosmo) { /* Some smoothing length multiples. */ const float h = p->h; @@ -226,14 +297,15 @@ __attribute__((always_inline)) INLINE static void hydro_end_density( p->density.wcount_dh *= h_inv * kernel_gamma * kernel_norm; const float irho = 1.f / p->rho; + const float a_inv2 = cosmo->a2_inv; /* Finish calculation of the velocity curl components */ - p->density.rot_v[0] *= h_inv_dim_plus_one * irho; - p->density.rot_v[1] *= h_inv_dim_plus_one * irho; - p->density.rot_v[2] *= h_inv_dim_plus_one * irho; + p->density.rot_v[0] *= h_inv_dim_plus_one * a_inv2 * irho; + p->density.rot_v[1] *= h_inv_dim_plus_one * a_inv2 * irho; + p->density.rot_v[2] *= h_inv_dim_plus_one * a_inv2 * irho; /* Finish calculation of the velocity divergence */ - p->density.div_v *= h_inv_dim_plus_one * irho; + p->density.div_v *= h_inv_dim_plus_one * a_inv2 * irho; } /** @@ -241,9 +313,11 @@ __attribute__((always_inline)) INLINE static void hydro_end_density( * * @param p The particle to act upon * @param xp The extended particle data to act upon + * @param cosmo The current cosmological model. */ __attribute__((always_inline)) INLINE static void hydro_part_has_no_neighbours( - struct part *restrict p, struct xpart *restrict xp) { + struct part *restrict p, struct xpart *restrict xp, + const struct cosmology *cosmo) { /* Some smoothing length multiples. */ const float h = p->h; @@ -268,10 +342,13 @@ __attribute__((always_inline)) INLINE static void hydro_part_has_no_neighbours( * * @param p The particle to act upon * @param xp The extended particle data to act upon - * @param time The current time + * @param cosmo The current cosmological model. */ __attribute__((always_inline)) INLINE static void hydro_prepare_force( - struct part *restrict p, struct xpart *restrict xp) { + struct part *restrict p, struct xpart *restrict xp, + const struct cosmology *cosmo) { + + const float fac_mu = cosmo->a_factor_mu; /* Some smoothing length multiples. */ const float h = p->h; @@ -296,7 +373,8 @@ __attribute__((always_inline)) INLINE static void hydro_prepare_force( p->force.P_over_rho2 = u * hydro_gamma_minus_one / (p->rho * xp->omega); /* Balsara switch */ - p->force.balsara = normDiv_v / (normDiv_v + normRot_v + 0.0001f * fc * h_inv); + p->force.balsara = + normDiv_v / (normDiv_v + normRot_v + 0.0001f * fac_mu * fc * h_inv); /* Viscosity parameter decay time */ /* const float tau = h / (2.f * const_viscosity_length * p->force.soundspeed); @@ -349,6 +427,8 @@ __attribute__((always_inline)) INLINE static void hydro_reset_predicted_values( p->v[0] = xp->v_full[0]; p->v[1] = xp->v_full[1]; p->v[2] = xp->v_full[2]; + + p->u = xp->u_full; } /** @@ -356,19 +436,18 @@ __attribute__((always_inline)) INLINE static void hydro_reset_predicted_values( * * @param p The particle * @param xp The extended data of the particle - * @param dt The drift time-step. - * @param t0 The time at the start of the drift - * @param t1 The time at the end of the drift - * @param timeBase The minimal time-step size + * @param dt_drift The drift time-step for positions. + * @param dt_therm The drift time-step for thermal quantities. */ __attribute__((always_inline)) INLINE static void hydro_predict_extra( - struct part *restrict p, struct xpart *restrict xp, float dt) { + struct part *restrict p, struct xpart *restrict xp, float dt_drift, + float dt_therm) { float u, w; const float h_inv = 1.f / p->h; /* Predict smoothing length */ - const float w1 = p->force.h_dt * h_inv * dt; + const float w1 = p->force.h_dt * h_inv * dt_drift; if (fabsf(w1) < 0.2f) p->h *= approx_expf(w1); /* 4th order expansion of exp(w) */ else @@ -382,7 +461,7 @@ __attribute__((always_inline)) INLINE static void hydro_predict_extra( p->rho *= expf(w2); /* Predict internal energy */ - w = p->force.u_dt / p->u * dt; + w = p->force.u_dt / p->u * dt_therm; if (fabsf(w) < 0.2f) u = p->u *= approx_expf(w); else @@ -398,9 +477,10 @@ __attribute__((always_inline)) INLINE static void hydro_predict_extra( * Multiplies the forces and accelerationsby the appropiate constants * * @param p The particle to act upon + * @param cosmo The current cosmological model. */ __attribute__((always_inline)) INLINE static void hydro_end_force( - struct part *restrict p) { + struct part *restrict p, const struct cosmology *cosmo) { p->force.h_dt *= p->h * hydro_dimension_inv; } @@ -409,11 +489,10 @@ __attribute__((always_inline)) INLINE static void hydro_end_force( * * @param p The particle to act upon * @param xp The particle extended data to act upon - * @param dt The time-step for this kick - * @param half_dt The half time-step for this kick + * @param dt_therm The time-step for this kick (for thermodynamic quantities) */ __attribute__((always_inline)) INLINE static void hydro_kick_extra( - struct part *restrict p, struct xpart *restrict xp, float dt) {} + struct part *restrict p, struct xpart *restrict xp, float dt_therm) {} /** * @brief Converts hydro quantity of a particle at the start of a run @@ -441,6 +520,9 @@ __attribute__((always_inline)) INLINE static void hydro_first_init_part( xp->v_full[0] = p->v[0]; xp->v_full[1] = p->v[1]; xp->v_full[2] = p->v[2]; + xp->a_grav[0] = 0.f; + xp->a_grav[1] = 0.f; + xp->a_grav[2] = 0.f; xp->u_full = p->u; hydro_reset_acceleration(p); diff --git a/src/hydro/Default/hydro_iact.h b/src/hydro/Default/hydro_iact.h index 89b90be22b831066c8b9211bfe50208b4c4af67e..658b4aba83085610a49bb9d2579d4f20c70d6c5b 100644 --- a/src/hydro/Default/hydro_iact.h +++ b/src/hydro/Default/hydro_iact.h @@ -26,22 +26,32 @@ * @brief SPH interaction functions following the Gadget-2 version of SPH. * * The interactions computed here are the ones presented in the Gadget-2 paper - *and use the same + * and use the same * numerical coefficients as the Gadget-2 code. When used with the Spline-3 - *kernel, the results + * kernel, the results * should be equivalent to the ones obtained with Gadget-2 up to the rounding - *errors and interactions + * errors and interactions * missed by the Gadget-2 tree-code neighbours search. * * The code uses internal energy instead of entropy as a thermodynamical - *variable. + * variable. */ /** - * @brief Density loop + * @brief Density interaction between two particles. + * + * @param r2 Comoving square distance between the two particles. + * @param dx Comoving vector separating both particles (pi - pj). + * @param hi Comoving smoothing-length of particle i. + * @param hj Comoving smoothing-length of particle j. + * @param pi First particle. + * @param pj Second particle. + * @param a Current scale factor. + * @param H Current Hubble parameter. */ __attribute__((always_inline)) INLINE static void runner_iact_density( - float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) { + float r2, const float *dx, float hi, float hj, struct part *restrict pi, + struct part *restrict pj, float a, float H) { float r = sqrtf(r2), ri = 1.0f / r; float xi, xj; @@ -97,10 +107,20 @@ __attribute__((always_inline)) INLINE static void runner_iact_density( } /** - * @brief Density loop (non-symmetric version) + * @brief Density interaction between two particles (non-symmetric). + * + * @param r2 Comoving square distance between the two particles. + * @param dx Comoving vector separating both particles (pi - pj). + * @param hi Comoving smoothing-length of particle i. + * @param hj Comoving smoothing-length of particle j. + * @param pi First particle. + * @param pj Second particle (not updated). + * @param a Current scale factor. + * @param H Current Hubble parameter. */ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_density( - float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) { + float r2, const float *dx, float hi, float hj, struct part *restrict pi, + const struct part *restrict pj, float a, float H) { float r, ri; float xi; @@ -145,10 +165,20 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_density( } /** - * @brief Force loop + * @brief Force interaction between two particles. + * + * @param r2 Comoving square distance between the two particles. + * @param dx Comoving vector separating both particles (pi - pj). + * @param hi Comoving smoothing-length of particle i. + * @param hj Comoving smoothing-length of particle j. + * @param pi First particle. + * @param pj Second particle. + * @param a Current scale factor. + * @param H Current Hubble parameter. */ __attribute__((always_inline)) INLINE static void runner_iact_force( - float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) { + float r2, const float *dx, float hi, float hj, struct part *restrict pi, + struct part *restrict pj, float a, float H) { float r = sqrtf(r2), ri = 1.0f / r; float xi, xj; @@ -160,6 +190,10 @@ __attribute__((always_inline)) INLINE static void runner_iact_force( float f; int k; + /* Cosmological factors entering the EoMs */ + const float fac_mu = pow_three_gamma_minus_five_over_two(a); + const float a2_Hubble = a * a * H; + /* Get some values in local variables. */ mi = pi->mass; mj = pj->mass; @@ -184,12 +218,12 @@ __attribute__((always_inline)) INLINE static void runner_iact_force( /* Compute dv dot r. */ dvdr = (pi->v[0] - pj->v[0]) * dx[0] + (pi->v[1] - pj->v[1]) * dx[1] + - (pi->v[2] - pj->v[2]) * dx[2]; + (pi->v[2] - pj->v[2]) * dx[2] + a2_Hubble * r2; dvdr *= ri; /* Compute the relative velocity. (This is 0 if the particles move away from * each other and negative otherwise) */ - omega_ij = min(dvdr, 0.f); + omega_ij = min(fac_mu * dvdr, 0.f); /* Compute signal velocity */ v_sig = pi->force.soundspeed + pj->force.soundspeed - 2.0f * omega_ij; @@ -240,10 +274,20 @@ __attribute__((always_inline)) INLINE static void runner_iact_force( } /** - * @brief Force loop (non-symmetric version) + * @brief Force interaction between two particles (non-symmetric). + * + * @param r2 Comoving square distance between the two particles. + * @param dx Comoving vector separating both particles (pi - pj). + * @param hi Comoving smoothing-length of particle i. + * @param hj Comoving smoothing-length of particle j. + * @param pi First particle. + * @param pj Second particle (not updated). + * @param a Current scale factor. + * @param H Current Hubble parameter. */ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force( - float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) { + float r2, const float *dx, float hi, float hj, struct part *restrict pi, + const struct part *restrict pj, float a, float H) { float r = sqrtf(r2), ri = 1.0f / r; float xi, xj; @@ -255,6 +299,10 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force( float f; int k; + /* Cosmological factors entering the EoMs */ + const float fac_mu = pow_three_gamma_minus_five_over_two(a); + const float a2_Hubble = a * a * H; + /* Get some values in local variables. */ // mi = pi->mass; mj = pj->mass; @@ -279,12 +327,12 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force( /* Compute dv dot r. */ dvdr = (pi->v[0] - pj->v[0]) * dx[0] + (pi->v[1] - pj->v[1]) * dx[1] + - (pi->v[2] - pj->v[2]) * dx[2]; + (pi->v[2] - pj->v[2]) * dx[2] + a2_Hubble * r2; dvdr *= ri; /* Compute the relative velocity. (This is 0 if the particles move away from * each other and negative otherwise) */ - omega_ij = min(dvdr, 0.f); + omega_ij = min(fac_mu * dvdr, 0.f); /* Compute signal velocity */ v_sig = pi->force.soundspeed + pj->force.soundspeed - 2.0f * omega_ij; diff --git a/src/hydro/Default/hydro_part.h b/src/hydro/Default/hydro_part.h index 6290ee5ba37a567b3819a06b8b824d83071ee4c2..2a18e03cb533ca860f227a31152ef2058e0dd37d 100644 --- a/src/hydro/Default/hydro_part.h +++ b/src/hydro/Default/hydro_part.h @@ -34,6 +34,9 @@ struct xpart { /* Velocity at the last full step. */ float v_full[3]; + /* Gravitational acceleration at the last full step. */ + float a_grav[3]; + /* Additional data used to record cooling information */ struct cooling_xpart_data cooling_data; diff --git a/src/hydro/Gadget2/hydro.h b/src/hydro/Gadget2/hydro.h index f3c33bc7a00bc649d5e6a2d5b75bc04022359f72..185a98b6d207bb851512a686be51414341fe7740 100644 --- a/src/hydro/Gadget2/hydro.h +++ b/src/hydro/Gadget2/hydro.h @@ -33,6 +33,7 @@ #include "adiabatic_index.h" #include "approx_math.h" +#include "cosmology.h" #include "dimension.h" #include "equation_of_state.h" #include "hydro_properties.h" @@ -41,60 +42,123 @@ #include "minmax.h" /** - * @brief Returns the internal energy of a particle + * @brief Returns the comoving internal energy of a particle * * @param p The particle of interest */ -__attribute__((always_inline)) INLINE static float hydro_get_internal_energy( - const struct part *restrict p) { +__attribute__((always_inline)) INLINE static float +hydro_get_comoving_internal_energy(const struct part *restrict p) { return gas_internal_energy_from_entropy(p->rho, p->entropy); } /** - * @brief Returns the pressure of a particle + * @brief Returns the physical internal energy of a particle + * + * @param p The particle of interest. + * @param cosmo The cosmological model. + */ +__attribute__((always_inline)) INLINE static float +hydro_get_physical_internal_energy(const struct part *restrict p, + const struct cosmology *cosmo) { + + return gas_internal_energy_from_entropy(p->rho * cosmo->a3_inv, p->entropy); +} + +/** + * @brief Returns the comoving pressure of a particle * * @param p The particle of interest */ -__attribute__((always_inline)) INLINE static float hydro_get_pressure( +__attribute__((always_inline)) INLINE static float hydro_get_comoving_pressure( const struct part *restrict p) { return gas_pressure_from_entropy(p->rho, p->entropy); } /** - * @brief Returns the entropy of a particle + * @brief Returns the physical pressure of a particle * * @param p The particle of interest */ -__attribute__((always_inline)) INLINE static float hydro_get_entropy( +__attribute__((always_inline)) INLINE static float hydro_get_physical_pressure( + const struct part *restrict p, const struct cosmology *cosmo) { + + return gas_pressure_from_entropy(p->rho * cosmo->a3_inv, p->entropy); +} + +/** + * @brief Returns the comoving entropy of a particle + * + * @param p The particle of interest. + */ +__attribute__((always_inline)) INLINE static float hydro_get_comoving_entropy( const struct part *restrict p) { return p->entropy; } /** - * @brief Returns the sound speed of a particle + * @brief Returns the physical entropy of a particle + * + * @param p The particle of interest. + * @param cosmo The cosmological model. + */ +__attribute__((always_inline)) INLINE static float hydro_get_physical_entropy( + const struct part *restrict p, const struct cosmology *cosmo) { + + /* Note: no cosmological conversion required here with our choice of + * coordinates. */ + return p->entropy; +} + +/** + * @brief Returns the comoving sound speed of a particle * * @param p The particle of interest */ -__attribute__((always_inline)) INLINE static float hydro_get_soundspeed( - const struct part *restrict p) { +__attribute__((always_inline)) INLINE static float +hydro_get_comoving_soundspeed(const struct part *restrict p) { return p->force.soundspeed; } /** - * @brief Returns the density of a particle + * @brief Returns the physical sound speed of a particle * * @param p The particle of interest + * @param cosmo The cosmological model. */ -__attribute__((always_inline)) INLINE static float hydro_get_density( +__attribute__((always_inline)) INLINE static float +hydro_get_physical_soundspeed(const struct part *restrict p, + const struct cosmology *cosmo) { + + return cosmo->a_factor_sound_speed * p->force.soundspeed; +} + +/** + * @brief Returns the comoving density of a particle + * + * @param p The particle of interest + */ +__attribute__((always_inline)) INLINE static float hydro_get_comoving_density( const struct part *restrict p) { return p->rho; } +/** + * @brief Returns the physical density of a particle + * + * @param p The particle of interest. + * @param cosmo The cosmological model. + */ +__attribute__((always_inline)) INLINE static float hydro_get_physical_density( + const struct part *restrict p, const struct cosmology *cosmo) { + + return p->rho * cosmo->a3_inv; +} + /** * @brief Returns the mass of a particle * @@ -111,16 +175,20 @@ __attribute__((always_inline)) INLINE static float hydro_get_mass( * * @param p The particle of interest * @param xp The extended data of the particle. - * @param dt The time since the last kick. + * @param dt_kick_hydro The time (for hydro accelerations) since the last kick. + * @param dt_kick_grav The time (for gravity accelerations) since the last kick. * @param v (return) The velocities at the current time. */ __attribute__((always_inline)) INLINE static void hydro_get_drifted_velocities( - const struct part *restrict p, const struct xpart *xp, float dt, - float v[3]) { - - v[0] = xp->v_full[0] + p->a_hydro[0] * dt; - v[1] = xp->v_full[1] + p->a_hydro[1] * dt; - v[2] = xp->v_full[2] + p->a_hydro[2] * dt; + const struct part *restrict p, const struct xpart *xp, float dt_kick_hydro, + float dt_kick_grav, float v[3]) { + + v[0] = xp->v_full[0] + p->a_hydro[0] * dt_kick_hydro + + xp->a_grav[0] * dt_kick_grav; + v[1] = xp->v_full[1] + p->a_hydro[1] * dt_kick_hydro + + xp->a_grav[1] * dt_kick_grav; + v[2] = xp->v_full[2] + p->a_hydro[2] * dt_kick_hydro + + xp->a_grav[2] * dt_kick_grav; } /** @@ -155,17 +223,19 @@ __attribute__((always_inline)) INLINE static void hydro_set_internal_energy_dt( * * @param p Pointer to the particle data * @param xp Pointer to the extended particle data - * + * @param hydro_properties The constants used in the scheme + * @param cosmo The cosmological model. */ __attribute__((always_inline)) INLINE static float hydro_compute_timestep( const struct part *restrict p, const struct xpart *restrict xp, - const struct hydro_props *restrict hydro_properties) { + const struct hydro_props *restrict hydro_properties, + const struct cosmology *restrict cosmo) { - const float CFL_condition = hydro_properties->CFL_condition; + const float CFL = hydro_properties->CFL_condition; /* CFL condition */ - const float dt_cfl = - 2.f * kernel_gamma * CFL_condition * p->h / p->force.v_sig; + const float dt_cfl = 2.f * kernel_gamma * CFL * cosmo->a * p->h / + (cosmo->a_factor_sound_speed * p->force.v_sig); return dt_cfl; } @@ -214,9 +284,10 @@ __attribute__((always_inline)) INLINE static void hydro_init_part( * and add the self-contribution term. * * @param p The particle to act upon + * @param cosmo The current cosmological model. */ __attribute__((always_inline)) INLINE static void hydro_end_density( - struct part *restrict p) { + struct part *restrict p, const struct cosmology *cosmo) { /* Some smoothing length multiples. */ const float h = p->h; @@ -237,14 +308,15 @@ __attribute__((always_inline)) INLINE static void hydro_end_density( p->density.wcount_dh *= h_inv_dim_plus_one; const float rho_inv = 1.f / p->rho; + const float a_inv2 = cosmo->a2_inv; - /* Finish calculation of the velocity curl components */ - p->density.rot_v[0] *= h_inv_dim_plus_one * rho_inv; - p->density.rot_v[1] *= h_inv_dim_plus_one * rho_inv; - p->density.rot_v[2] *= h_inv_dim_plus_one * rho_inv; + /* Finish calculation of the (physical) velocity curl components */ + p->density.rot_v[0] *= h_inv_dim_plus_one * a_inv2 * rho_inv; + p->density.rot_v[1] *= h_inv_dim_plus_one * a_inv2 * rho_inv; + p->density.rot_v[2] *= h_inv_dim_plus_one * a_inv2 * rho_inv; - /* Finish calculation of the velocity divergence */ - p->density.div_v *= h_inv_dim_plus_one * rho_inv; + /* Finish calculation of the (physical) velocity divergence */ + p->density.div_v *= h_inv_dim_plus_one * a_inv2 * rho_inv; } /** @@ -252,9 +324,11 @@ __attribute__((always_inline)) INLINE static void hydro_end_density( * * @param p The particle to act upon * @param xp The extended particle data to act upon + * @param cosmo The current cosmological model. */ __attribute__((always_inline)) INLINE static void hydro_part_has_no_neighbours( - struct part *restrict p, struct xpart *restrict xp) { + struct part *restrict p, struct xpart *restrict xp, + const struct cosmology *cosmo) { /* Some smoothing length multiples. */ const float h = p->h; @@ -279,13 +353,13 @@ __attribute__((always_inline)) INLINE static void hydro_part_has_no_neighbours( * * @param p The particle to act upon * @param xp The extended particle data to act upon - * @param ti_current The current time (on the timeline) - * @param timeBase The minimal time-step size + * @param cosmo The current cosmological model. */ __attribute__((always_inline)) INLINE static void hydro_prepare_force( - struct part *restrict p, struct xpart *restrict xp) { + struct part *restrict p, struct xpart *restrict xp, + const struct cosmology *cosmo) { - const float fac_mu = 1.f; /* Will change with cosmological integration */ + const float fac_mu = cosmo->a_factor_mu; /* Inverse of the physical density */ const float rho_inv = 1.f / p->rho; @@ -309,7 +383,7 @@ __attribute__((always_inline)) INLINE static void hydro_prepare_force( /* Compute the Balsara switch */ const float balsara = - abs_div_v / (abs_div_v + curl_v + 0.0001f * soundspeed / fac_mu / p->h); + abs_div_v / (abs_div_v + curl_v + 0.0001f * fac_mu * soundspeed / p->h); /* Compute the "grad h" term */ const float omega_inv = @@ -375,18 +449,17 @@ __attribute__((always_inline)) INLINE static void hydro_reset_predicted_values( * * @param p The particle * @param xp The extended data of the particle - * @param dt The drift time-step. - * @param t0 The time at the start of the drift - * @param t1 The time at the end of the drift - * @param timeBase The minimal time-step size + * @param dt_drift The drift time-step for positions. + * @param dt_therm The drift time-step for thermal quantities. */ __attribute__((always_inline)) INLINE static void hydro_predict_extra( - struct part *restrict p, const struct xpart *restrict xp, float dt) { + struct part *restrict p, const struct xpart *restrict xp, float dt_drift, + float dt_therm) { const float h_inv = 1.f / p->h; /* Predict smoothing length */ - const float w1 = p->force.h_dt * h_inv * dt; + const float w1 = p->force.h_dt * h_inv * dt_drift; if (fabsf(w1) < 0.2f) p->h *= approx_expf(w1); /* 4th order expansion of exp(w) */ else @@ -400,7 +473,7 @@ __attribute__((always_inline)) INLINE static void hydro_predict_extra( p->rho *= expf(w2); /* Predict the entropy */ - p->entropy += p->entropy_dt * dt; + p->entropy += p->entropy_dt * dt_therm; /* Re-compute the pressure */ const float pressure = gas_pressure_from_entropy(p->rho, p->entropy); @@ -423,14 +496,15 @@ __attribute__((always_inline)) INLINE static void hydro_predict_extra( * Multiplies the forces and accelerationsby the appropiate constants * * @param p The particle to act upon + * @param cosmo The current cosmological model. */ __attribute__((always_inline)) INLINE static void hydro_end_force( - struct part *restrict p) { + struct part *restrict p, const struct cosmology *cosmo) { p->force.h_dt *= p->h * hydro_dimension_inv; - p->entropy_dt = - 0.5f * gas_entropy_from_internal_energy(p->rho, p->entropy_dt); + p->entropy_dt = 0.5f * cosmo->a2_inv * + gas_entropy_from_internal_energy(p->rho, p->entropy_dt); } /** @@ -438,19 +512,19 @@ __attribute__((always_inline)) INLINE static void hydro_end_force( * * @param p The particle to act upon * @param xp The particle extended data to act upon - * @param dt The time-step for this kick + * @param dt_therm The time-step for this kick (for thermodynamic quantities) */ __attribute__((always_inline)) INLINE static void hydro_kick_extra( - struct part *restrict p, struct xpart *restrict xp, float dt) { + struct part *restrict p, struct xpart *restrict xp, float dt_therm) { /* Do not decrease the entropy by more than a factor of 2 */ - if (dt > 0. && p->entropy_dt * dt < -0.5f * xp->entropy_full) { + if (dt_therm > 0. && p->entropy_dt * dt_therm < -0.5f * xp->entropy_full) { /* message("Warning! Limiting entropy_dt. Possible cooling error.\n * entropy_full = %g \n entropy_dt * dt =%g \n", */ /* xp->entropy_full,p->entropy_dt * dt); */ - p->entropy_dt = -0.5f * xp->entropy_full / dt; + p->entropy_dt = -0.5f * xp->entropy_full / dt_therm; } - xp->entropy_full += p->entropy_dt * dt; + xp->entropy_full += p->entropy_dt * dt_therm; /* Compute the pressure */ const float pressure = gas_pressure_from_entropy(p->rho, xp->entropy_full); @@ -510,6 +584,9 @@ __attribute__((always_inline)) INLINE static void hydro_first_init_part( xp->v_full[0] = p->v[0]; xp->v_full[1] = p->v[1]; xp->v_full[2] = p->v[2]; + xp->a_grav[0] = 0.f; + xp->a_grav[1] = 0.f; + xp->a_grav[2] = 0.f; xp->entropy_full = p->entropy; hydro_reset_acceleration(p); diff --git a/src/hydro/Gadget2/hydro_debug.h b/src/hydro/Gadget2/hydro_debug.h index 6500d1126bd5b5a65d3e511c13afb8364574e0ba..d0642a03a4c4eecb2da80fdae473948e460c5e31 100644 --- a/src/hydro/Gadget2/hydro_debug.h +++ b/src/hydro/Gadget2/hydro_debug.h @@ -31,7 +31,7 @@ __attribute__((always_inline)) INLINE static void hydro_debug_particle( p->x[0], p->x[1], p->x[2], p->v[0], p->v[1], p->v[2], xp->v_full[0], xp->v_full[1], xp->v_full[2], p->a_hydro[0], p->a_hydro[1], p->a_hydro[2], p->h, p->density.wcount, p->density.wcount_dh, p->mass, p->density.rho_dh, - p->rho, hydro_get_pressure(p), p->force.P_over_rho2, p->entropy, + p->rho, hydro_get_comoving_pressure(p), p->force.P_over_rho2, p->entropy, p->entropy_dt, p->force.soundspeed, p->density.div_v, p->density.rot_v[0], p->density.rot_v[1], p->density.rot_v[2], p->force.balsara, p->force.v_sig, p->force.h_dt, p->time_bin); diff --git a/src/hydro/Gadget2/hydro_iact.h b/src/hydro/Gadget2/hydro_iact.h index d30fd7b80318465cb654d769accd0e185336a878..90484c9cee1b384b0540f56e3c845cc4120cdfe0 100644 --- a/src/hydro/Gadget2/hydro_iact.h +++ b/src/hydro/Gadget2/hydro_iact.h @@ -36,10 +36,20 @@ #include "minmax.h" /** - * @brief Density loop + * @brief Density interaction between two particles. + * + * @param r2 Comoving square distance between the two particles. + * @param dx Comoving vector separating both particles (pi - pj). + * @param hi Comoving smoothing-length of particle i. + * @param hj Comoving smoothing-length of particle j. + * @param pi First particle. + * @param pj Second particle. + * @param a Current scale factor. + * @param H Current Hubble parameter. */ __attribute__((always_inline)) INLINE static void runner_iact_density( - float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) { + float r2, const float *dx, float hi, float hj, struct part *restrict pi, + struct part *restrict pj, float a, float H) { float wi, wi_dx; float wj, wj_dx; @@ -117,10 +127,20 @@ __attribute__((always_inline)) INLINE static void runner_iact_density( } /** - * @brief Density loop (non-symmetric version) + * @brief Density interaction between two particles (non-symmetric). + * + * @param r2 Comoving square distance between the two particles. + * @param dx Comoving vector separating both particles (pi - pj). + * @param hi Comoving smoothing-length of particle i. + * @param hj Comoving smoothing-length of particle j. + * @param pi First particle. + * @param pj Second particle (not updated). + * @param a Current scale factor. + * @param H Current Hubble parameter. */ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_density( - float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) { + float r2, const float *dx, float hi, float hj, struct part *restrict pi, + const struct part *restrict pj, float a, float H) { float wi, wi_dx; float dv[3], curlvr[3]; @@ -399,14 +419,26 @@ runner_iact_nonsym_2_vec_density(float *R2, float *Dx, float *Dy, float *Dz, #endif /** - * @brief Force loop + * @brief Force interaction between two particles. + * + * @param r2 Comoving square distance between the two particles. + * @param dx Comoving vector separating both particles (pi - pj). + * @param hi Comoving smoothing-length of particle i. + * @param hj Comoving smoothing-length of particle j. + * @param pi First particle. + * @param pj Second particle. + * @param a Current scale factor. + * @param H Current Hubble parameter. */ __attribute__((always_inline)) INLINE static void runner_iact_force( - float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) { + float r2, const float *dx, float hi, float hj, struct part *restrict pi, + struct part *restrict pj, float a, float H) { float wi, wj, wi_dx, wj_dx; - const float fac_mu = 1.f; /* Will change with cosmological integration */ + /* Cosmological factors entering the EoMs */ + const float fac_mu = pow_three_gamma_minus_five_over_two(a); + const float a2_Hubble = a * a * H; const float r = sqrtf(r2); const float r_inv = 1.0f / r; @@ -446,7 +478,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_force( /* Compute dv dot r. */ const float dvdr = (pi->v[0] - pj->v[0]) * dx[0] + (pi->v[1] - pj->v[1]) * dx[1] + - (pi->v[2] - pj->v[2]) * dx[2]; + (pi->v[2] - pj->v[2]) * dx[2] + a2_Hubble * r2; /* Balsara term */ const float balsara_i = pi->force.balsara; @@ -486,8 +518,8 @@ __attribute__((always_inline)) INLINE static void runner_iact_force( pj->force.h_dt -= mi * dvdr * r_inv / rhoi * wj_dr; /* Update the signal velocity. */ - pi->force.v_sig = (pi->force.v_sig > v_sig) ? pi->force.v_sig : v_sig; - pj->force.v_sig = (pj->force.v_sig > v_sig) ? pj->force.v_sig : v_sig; + pi->force.v_sig = max(pi->force.v_sig, v_sig); + pj->force.v_sig = max(pj->force.v_sig, v_sig); /* Change in entropy */ pi->entropy_dt += mj * visc_term * dvdr; @@ -506,14 +538,26 @@ __attribute__((always_inline)) INLINE static void runner_iact_force( } /** - * @brief Force loop (non-symmetric version) + * @brief Force interaction between two particles (non-symmetric). + * + * @param r2 Comoving square distance between the two particles. + * @param dx Comoving vector separating both particles (pi - pj). + * @param hi Comoving smoothing-length of particle i. + * @param hj Comoving smoothing-length of particle j. + * @param pi First particle. + * @param pj Second particle (not updated). + * @param a Current scale factor. + * @param H Current Hubble parameter. */ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force( - float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) { + float r2, const float *dx, float hi, float hj, struct part *restrict pi, + const struct part *restrict pj, float a, float H) { float wi, wj, wi_dx, wj_dx; - const float fac_mu = 1.f; /* Will change with cosmological integration */ + /* Cosmological factors entering the EoMs */ + const float fac_mu = pow_three_gamma_minus_five_over_two(a); + const float a2_Hubble = a * a * H; const float r = sqrtf(r2); const float r_inv = 1.0f / r; @@ -553,7 +597,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force( /* Compute dv dot r. */ const float dvdr = (pi->v[0] - pj->v[0]) * dx[0] + (pi->v[1] - pj->v[1]) * dx[1] + - (pi->v[2] - pj->v[2]) * dx[2]; + (pi->v[2] - pj->v[2]) * dx[2] + a2_Hubble * r2; /* Balsara term */ const float balsara_i = pi->force.balsara; @@ -588,7 +632,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force( pi->force.h_dt -= mj * dvdr * r_inv / rhoj * wi_dr; /* Update the signal velocity. */ - pi->force.v_sig = (pi->force.v_sig > v_sig) ? pi->force.v_sig : v_sig; + pi->force.v_sig = max(pi->force.v_sig, v_sig); /* Change in entropy */ pi->entropy_dt += mj * visc_term * dvdr; diff --git a/src/hydro/Gadget2/hydro_io.h b/src/hydro/Gadget2/hydro_io.h index 917e260fbd16526c7f2f6983b674df597555a41f..1d1f5ed453f249191b6853a3a699de847ed501f2 100644 --- a/src/hydro/Gadget2/hydro_io.h +++ b/src/hydro/Gadget2/hydro_io.h @@ -57,12 +57,12 @@ void hydro_read_particles(struct part* parts, struct io_props* list, void convert_u(const struct engine* e, const struct part* p, float* ret) { - ret[0] = hydro_get_internal_energy(p); + ret[0] = hydro_get_comoving_internal_energy(p); } void convert_P(const struct engine* e, const struct part* p, float* ret) { - ret[0] = hydro_get_pressure(p); + ret[0] = hydro_get_comoving_pressure(p); } void convert_part_pos(const struct engine* e, const struct part* p, diff --git a/src/hydro/Gadget2/hydro_part.h b/src/hydro/Gadget2/hydro_part.h index 55745b52f4459905b02adf4824c489510ee93f97..90f73571701b37b3377601655330d8d25f862a05 100644 --- a/src/hydro/Gadget2/hydro_part.h +++ b/src/hydro/Gadget2/hydro_part.h @@ -46,6 +46,9 @@ struct xpart { /* Velocity at the last full step. */ float v_full[3]; + /* Gravitational acceleration at the last full step. */ + float a_grav[3]; + /* Entropy at the last full step. */ float entropy_full; diff --git a/src/hydro/Gizmo/hydro.h b/src/hydro/Gizmo/hydro.h index b8c2c5e405e116acf5632b42b3b5fb60ae3e0d4e..0faa4bf39ae533ee9942898bdc08118ee4078868 100644 --- a/src/hydro/Gizmo/hydro.h +++ b/src/hydro/Gizmo/hydro.h @@ -22,6 +22,7 @@ #include "adiabatic_index.h" #include "approx_math.h" +#include "cosmology.h" #include "equation_of_state.h" #include "hydro_gradients.h" #include "hydro_properties.h" @@ -41,10 +42,12 @@ * @param p Pointer to the particle data. * @param xp Pointer to the extended particle data. * @param hydro_properties Pointer to the hydro parameters. + * @param cosmo The cosmological model. */ __attribute__((always_inline)) INLINE static float hydro_compute_timestep( const struct part* restrict p, const struct xpart* restrict xp, - const struct hydro_props* restrict hydro_properties) { + const struct hydro_props* restrict hydro_properties, + const struct cosmology* restrict cosmo) { const float CFL_condition = hydro_properties->CFL_condition; @@ -63,8 +66,11 @@ __attribute__((always_inline)) INLINE static float hydro_compute_timestep( sqrtf(vrel[0] * vrel[0] + vrel[1] * vrel[1] + vrel[2] * vrel[2]) + sqrtf(hydro_gamma * p->primitives.P / p->primitives.rho); vmax = max(vmax, p->timestepvars.vmax); - const float psize = powf(p->geometry.volume / hydro_dimension_unit_sphere, - hydro_dimension_inv); + + // MATTHIEU: Bert is this correct? Do we need more cosmology terms here? + const float psize = + cosmo->a * powf(p->geometry.volume / hydro_dimension_unit_sphere, + hydro_dimension_inv); float dt = FLT_MAX; if (vmax > 0.) { dt = psize / vmax; @@ -223,9 +229,10 @@ __attribute__((always_inline)) INLINE static void hydro_init_part( * passive particles. * * @param p The particle to act upon. + * @param cosmo The cosmological model. */ __attribute__((always_inline)) INLINE static void hydro_end_density( - struct part* restrict p) { + struct part* restrict p, const struct cosmology* cosmo) { /* Some smoothing length multiples. */ const float h = p->h; @@ -318,6 +325,7 @@ __attribute__((always_inline)) INLINE static void hydro_end_density( } #endif + // MATTHIEU: Bert is this correct? Do we need cosmology terms here? float momentum[3]; momentum[0] = p->conserved.momentum[0]; momentum[1] = p->conserved.momentum[1]; @@ -377,9 +385,11 @@ __attribute__((always_inline)) INLINE static void hydro_end_density( * * @param p The particle to act upon * @param xp The extended particle data to act upon + * @param cosmo The cosmological model. */ __attribute__((always_inline)) INLINE static void hydro_part_has_no_neighbours( - struct part* restrict p, struct xpart* restrict xp) { + struct part* restrict p, struct xpart* restrict xp, + const struct cosmology* cosmo) { /* Some smoothing length multiples. */ const float h = p->h; @@ -420,13 +430,17 @@ __attribute__((always_inline)) INLINE static void hydro_part_has_no_neighbours( * * @param p The particle to act upon. * @param xp The extended particle data to act upon. + * @param cosmo The cosmological model. */ __attribute__((always_inline)) INLINE static void hydro_prepare_force( - struct part* restrict p, struct xpart* restrict xp) { + struct part* restrict p, struct xpart* restrict xp, + const struct cosmology* cosmo) { /* Initialize time step criterion variables */ p->timestepvars.vmax = 0.; + // MATTHIEU: Bert is this correct? Do we need cosmology terms here? + /* Set the actual velocity of the particle */ hydro_velocities_prepare_force(p, xp); } @@ -510,13 +524,11 @@ __attribute__((always_inline)) INLINE static void hydro_convert_quantities( * * @param p Particle to act upon. * @param xp The extended particle data to act upon. - * @param dt The drift time-step. - * @param t0 Integer start time of the drift interval. - * @param t1 Integer end time of the drift interval. - * @param timeBase Conversion factor between integer and physical time. + * @param dt_drift The drift time-step for positions. + * @param dt_therm The drift time-step for thermal quantities. */ __attribute__((always_inline)) INLINE static void hydro_predict_extra( - struct part* p, struct xpart* xp, float dt) { + struct part* p, struct xpart* xp, float dt_drift, float dt_therm) { #ifdef GIZMO_LLOYD_ITERATION return; @@ -525,7 +537,7 @@ __attribute__((always_inline)) INLINE static void hydro_predict_extra( const float h_inv = 1.0f / p->h; /* Predict smoothing length */ - const float w1 = p->force.h_dt * h_inv * dt; + const float w1 = p->force.h_dt * h_inv * dt_drift; float h_corr; if (fabsf(w1) < 0.2f) h_corr = approx_expf(w1); /* 4th order expansion of exp(w) */ @@ -540,19 +552,20 @@ __attribute__((always_inline)) INLINE static void hydro_predict_extra( /* drift the primitive variables based on the old fluxes */ if (p->geometry.volume > 0.) { - p->primitives.rho += p->conserved.flux.mass * dt / p->geometry.volume; + p->primitives.rho += p->conserved.flux.mass * dt_drift / p->geometry.volume; } if (p->conserved.mass > 0.) { p->primitives.v[0] += - p->conserved.flux.momentum[0] * dt / p->conserved.mass; + p->conserved.flux.momentum[0] * dt_drift / p->conserved.mass; p->primitives.v[1] += - p->conserved.flux.momentum[1] * dt / p->conserved.mass; + p->conserved.flux.momentum[1] * dt_drift / p->conserved.mass; p->primitives.v[2] += - p->conserved.flux.momentum[2] * dt / p->conserved.mass; + p->conserved.flux.momentum[2] * dt_drift / p->conserved.mass; +// MATTHIEU: Bert is this correct? #if !defined(EOS_ISOTHERMAL_GAS) - const float u = p->conserved.energy + p->conserved.flux.energy * dt; + const float u = p->conserved.energy + p->conserved.flux.energy * dt_therm; p->primitives.P = hydro_gamma_minus_one * u * p->primitives.rho / p->conserved.mass; #endif @@ -576,12 +589,14 @@ __attribute__((always_inline)) INLINE static void hydro_predict_extra( * should only happen at the start of the simulation. * * @param p Particle to act upon. + * @param cosmo The cosmological model. */ __attribute__((always_inline)) INLINE static void hydro_end_force( - struct part* p) { + struct part* p, const struct cosmology* cosmo) { /* set the variables that are used to drift the primitive variables */ + // MATTHIEU: Bert is this correct? Do we need cosmology terms here? hydro_velocities_end_force(p); } @@ -679,12 +694,12 @@ __attribute__((always_inline)) INLINE static void hydro_kick_extra( } /** - * @brief Returns the internal energy of a particle + * @brief Returns the comoving internal energy of a particle * * @param p The particle of interest. */ -__attribute__((always_inline)) INLINE static float hydro_get_internal_energy( - const struct part* restrict p) { +__attribute__((always_inline)) INLINE static float +hydro_get_comoving_internal_energy(const struct part* restrict p) { if (p->primitives.rho > 0.) return gas_internal_energy_from_pressure(p->primitives.rho, @@ -694,11 +709,25 @@ __attribute__((always_inline)) INLINE static float hydro_get_internal_energy( } /** - * @brief Returns the entropy of a particle + * @brief Returns the physical internal energy of a particle * * @param p The particle of interest. + * @param cosmo The cosmological model. */ -__attribute__((always_inline)) INLINE static float hydro_get_entropy( +__attribute__((always_inline)) INLINE static float +hydro_get_physical_internal_energy(const struct part* restrict p, + const struct cosmology* cosmo) { + + return cosmo->a_factor_internal_energy * + hydro_get_comoving_internal_energy(p); +} + +/** + * @brief Returns the comoving entropy of a particle + * + * @param p The particle of interest. + */ +__attribute__((always_inline)) INLINE static float hydro_get_comoving_entropy( const struct part* restrict p) { if (p->primitives.rho > 0.) { @@ -708,13 +737,27 @@ __attribute__((always_inline)) INLINE static float hydro_get_entropy( } } +/** + * @brief Returns the physical internal energy of a particle + * + * @param p The particle of interest. + * @param cosmo The cosmological model. + */ +__attribute__((always_inline)) INLINE static float hydro_get_physical_entropy( + const struct part* restrict p, const struct cosmology* cosmo) { + + /* Note: no cosmological conversion required here with our choice of + * coordinates. */ + return hydro_get_comoving_entropy(p); +} + /** * @brief Returns the sound speed of a particle * * @param p The particle of interest. */ -__attribute__((always_inline)) INLINE static float hydro_get_soundspeed( - const struct part* restrict p) { +__attribute__((always_inline)) INLINE static float +hydro_get_comoving_soundspeed(const struct part* restrict p) { if (p->primitives.rho > 0.) return gas_soundspeed_from_pressure(p->primitives.rho, p->primitives.P); @@ -723,16 +766,41 @@ __attribute__((always_inline)) INLINE static float hydro_get_soundspeed( } /** - * @brief Returns the pressure of a particle + * @brief Returns the physical sound speed of a particle + * + * @param p The particle of interest. + * @param cosmo The cosmological model. + */ +__attribute__((always_inline)) INLINE static float +hydro_get_physical_soundspeed(const struct part* restrict p, + const struct cosmology* cosmo) { + + return cosmo->a_factor_sound_speed * hydro_get_comoving_soundspeed(p); +} + +/** + * @brief Returns the comoving pressure of a particle * * @param p The particle of interest */ -__attribute__((always_inline)) INLINE static float hydro_get_pressure( +__attribute__((always_inline)) INLINE static float hydro_get_comoving_pressure( const struct part* restrict p) { return p->primitives.P; } +/** + * @brief Returns the comoving pressure of a particle + * + * @param p The particle of interest. + * @param cosmo The cosmological model. + */ +__attribute__((always_inline)) INLINE static float hydro_get_physical_pressure( + const struct part* restrict p, const struct cosmology* cosmo) { + + return cosmo->a_factor_pressure * p->primitives.P; +} + /** * @brief Returns the mass of a particle * @@ -749,38 +817,56 @@ __attribute__((always_inline)) INLINE static float hydro_get_mass( * * @param p The particle of interest * @param xp The extended data of the particle. - * @param dt The time since the last kick. + * @param dt_kick_hydro The time (for hydro accelerations) since the last kick. + * @param dt_kick_grav The time (for gravity accelerations) since the last kick. * @param v (return) The velocities at the current time. */ __attribute__((always_inline)) INLINE static void hydro_get_drifted_velocities( - const struct part* restrict p, const struct xpart* xp, float dt, - float v[3]) { + const struct part* restrict p, const struct xpart* xp, float dt_kick_hydro, + float dt_kick_grav, float v[3]) { if (p->conserved.mass > 0.) { v[0] = p->primitives.v[0] + - p->conserved.flux.momentum[0] * dt / p->conserved.mass; + p->conserved.flux.momentum[0] * dt_kick_hydro / p->conserved.mass; v[1] = p->primitives.v[1] + - p->conserved.flux.momentum[1] * dt / p->conserved.mass; + p->conserved.flux.momentum[1] * dt_kick_hydro / p->conserved.mass; v[2] = p->primitives.v[2] + - p->conserved.flux.momentum[2] * dt / p->conserved.mass; + p->conserved.flux.momentum[2] * dt_kick_hydro / p->conserved.mass; } else { v[0] = p->primitives.v[0]; v[1] = p->primitives.v[1]; v[2] = p->primitives.v[2]; } + + // MATTHIEU: Bert is this correct? + v[0] += xp->a_grav[0] * dt_kick_grav; + v[1] += xp->a_grav[1] * dt_kick_grav; + v[2] += xp->a_grav[2] * dt_kick_grav; } /** - * @brief Returns the density of a particle + * @brief Returns the comoving density of a particle * * @param p The particle of interest */ -__attribute__((always_inline)) INLINE static float hydro_get_density( +__attribute__((always_inline)) INLINE static float hydro_get_comoving_density( const struct part* restrict p) { return p->primitives.rho; } +/** + * @brief Returns the physical density of a particle + * + * @param p The particle of interest + * @param cosmo The cosmological model. + */ +__attribute__((always_inline)) INLINE static float hydro_get_physical_density( + const struct part* restrict p, const struct cosmology* cosmo) { + + return cosmo->a3_inv * p->primitives.rho; +} + /** * @brief Modifies the thermal state of a particle to the imposed internal * energy diff --git a/src/hydro/Gizmo/hydro_gradients.h b/src/hydro/Gizmo/hydro_gradients.h index 46cafcc31ef80cef468a915fdfdaf9b1625807ab..cd53c1dfce670abe58e2aa108f28b1146b3f1013 100644 --- a/src/hydro/Gizmo/hydro_gradients.h +++ b/src/hydro/Gizmo/hydro_gradients.h @@ -45,7 +45,7 @@ * @param p Particle. */ __attribute__((always_inline)) INLINE static void hydro_gradients_init( - struct part* p) {} + struct part *p) {} /** * @brief Gradient calculations done during the neighbour loop @@ -58,8 +58,8 @@ __attribute__((always_inline)) INLINE static void hydro_gradients_init( * @param pj Particle j. */ __attribute__((always_inline)) INLINE static void hydro_gradients_collect( - float r2, float* dx, float hi, float hj, struct part* pi, struct part* pj) { -} + float r2, const float *dx, float hi, float hj, struct part *restrict pi, + struct part *restrict pj) {} /** * @brief Gradient calculations done during the neighbour loop: non-symmetric @@ -73,8 +73,9 @@ __attribute__((always_inline)) INLINE static void hydro_gradients_collect( * @param pj Particle j. */ __attribute__((always_inline)) INLINE static void -hydro_gradients_nonsym_collect(float r2, float* dx, float hi, float hj, - struct part* pi, struct part* pj) {} +hydro_gradients_nonsym_collect(float r2, const float *dx, float hi, float hj, + struct part *restrict pi, + struct part *restrict pj) {} /** * @brief Finalize the gradient variables after all data have been collected @@ -82,7 +83,7 @@ hydro_gradients_nonsym_collect(float r2, float* dx, float hi, float hj, * @param p Particle. */ __attribute__((always_inline)) INLINE static void hydro_gradients_finalize( - struct part* p) {} + struct part *p) {} #endif @@ -91,8 +92,8 @@ __attribute__((always_inline)) INLINE static void hydro_gradients_finalize( * gradients_none does nothing, since all gradients are zero -- are they?). */ __attribute__((always_inline)) INLINE static void hydro_gradients_predict( - struct part* pi, struct part* pj, float hi, float hj, float* dx, float r, - float* xij_i, float* Wi, float* Wj) { + struct part* restrict pi, struct part* restrict pj, float hi, float hj, + const float* dx, float r, float* xij_i, float* Wi, float* Wj) { float dWi[5], dWj[5]; float xij_j[3]; diff --git a/src/hydro/Gizmo/hydro_gradients_gizmo.h b/src/hydro/Gizmo/hydro_gradients_gizmo.h index 034f03c619a2815912a163f5ba7487cf0761dbbe..0140279745c8a2520479175ecf6e5e24d3fba1d6 100644 --- a/src/hydro/Gizmo/hydro_gradients_gizmo.h +++ b/src/hydro/Gizmo/hydro_gradients_gizmo.h @@ -62,7 +62,8 @@ __attribute__((always_inline)) INLINE static void hydro_gradients_init( * @param pj Particle j. */ __attribute__((always_inline)) INLINE static void hydro_gradients_collect( - float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) { + float r2, const float *dx, float hi, float hj, struct part *restrict pi, + struct part *restrict pj) { float r = sqrtf(r2); float xi, xj; @@ -299,8 +300,9 @@ __attribute__((always_inline)) INLINE static void hydro_gradients_collect( * @param pj Particle j. */ __attribute__((always_inline)) INLINE static void -hydro_gradients_nonsym_collect(float r2, float *dx, float hi, float hj, - struct part *pi, struct part *pj) { +hydro_gradients_nonsym_collect(float r2, const float *dx, float hi, float hj, + struct part *restrict pi, + struct part *restrict pj) { float r = sqrtf(r2); float xi; diff --git a/src/hydro/Gizmo/hydro_gradients_sph.h b/src/hydro/Gizmo/hydro_gradients_sph.h index 56a5a88cc184d0260036c8557aacf7a3f198213f..b3e3eae5b7ca11b305085058960904a4a3877845 100644 --- a/src/hydro/Gizmo/hydro_gradients_sph.h +++ b/src/hydro/Gizmo/hydro_gradients_sph.h @@ -61,7 +61,8 @@ __attribute__((always_inline)) INLINE static void hydro_gradients_init( * @param pj Particle j. */ __attribute__((always_inline)) INLINE static void hydro_gradients_collect( - float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) { + float r2, const float *dx, float hi, float hj, struct part *restrict pi, + struct part *restrict pj) { float wi, wi_dx, xi, hi_inv; float wj, wj_dx, xj, hj_inv; @@ -163,8 +164,9 @@ __attribute__((always_inline)) INLINE static void hydro_gradients_collect( * @param pj Particle j. */ __attribute__((always_inline)) INLINE static void -hydro_gradients_nonsym_collect(float r2, float *dx, float hi, float hj, - struct part *pi, struct part *pj) { +hydro_gradients_nonsym_collect(float r2, const float *dx, float hi, float hj, + struct part *restrict pi, + struct part *restrict pj) { float wi, wi_dx, xi, hi_inv; float r = sqrtf(r2); diff --git a/src/hydro/Gizmo/hydro_iact.h b/src/hydro/Gizmo/hydro_iact.h index a42c3d6a77c5d25e32c5f34cc581d8cbec1ffba9..08c2480f4722d8704c250e5089786e93a5116da4 100644 --- a/src/hydro/Gizmo/hydro_iact.h +++ b/src/hydro/Gizmo/hydro_iact.h @@ -37,15 +37,19 @@ * order accurate gradient calculations and for the calculation of the interface * surface areas. * - * @param r2 Squared distance between particle i and particle j. - * @param dx Distance vector between the particles (dx = pi->x - pj->x). - * @param hi Smoothing length of particle i. - * @param hj Smoothing length of particle j. + * @param r2 Comoving squared distance between particle i and particle j. + * @param dx Comoving distance vector between the particles (dx = pi->x - + * pj->x). + * @param hi Comoving smoothing-length of particle i. + * @param hj Comoving smoothing-length of particle j. * @param pi Particle i. * @param pj Particle j. + * @param a Current scale factor. + * @param H Current Hubble parameter. */ __attribute__((always_inline)) INLINE static void runner_iact_density( - float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) { + float r2, const float *dx, float hi, float hj, struct part *restrict pi, + struct part *restrict pj, float a, float H) { float r = sqrtf(r2); float xi, xj; @@ -99,15 +103,19 @@ __attribute__((always_inline)) INLINE static void runner_iact_density( * order accurate gradient calculations and for the calculation of the interface * surface areas. * - * @param r2 Squared distance between particle i and particle j. - * @param dx Distance vector between the particles (dx = pi->x - pj->x). - * @param hi Smoothing length of particle i. - * @param hj Smoothing length of particle j. + * @param r2 Comoving squared distance between particle i and particle j. + * @param dx Comoving distance vector between the particles (dx = pi->x - + * pj->x). + * @param hi Comoving smoothing-length of particle i. + * @param hj Comoving smoothing-length of particle j. * @param pi Particle i. * @param pj Particle j. + * @param a Current scale factor. + * @param H Current Hubble parameter. */ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_density( - float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) { + float r2, const float *dx, float hi, float hj, struct part *restrict pi, + const struct part *restrict pj, float a, float H) { float r; float xi; @@ -141,15 +149,19 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_density( * This method wraps around hydro_gradients_collect, which can be an empty * method, in which case no gradients are used. * - * @param r2 Squared distance between particle i and particle j. - * @param dx Distance vector between the particles (dx = pi->x - pj->x). - * @param hi Smoothing length of particle i. - * @param hj Smoothing length of particle j. + * @param r2 Comoving squared distance between particle i and particle j. + * @param dx Comoving distance vector between the particles (dx = pi->x - + * pj->x). + * @param hi Comoving smoothing-length of particle i. + * @param hj Comoving smoothing-length of particle j. * @param pi Particle i. * @param pj Particle j. + * @param a Current scale factor. + * @param H Current Hubble parameter. */ __attribute__((always_inline)) INLINE static void runner_iact_gradient( - float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) { + float r2, const float *dx, float hi, float hj, struct part *restrict pi, + struct part *restrict pj, float a, float H) { hydro_gradients_collect(r2, dx, hi, hj, pi, pj); } @@ -161,15 +173,19 @@ __attribute__((always_inline)) INLINE static void runner_iact_gradient( * This method wraps around hydro_gradients_nonsym_collect, which can be an * empty method, in which case no gradients are used. * - * @param r2 Squared distance between particle i and particle j. - * @param dx Distance vector between the particles (dx = pi->x - pj->x). - * @param hi Smoothing length of particle i. - * @param hj Smoothing length of particle j. + * @param r2 Comoving squared distance between particle i and particle j. + * @param dx Comoving distance vector between the particles (dx = pi->x - + * pj->x). + * @param hi Comoving smoothing-length of particle i. + * @param hj Comoving smoothing-length of particle j. * @param pi Particle i. * @param pj Particle j. + * @param a Current scale factor. + * @param H Current Hubble parameter. */ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_gradient( - float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) { + float r2, const float *dx, float hi, float hj, struct part *restrict pi, + struct part *restrict pj, float a, float H) { hydro_gradients_nonsym_collect(r2, dx, hi, hj, pi, pj); } @@ -192,16 +208,19 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_gradient( * This method also calculates the maximal velocity used to calculate the time * step. * - * @param r2 Squared distance between particle i and particle j. - * @param dx Distance vector between the particles (dx = pi->x - pj->x). - * @param hi Smoothing length of particle i. - * @param hj Smoothing length of particle j. + * @param r2 Comoving squared distance between particle i and particle j. + * @param dx Comoving distance vector between the particles (dx = pi->x - + * pj->x). + * @param hi Comoving smoothing-length of particle i. + * @param hj Comoving smoothing-length of particle j. * @param pi Particle i. * @param pj Particle j. + * @param a Current scale factor. + * @param H Current Hubble parameter. */ __attribute__((always_inline)) INLINE static void runner_iact_fluxes_common( - float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj, - int mode) { + float r2, const float *dx, float hi, float hj, struct part *restrict pi, + struct part *restrict pj, int mode, float a, float H) { float r = sqrtf(r2); float xi, xj; @@ -457,17 +476,21 @@ __attribute__((always_inline)) INLINE static void runner_iact_fluxes_common( * * This method calls runner_iact_fluxes_common with mode 1. * - * @param r2 Squared distance between particle i and particle j. - * @param dx Distance vector between the particles (dx = pi->x - pj->x). - * @param hi Smoothing length of particle i. - * @param hj Smoothing length of particle j. + * @param r2 Comoving squared distance between particle i and particle j. + * @param dx Comoving distance vector between the particles (dx = pi->x - + * pj->x). + * @param hi Comoving smoothing-length of particle i. + * @param hj Comoving smoothing-length of particle j. * @param pi Particle i. * @param pj Particle j. + * @param a Current scale factor. + * @param H Current Hubble parameter. */ __attribute__((always_inline)) INLINE static void runner_iact_force( - float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) { + float r2, const float *dx, float hi, float hj, struct part *restrict pi, + struct part *restrict pj, float a, float H) { - runner_iact_fluxes_common(r2, dx, hi, hj, pi, pj, 1); + runner_iact_fluxes_common(r2, dx, hi, hj, pi, pj, 1, a, H); } /** @@ -476,17 +499,21 @@ __attribute__((always_inline)) INLINE static void runner_iact_force( * * This method calls runner_iact_fluxes_common with mode 0. * - * @param r2 Squared distance between particle i and particle j. - * @param dx Distance vector between the particles (dx = pi->x - pj->x). - * @param hi Smoothing length of particle i. - * @param hj Smoothing length of particle j. + * @param r2 Comoving squared distance between particle i and particle j. + * @param dx Comoving distance vector between the particles (dx = pi->x - + * pj->x). + * @param hi Comoving smoothing-length of particle i. + * @param hj Comoving smoothing-length of particle j. * @param pi Particle i. * @param pj Particle j. + * @param a Current scale factor. + * @param H Current Hubble parameter. */ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force( - float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) { + float r2, const float *dx, float hi, float hj, struct part *restrict pi, + struct part *restrict pj, float a, float H) { - runner_iact_fluxes_common(r2, dx, hi, hj, pi, pj, 0); + runner_iact_fluxes_common(r2, dx, hi, hj, pi, pj, 0, a, H); } #endif /* SWIFT_GIZMO_HYDRO_IACT_H */ diff --git a/src/hydro/Gizmo/hydro_io.h b/src/hydro/Gizmo/hydro_io.h index aa26316d54c003c2fbd1fda7d05eadfb222c5fc2..b8e2e30646c3aafb73d387010ab7ea0b0a663a77 100644 --- a/src/hydro/Gizmo/hydro_io.h +++ b/src/hydro/Gizmo/hydro_io.h @@ -74,7 +74,7 @@ void hydro_read_particles(struct part* parts, struct io_props* list, */ void convert_u(const struct engine* e, const struct part* p, float* ret) { - ret[0] = hydro_get_internal_energy(p); + ret[0] = hydro_get_comoving_internal_energy(p); } /** @@ -85,7 +85,7 @@ void convert_u(const struct engine* e, const struct part* p, float* ret) { * @param ret (return) Entropic function of the particle */ void convert_A(const struct engine* e, const struct part* p, float* ret) { - ret[0] = hydro_get_entropy(p); + ret[0] = hydro_get_comoving_entropy(p); } /** diff --git a/src/hydro/Gizmo/hydro_part.h b/src/hydro/Gizmo/hydro_part.h index fdd73dd196465d7257555dcb2529935eec3fe3df..d5bc3f84238fecbf3b2f120f031996f55bbd65fe 100644 --- a/src/hydro/Gizmo/hydro_part.h +++ b/src/hydro/Gizmo/hydro_part.h @@ -34,6 +34,9 @@ struct xpart { /* Velocity at the last full step. */ float v_full[3]; + /* Gravitational acceleration at the last full step. */ + float a_grav[3]; + /* Additional data used to record cooling information */ struct cooling_xpart_data cooling_data; diff --git a/src/hydro/Minimal/hydro.h b/src/hydro/Minimal/hydro.h index 935b5d96843c5ed13b167ad1152c96b5ced647bd..97cd5ef577dcfd7b07c5183a92349313096a6412 100644 --- a/src/hydro/Minimal/hydro.h +++ b/src/hydro/Minimal/hydro.h @@ -35,6 +35,7 @@ #include "adiabatic_index.h" #include "approx_math.h" +#include "cosmology.h" #include "dimension.h" #include "equation_of_state.h" #include "hydro_properties.h" @@ -43,7 +44,7 @@ #include "minmax.h" /** - * @brief Returns the internal energy of a particle + * @brief Returns the comoving internal energy of a particle * * For implementations where the main thermodynamic variable * is not internal energy, this function computes the internal @@ -51,25 +52,61 @@ * * @param p The particle of interest */ -__attribute__((always_inline)) INLINE static float hydro_get_internal_energy( - const struct part *restrict p) { +__attribute__((always_inline)) INLINE static float +hydro_get_comoving_internal_energy(const struct part *restrict p) { return p->u; } /** - * @brief Returns the pressure of a particle + * @brief Returns the physical internal energy of a particle + * + * For implementations where the main thermodynamic variable + * is not internal energy, this function computes the internal + * energy from the thermodynamic variable and converts it to + * physical coordinates. + * + * @param p The particle of interest. + * @param cosmo The cosmological model. + */ +__attribute__((always_inline)) INLINE static float +hydro_get_physical_internal_energy(const struct part *restrict p, + const struct cosmology *cosmo) { + + return p->u * cosmo->a_factor_internal_energy; +} + +/** + * @brief Returns the comoving pressure of a particle + * + * Computes the pressure based on the particle's properties. * * @param p The particle of interest */ -__attribute__((always_inline)) INLINE static float hydro_get_pressure( +__attribute__((always_inline)) INLINE static float hydro_get_comoving_pressure( const struct part *restrict p) { return gas_pressure_from_internal_energy(p->rho, p->u); } /** - * @brief Returns the entropy of a particle + * @brief Returns the physical pressure of a particle + * + * Computes the pressure based on the particle's properties and + * convert it to physical coordinates. + * + * @param p The particle of interest + * @param cosmo The cosmological model. + */ +__attribute__((always_inline)) INLINE static float hydro_get_physical_pressure( + const struct part *restrict p, const struct cosmology *cosmo) { + + return cosmo->a_factor_pressure * + gas_pressure_from_internal_energy(p->rho, p->u); +} + +/** + * @brief Returns the comoving entropy of a particle * * For implementations where the main thermodynamic variable * is not entropy, this function computes the entropy from @@ -77,34 +114,78 @@ __attribute__((always_inline)) INLINE static float hydro_get_pressure( * * @param p The particle of interest */ -__attribute__((always_inline)) INLINE static float hydro_get_entropy( +__attribute__((always_inline)) INLINE static float hydro_get_comoving_entropy( const struct part *restrict p) { return gas_entropy_from_internal_energy(p->rho, p->u); } /** - * @brief Returns the sound speed of a particle + * @brief Returns the physical entropy of a particle + * + * For implementations where the main thermodynamic variable + * is not entropy, this function computes the entropy from + * the thermodynamic variable and converts it to + * physical coordinates. * * @param p The particle of interest + * @param cosmo The cosmological model. */ -__attribute__((always_inline)) INLINE static float hydro_get_soundspeed( - const struct part *restrict p) { +__attribute__((always_inline)) INLINE static float hydro_get_physical_entropy( + const struct part *restrict p, const struct cosmology *cosmo) { + + /* Note: no cosmological conversion required here with our choice of + * coordinates. */ + return gas_entropy_from_internal_energy(p->rho, p->u); +} + +/** + * @brief Returns the comoving sound speed of a particle + * + * @param p The particle of interest + */ +__attribute__((always_inline)) INLINE static float +hydro_get_comoving_soundspeed(const struct part *restrict p) { return p->force.soundspeed; } /** - * @brief Returns the density of a particle + * @brief Returns the physical sound speed of a particle * * @param p The particle of interest + * @param cosmo The cosmological model. */ -__attribute__((always_inline)) INLINE static float hydro_get_density( +__attribute__((always_inline)) INLINE static float +hydro_get_physical_soundspeed(const struct part *restrict p, + const struct cosmology *cosmo) { + + return cosmo->a_factor_sound_speed * p->force.soundspeed; +} + +/** + * @brief Returns the comoving density of a particle + * + * @param p The particle of interest + */ +__attribute__((always_inline)) INLINE static float hydro_get_comoving_density( const struct part *restrict p) { return p->rho; } +/** + * @brief Returns the comoving density of a particle. + * + * @param p The particle of interest + * @param cosmo The cosmological model. + */ +__attribute__((always_inline)) INLINE static float hydro_get_physical_density( + const struct part *restrict p, const struct cosmology *cosmo) { + + return cosmo->a3_inv * p->rho; +} + /** * @brief Returns the mass of a particle * @@ -121,16 +202,20 @@ __attribute__((always_inline)) INLINE static float hydro_get_mass( * * @param p The particle of interest * @param xp The extended data of the particle. - * @param dt The time since the last kick. + * @param dt_kick_hydro The time (for hydro accelerations) since the last kick. + * @param dt_kick_grav The time (for gravity accelerations) since the last kick. * @param v (return) The velocities at the current time. */ __attribute__((always_inline)) INLINE static void hydro_get_drifted_velocities( - const struct part *restrict p, const struct xpart *xp, float dt, - float v[3]) { - - v[0] = xp->v_full[0] + p->a_hydro[0] * dt; - v[1] = xp->v_full[1] + p->a_hydro[1] * dt; - v[2] = xp->v_full[2] + p->a_hydro[2] * dt; + const struct part *restrict p, const struct xpart *xp, float dt_kick_hydro, + float dt_kick_grav, float v[3]) { + + v[0] = xp->v_full[0] + p->a_hydro[0] * dt_kick_hydro + + xp->a_grav[0] * dt_kick_grav; + v[1] = xp->v_full[1] + p->a_hydro[1] * dt_kick_hydro + + xp->a_grav[1] * dt_kick_grav; + v[2] = xp->v_full[2] + p->a_hydro[2] * dt_kick_hydro + + xp->a_grav[2] * dt_kick_grav; } /** @@ -168,17 +253,18 @@ __attribute__((always_inline)) INLINE static void hydro_set_internal_energy_dt( * @param p Pointer to the particle data * @param xp Pointer to the extended particle data * @param hydro_properties The SPH parameters - * + * @param cosmo The cosmological model. */ __attribute__((always_inline)) INLINE static float hydro_compute_timestep( const struct part *restrict p, const struct xpart *restrict xp, - const struct hydro_props *restrict hydro_properties) { + const struct hydro_props *restrict hydro_properties, + const struct cosmology *restrict cosmo) { const float CFL_condition = hydro_properties->CFL_condition; /* CFL condition */ - const float dt_cfl = - 2.f * kernel_gamma * CFL_condition * p->h / p->force.v_sig; + const float dt_cfl = 2.f * kernel_gamma * CFL_condition * cosmo->a * p->h / + (cosmo->a_factor_sound_speed * p->force.v_sig); return dt_cfl; } @@ -218,13 +304,15 @@ __attribute__((always_inline)) INLINE static void hydro_init_part( * Multiplies the density and number of neighbours by the appropiate constants * and add the self-contribution term. * Additional quantities such as velocity gradients will also get the final - *terms - * added to them here. + * terms added to them here. + * + * Also adds/multiplies the cosmological terms if need be. * * @param p The particle to act upon + * @param cosmo The cosmological model. */ __attribute__((always_inline)) INLINE static void hydro_end_density( - struct part *restrict p) { + struct part *restrict p, const struct cosmology *cosmo) { /* Some smoothing length multiples. */ const float h = p->h; @@ -248,11 +336,17 @@ __attribute__((always_inline)) INLINE static void hydro_end_density( /** * @brief Sets all particle fields to sensible values when the #part has 0 ngbs. * + * In the desperate case where a particle has no neighbours (likely because + * of the h_max ceiling), set the particle fields to something sensible to avoid + * NaNs in the next calculations. + * * @param p The particle to act upon * @param xp The extended particle data to act upon + * @param cosmo The cosmological model. */ __attribute__((always_inline)) INLINE static void hydro_part_has_no_neighbours( - struct part *restrict p, struct xpart *restrict xp) { + struct part *restrict p, struct xpart *restrict xp, + const struct cosmology *cosmo) { /* Some smoothing length multiples. */ const float h = p->h; @@ -278,9 +372,11 @@ __attribute__((always_inline)) INLINE static void hydro_part_has_no_neighbours( * * @param p The particle to act upon * @param xp The extended particle data to act upon + * @param cosmo The current cosmological model. */ __attribute__((always_inline)) INLINE static void hydro_prepare_force( - struct part *restrict p, struct xpart *restrict xp) { + struct part *restrict p, struct xpart *restrict xp, + const struct cosmology *cosmo) { /* Compute the pressure */ const float pressure = gas_pressure_from_internal_energy(p->rho, p->u); @@ -346,17 +442,22 @@ __attribute__((always_inline)) INLINE static void hydro_reset_predicted_values( * Additional hydrodynamic quantites are drifted forward in time here. These * include thermal quantities (thermal energy or total energy or entropy, ...). * + * Note the different time-step sizes used for the different quantities as they + * include cosmological factors. + * * @param p The particle. * @param xp The extended data of the particle. - * @param dt The drift time-step. + * @param dt_drift The drift time-step for positions. + * @param dt_therm The drift time-step for thermal quantities. */ __attribute__((always_inline)) INLINE static void hydro_predict_extra( - struct part *restrict p, const struct xpart *restrict xp, float dt) { + struct part *restrict p, const struct xpart *restrict xp, float dt_drift, + float dt_therm) { const float h_inv = 1.f / p->h; /* Predict smoothing length */ - const float w1 = p->force.h_dt * h_inv * dt; + const float w1 = p->force.h_dt * h_inv * dt_drift; if (fabsf(w1) < 0.2f) p->h *= approx_expf(w1); /* 4th order expansion of exp(w) */ else @@ -370,7 +471,7 @@ __attribute__((always_inline)) INLINE static void hydro_predict_extra( p->rho *= expf(w2); /* Predict the internal energy */ - p->u += p->u_dt * dt; + p->u += p->u_dt * dt_therm; /* Compute the new pressure */ const float pressure = gas_pressure_from_internal_energy(p->rho, p->u); @@ -386,13 +487,16 @@ __attribute__((always_inline)) INLINE static void hydro_predict_extra( * @brief Finishes the force calculation. * * Multiplies the force and accelerations by the appropiate constants - * and add the self-contribution term. In most cases, there is nothing + * and add the self-contribution term. In most cases, there is little * to do here. * + * Cosmological terms are also added/multiplied here. + * * @param p The particle to act upon + * @param cosmo The current cosmological model. */ __attribute__((always_inline)) INLINE static void hydro_end_force( - struct part *restrict p) { + struct part *restrict p, const struct cosmology *cosmo) { p->force.h_dt *= p->h * hydro_dimension_inv; } @@ -403,18 +507,18 @@ __attribute__((always_inline)) INLINE static void hydro_end_force( * Additional hydrodynamic quantites are kicked forward in time here. These * include thermal quantities (thermal energy or total energy or entropy, ...). * - * @param p The particle to act upon - * @param xp The particle extended data to act upon - * @param dt The time-step for this kick + * @param p The particle to act upon. + * @param xp The particle extended data to act upon. + * @param dt_therm The time-step for this kick (for thermodynamic quantities). */ __attribute__((always_inline)) INLINE static void hydro_kick_extra( - struct part *restrict p, struct xpart *restrict xp, float dt) { + struct part *restrict p, struct xpart *restrict xp, float dt_therm) { /* Do not decrease the energy by more than a factor of 2*/ - if (dt > 0. && p->u_dt * dt < -0.5f * xp->u_full) { - p->u_dt = -0.5f * xp->u_full / dt; + if (dt_therm > 0. && p->u_dt * dt_therm < -0.5f * xp->u_full) { + p->u_dt = -0.5f * xp->u_full / dt_therm; } - xp->u_full += p->u_dt * dt; + xp->u_full += p->u_dt * dt_therm; /* Compute the pressure */ const float pressure = gas_pressure_from_internal_energy(p->rho, xp->u_full); @@ -467,6 +571,9 @@ __attribute__((always_inline)) INLINE static void hydro_first_init_part( xp->v_full[0] = p->v[0]; xp->v_full[1] = p->v[1]; xp->v_full[2] = p->v[2]; + xp->a_grav[0] = 0.f; + xp->a_grav[1] = 0.f; + xp->a_grav[2] = 0.f; xp->u_full = p->u; hydro_reset_acceleration(p); diff --git a/src/hydro/Minimal/hydro_debug.h b/src/hydro/Minimal/hydro_debug.h index 876ce148824489d4c43358c2c519aa3b90dcf002..541029ee06dd2799443fc89b688d7baca3fae0f8 100644 --- a/src/hydro/Minimal/hydro_debug.h +++ b/src/hydro/Minimal/hydro_debug.h @@ -43,8 +43,9 @@ __attribute__((always_inline)) INLINE static void hydro_debug_particle( "time_bin=%d\n", p->x[0], p->x[1], p->x[2], p->v[0], p->v[1], p->v[2], xp->v_full[0], xp->v_full[1], xp->v_full[2], p->a_hydro[0], p->a_hydro[1], p->a_hydro[2], - p->u, p->u_dt, p->force.v_sig, p->force.pressure, p->h, p->force.h_dt, - (int)p->density.wcount, p->mass, p->density.rho_dh, p->rho, p->time_bin); + p->u, p->u_dt, p->force.v_sig, hydro_get_comoving_pressure(p), p->h, + p->force.h_dt, (int)p->density.wcount, p->mass, p->density.rho_dh, p->rho, + p->time_bin); } #endif /* SWIFT_MINIMAL_HYDRO_DEBUG_H */ diff --git a/src/hydro/Minimal/hydro_iact.h b/src/hydro/Minimal/hydro_iact.h index 0d4db1123d23e59146a2b026700c7b44a9e99f0c..bfd8f1dff5febbd14b8a1e3a1cb8c01d49bc85ba 100644 --- a/src/hydro/Minimal/hydro_iact.h +++ b/src/hydro/Minimal/hydro_iact.h @@ -36,10 +36,20 @@ #include "minmax.h" /** - * @brief Density loop + * @brief Density interaction between two particles. + * + * @param r2 Comoving square distance between the two particles. + * @param dx Comoving vector separating both particles (pi - pj). + * @param hi Comoving smoothing-length of particle i. + * @param hj Comoving smoothing-length of particle j. + * @param pi First particle. + * @param pj Second particle. + * @param a Current scale factor. + * @param H Current Hubble parameter. */ __attribute__((always_inline)) INLINE static void runner_iact_density( - float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) { + float r2, const float *dx, float hi, float hj, struct part *restrict pi, + struct part *restrict pj, float a, float H) { float wi, wj, wi_dx, wj_dx; @@ -71,10 +81,20 @@ __attribute__((always_inline)) INLINE static void runner_iact_density( } /** - * @brief Density loop (non-symmetric version) + * @brief Density interaction between two particles (non-symmetric). + * + * @param r2 Comoving square distance between the two particles. + * @param dx Comoving vector separating both particles (pi - pj). + * @param hi Comoving smoothing-length of particle i. + * @param hj Comoving smoothing-length of particle j. + * @param pi First particle. + * @param pj Second particle (not updated). + * @param a Current scale factor. + * @param H Current Hubble parameter. */ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_density( - float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) { + float r2, const float *dx, float hi, float hj, struct part *restrict pi, + const struct part *restrict pj, float a, float H) { float wi, wi_dx; @@ -95,12 +115,24 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_density( } /** - * @brief Force loop + * @brief Force interaction between two particles. + * + * @param r2 Comoving square distance between the two particles. + * @param dx Comoving vector separating both particles (pi - pj). + * @param hi Comoving smoothing-length of particle i. + * @param hj Comoving smoothing-length of particle j. + * @param pi First particle. + * @param pj Second particle. + * @param a Current scale factor. + * @param H Current Hubble parameter. */ __attribute__((always_inline)) INLINE static void runner_iact_force( - float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) { + float r2, const float *dx, float hi, float hj, struct part *restrict pi, + struct part *restrict pj, float a, float H) { - const float fac_mu = 1.f; /* Will change with cosmological integration */ + /* Cosmological factors entering the EoMs */ + const float fac_mu = pow_three_gamma_minus_five_over_two(a); + const float a2_Hubble = a * a * H; const float r = sqrtf(r2); const float r_inv = 1.0f / r; @@ -136,7 +168,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_force( /* Compute dv dot r. */ const float dvdr = (pi->v[0] - pj->v[0]) * dx[0] + (pi->v[1] - pj->v[1]) * dx[1] + - (pi->v[2] - pj->v[2]) * dx[2]; + (pi->v[2] - pj->v[2]) * dx[2] + a2_Hubble * r2; /* Are the particles moving towards each others ? */ const float omega_ij = min(dvdr, 0.f); @@ -195,12 +227,24 @@ __attribute__((always_inline)) INLINE static void runner_iact_force( } /** - * @brief Force loop (non-symmetric version) + * @brief Force interaction between two particles (non-symmetric). + * + * @param r2 Comoving square distance between the two particles. + * @param dx Comoving vector separating both particles (pi - pj). + * @param hi Comoving smoothing-length of particle i. + * @param hj Comoving smoothing-length of particle j. + * @param pi First particle. + * @param pj Second particle (not updated). + * @param a Current scale factor. + * @param H Current Hubble parameter. */ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force( - float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) { + float r2, const float *dx, float hi, float hj, struct part *restrict pi, + const struct part *restrict pj, float a, float H) { - const float fac_mu = 1.f; /* Will change with cosmological integration */ + /* Cosmological factors entering the EoMs */ + const float fac_mu = pow_three_gamma_minus_five_over_two(a); + const float a2_Hubble = a * a * H; const float r = sqrtf(r2); const float r_inv = 1.0f / r; @@ -236,7 +280,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force( /* Compute dv dot r. */ const float dvdr = (pi->v[0] - pj->v[0]) * dx[0] + (pi->v[1] - pj->v[1]) * dx[1] + - (pi->v[2] - pj->v[2]) * dx[2]; + (pi->v[2] - pj->v[2]) * dx[2] + a2_Hubble * r2; /* Are the particles moving towards each others ? */ const float omega_ij = min(dvdr, 0.f); diff --git a/src/hydro/Minimal/hydro_io.h b/src/hydro/Minimal/hydro_io.h index d30d1e6ce6ecc00f5c370239e966ab1391055c3b..5922834e12f6dd74e951b46c2c93f975d7e8b82e 100644 --- a/src/hydro/Minimal/hydro_io.h +++ b/src/hydro/Minimal/hydro_io.h @@ -71,12 +71,12 @@ void hydro_read_particles(struct part* parts, struct io_props* list, void convert_S(const struct engine* e, const struct part* p, float* ret) { - ret[0] = hydro_get_entropy(p); + ret[0] = hydro_get_comoving_entropy(p); } void convert_P(const struct engine* e, const struct part* p, float* ret) { - ret[0] = hydro_get_pressure(p); + ret[0] = hydro_get_comoving_pressure(p); } void convert_part_pos(const struct engine* e, const struct part* p, diff --git a/src/hydro/Minimal/hydro_part.h b/src/hydro/Minimal/hydro_part.h index 7556f415b9a3fb03923c98352322a9922f078f9a..c33f1b9a214cf9839f1acb965b686d4a4962865c 100644 --- a/src/hydro/Minimal/hydro_part.h +++ b/src/hydro/Minimal/hydro_part.h @@ -53,6 +53,9 @@ struct xpart { /*! Velocity at the last full step. */ float v_full[3]; + /*! Gravitational acceleration at the last full step. */ + float a_grav[3]; + /*! Internal energy at the last full step. */ float u_full; diff --git a/src/hydro/PressureEntropy/hydro.h b/src/hydro/PressureEntropy/hydro.h index 2c10e4fde8865c5afa228fbb92a79dfa5aa55a87..37de855b375a5ac11f8a33f3993f7d2101c58522 100644 --- a/src/hydro/PressureEntropy/hydro.h +++ b/src/hydro/PressureEntropy/hydro.h @@ -33,6 +33,7 @@ #include "adiabatic_index.h" #include "approx_math.h" +#include "cosmology.h" #include "dimension.h" #include "equation_of_state.h" #include "hydro_properties.h" @@ -41,60 +42,123 @@ #include "minmax.h" /** - * @brief Returns the internal energy of a particle + * @brief Returns the comoving internal energy of a particle * * @param p The particle of interest */ -__attribute__((always_inline)) INLINE static float hydro_get_internal_energy( - const struct part *restrict p) { +__attribute__((always_inline)) INLINE static float +hydro_get_comoving_internal_energy(const struct part *restrict p) { return gas_internal_energy_from_entropy(p->rho_bar, p->entropy); } /** - * @brief Returns the pressure of a particle + * @brief Returns the physical internal energy of a particle + * + * @param p The particle of interest + * @param cosmo The cosmological model. + */ +__attribute__((always_inline)) INLINE static float +hydro_get_physical_internal_energy(const struct part *restrict p, + const struct cosmology *cosmo) { + + return gas_internal_energy_from_entropy(p->rho_bar * cosmo->a3_inv, + p->entropy); +} + +/** + * @brief Returns the comoving pressure of a particle * * @param p The particle of interest */ -__attribute__((always_inline)) INLINE static float hydro_get_pressure( +__attribute__((always_inline)) INLINE static float hydro_get_comoving_pressure( const struct part *restrict p) { return gas_pressure_from_entropy(p->rho_bar, p->entropy); } /** - * @brief Returns the entropy of a particle + * @brief Returns the physical pressure of a particle * * @param p The particle of interest */ -__attribute__((always_inline)) INLINE static float hydro_get_entropy( +__attribute__((always_inline)) INLINE static float hydro_get_physical_pressure( + const struct part *restrict p, const struct cosmology *cosmo) { + + return gas_pressure_from_entropy(p->rho_bar * cosmo->a3_inv, p->entropy); +} + +/** + * @brief Returns the comoving entropy of a particle + * + * @param p The particle of interest + */ +__attribute__((always_inline)) INLINE static float hydro_get_comoving_entropy( const struct part *restrict p) { return p->entropy; } /** - * @brief Returns the sound speed of a particle + * @brief Returns the physical entropy of a particle + * + * @param p The particle of interest. + * @param cosmo The cosmological model. + */ +__attribute__((always_inline)) INLINE static float hydro_get_physical_entropy( + const struct part *restrict p, const struct cosmology *cosmo) { + + /* Note: no cosmological conversion required here with our choice of + * coordinates. */ + return p->entropy; +} + +/** + * @brief Returns the comoving sound speed of a particle * * @param p The particle of interest */ -__attribute__((always_inline)) INLINE static float hydro_get_soundspeed( - const struct part *restrict p) { +__attribute__((always_inline)) INLINE static float +hydro_get_comoving_soundspeed(const struct part *restrict p) { return p->force.soundspeed; } /** - * @brief Returns the physical density of a particle + * @brief Returns the physical sound speed of a particle + * + * @param p The particle of interest + * @param cosmo The cosmological model. + */ +__attribute__((always_inline)) INLINE static float +hydro_get_physical_soundspeed(const struct part *restrict p, + const struct cosmology *cosmo) { + + return cosmo->a_factor_sound_speed * p->force.soundspeed; +} + +/** + * @brief Returns the comoving density of a particle * * @param p The particle of interest */ -__attribute__((always_inline)) INLINE static float hydro_get_density( +__attribute__((always_inline)) INLINE static float hydro_get_comoving_density( const struct part *restrict p) { return p->rho; } +/** + * @brief Returns the physical density of a particle + * + * @param p The particle of interest + */ +__attribute__((always_inline)) INLINE static float hydro_get_physical_density( + const struct part *restrict p, const struct cosmology *cosmo) { + + return p->rho * cosmo->a3_inv; +} + /** * @brief Returns the mass of a particle * @@ -111,16 +175,20 @@ __attribute__((always_inline)) INLINE static float hydro_get_mass( * * @param p The particle of interest * @param xp The extended data of the particle. - * @param dt The time since the last kick. + * @param dt_kick_hydro The time (for hydro accelerations) since the last kick. + * @param dt_kick_grav The time (for gravity accelerations) since the last kick. * @param v (return) The velocities at the current time. */ __attribute__((always_inline)) INLINE static void hydro_get_drifted_velocities( - const struct part *restrict p, const struct xpart *xp, float dt, - float v[3]) { - - v[0] = xp->v_full[0] + p->a_hydro[0] * dt; - v[1] = xp->v_full[1] + p->a_hydro[1] * dt; - v[2] = xp->v_full[2] + p->a_hydro[2] * dt; + const struct part *restrict p, const struct xpart *xp, float dt_kick_hydro, + float dt_kick_grav, float v[3]) { + + v[0] = xp->v_full[0] + p->a_hydro[0] * dt_kick_hydro + + xp->a_grav[0] * dt_kick_grav; + v[1] = xp->v_full[1] + p->a_hydro[1] * dt_kick_hydro + + xp->a_grav[1] * dt_kick_grav; + v[2] = xp->v_full[2] + p->a_hydro[2] * dt_kick_hydro + + xp->a_grav[2] * dt_kick_grav; } /** @@ -153,19 +221,21 @@ __attribute__((always_inline)) INLINE static void hydro_set_internal_energy_dt( /** * @brief Computes the hydro time-step of a given particle * - * @param p Pointer to the particle data - * @param xp Pointer to the extended particle data - * + * @param p Pointer to the particle data. + * @param xp Pointer to the extended particle data. + * @param hydro_properties The constants used in the scheme. + * @param cosmo The current cosmological model. */ __attribute__((always_inline)) INLINE static float hydro_compute_timestep( const struct part *restrict p, const struct xpart *restrict xp, - const struct hydro_props *restrict hydro_properties) { + const struct hydro_props *restrict hydro_properties, + const struct cosmology *restrict cosmo) { - const float CFL_condition = hydro_properties->CFL_condition; + const float CFL = hydro_properties->CFL_condition; /* CFL condition */ - const float dt_cfl = - 2.f * kernel_gamma * CFL_condition * p->h / p->force.v_sig; + const float dt_cfl = 2.f * kernel_gamma * CFL * cosmo->a * p->h / + (cosmo->a_factor_sound_speed * p->force.v_sig); return dt_cfl; } @@ -212,9 +282,10 @@ __attribute__((always_inline)) INLINE static void hydro_init_part( * and add the self-contribution term. * * @param p The particle to act upon + * @param cosmo The current cosmological model. */ __attribute__((always_inline)) INLINE static void hydro_end_density( - struct part *restrict p) { + struct part *restrict p, const struct cosmology *cosmo) { /* Some smoothing length multiples. */ const float h = p->h; @@ -240,15 +311,16 @@ __attribute__((always_inline)) INLINE static void hydro_end_density( p->density.wcount_dh *= h_inv_dim_plus_one; const float rho_inv = 1.f / p->rho; + const float a_inv2 = cosmo->a2_inv; const float entropy_minus_one_over_gamma = 1.f / p->entropy_one_over_gamma; /* Final operation on the weighted density */ p->rho_bar *= entropy_minus_one_over_gamma; /* Finish calculation of the velocity curl components */ - p->density.rot_v[0] *= h_inv_dim_plus_one * rho_inv; - p->density.rot_v[1] *= h_inv_dim_plus_one * rho_inv; - p->density.rot_v[2] *= h_inv_dim_plus_one * rho_inv; + p->density.rot_v[0] *= h_inv_dim_plus_one * a_inv2 * rho_inv; + p->density.rot_v[1] *= h_inv_dim_plus_one * a_inv2 * rho_inv; + p->density.rot_v[2] *= h_inv_dim_plus_one * a_inv2 * rho_inv; /* Finish calculation of the velocity divergence */ p->density.div_v *= h_inv_dim_plus_one * rho_inv; @@ -259,9 +331,11 @@ __attribute__((always_inline)) INLINE static void hydro_end_density( * * @param p The particle to act upon * @param xp The extended particle data to act upon + * @param cosmo The current cosmological model. */ __attribute__((always_inline)) INLINE static void hydro_part_has_no_neighbours( - struct part *restrict p, struct xpart *restrict xp) { + struct part *restrict p, struct xpart *restrict xp, + const struct cosmology *cosmo) { /* Some smoothing length multiples. */ const float h = p->h; @@ -288,11 +362,13 @@ __attribute__((always_inline)) INLINE static void hydro_part_has_no_neighbours( * * @param p The particle to act upon * @param xp The extended particle data to act upon + * @param cosmo The current cosmological model. */ __attribute__((always_inline)) INLINE static void hydro_prepare_force( - struct part *restrict p, struct xpart *restrict xp) { + struct part *restrict p, struct xpart *restrict xp, + const struct cosmology *cosmo) { - const float fac_mu = 1.f; /* Will change with cosmological integration */ + const float fac_mu = cosmo->a_factor_mu; /* Compute the norm of the curl */ const float curl_v = sqrtf(p->density.rot_v[0] * p->density.rot_v[0] + @@ -310,7 +386,7 @@ __attribute__((always_inline)) INLINE static void hydro_prepare_force( /* Compute the Balsara switch */ const float balsara = - abs_div_v / (abs_div_v + curl_v + 0.0001f * soundspeed / fac_mu / p->h); + abs_div_v / (abs_div_v + curl_v + 0.0001f * soundspeed * fac_mu / p->h); /* Divide the pressure by the density squared to get the SPH term */ const float rho_bar_inv = 1.f / p->rho_bar; @@ -380,15 +456,17 @@ __attribute__((always_inline)) INLINE static void hydro_reset_predicted_values( * * @param p The particle * @param xp The extended data of the particle - * @param dt The drift time-step. + * @param dt_drift The drift time-step for positions. + * @param dt_therm The drift time-step for thermal quantities. */ __attribute__((always_inline)) INLINE static void hydro_predict_extra( - struct part *restrict p, const struct xpart *restrict xp, float dt) { + struct part *restrict p, const struct xpart *restrict xp, float dt_drift, + float dt_therm) { const float h_inv = 1.f / p->h; /* Predict smoothing length */ - const float w1 = p->force.h_dt * h_inv * dt; + const float w1 = p->force.h_dt * h_inv * dt_drift; if (fabsf(w1) < 0.2f) p->h *= approx_expf(w1); /* 4th order expansion of exp(w) */ else @@ -405,7 +483,7 @@ __attribute__((always_inline)) INLINE static void hydro_predict_extra( } /* Predict the entropy */ - p->entropy += p->entropy_dt * dt; + p->entropy += p->entropy_dt * dt_therm; /* Compute the pressure */ const float pressure = gas_pressure_from_entropy(p->rho_bar, p->entropy); @@ -429,14 +507,15 @@ __attribute__((always_inline)) INLINE static void hydro_predict_extra( * Multiplies the forces and accelerationsby the appropiate constants * * @param p The particle to act upon + * @param cosmo The current cosmological model. */ __attribute__((always_inline)) INLINE static void hydro_end_force( - struct part *restrict p) { + struct part *restrict p, const struct cosmology *cosmo) { p->force.h_dt *= p->h * hydro_dimension_inv; - p->entropy_dt = - 0.5f * gas_entropy_from_internal_energy(p->rho_bar, p->entropy_dt); + p->entropy_dt = 0.5f * cosmo->a2_inv * + gas_entropy_from_internal_energy(p->rho_bar, p->entropy_dt); } /** @@ -444,17 +523,16 @@ __attribute__((always_inline)) INLINE static void hydro_end_force( * * @param p The particle to act upon * @param xp The particle extended data to act upon - * @param dt The time-step for this kick - * @param half_dt The half time-step for this kick + * @param dt_therm The time-step for this kick (for thermodynamic quantities) */ __attribute__((always_inline)) INLINE static void hydro_kick_extra( - struct part *restrict p, struct xpart *restrict xp, float dt) { + struct part *restrict p, struct xpart *restrict xp, float dt_therm) { /* Do not decrease the entropy (temperature) by more than a factor of 2*/ - if (dt > 0. && p->entropy_dt * dt < -0.5f * xp->entropy_full) { - p->entropy_dt = -0.5f * xp->entropy_full / dt; + if (dt_therm > 0. && p->entropy_dt * dt_therm < -0.5f * xp->entropy_full) { + p->entropy_dt = -0.5f * xp->entropy_full / dt_therm; } - xp->entropy_full += p->entropy_dt * dt; + xp->entropy_full += p->entropy_dt * dt_therm; /* Compute the pressure */ const float pressure = @@ -519,6 +597,9 @@ __attribute__((always_inline)) INLINE static void hydro_first_init_part( xp->v_full[0] = p->v[0]; xp->v_full[1] = p->v[1]; xp->v_full[2] = p->v[2]; + xp->a_grav[0] = 0.f; + xp->a_grav[1] = 0.f; + xp->a_grav[2] = 0.f; hydro_reset_acceleration(p); hydro_init_part(p, NULL); diff --git a/src/hydro/PressureEntropy/hydro_debug.h b/src/hydro/PressureEntropy/hydro_debug.h index 3a0a315a4fa0eb4710042e8020002691ed9c425a..14d69bb650ff1bbd49394c0ca2f6256ad0cb188d 100644 --- a/src/hydro/PressureEntropy/hydro_debug.h +++ b/src/hydro/PressureEntropy/hydro_debug.h @@ -40,10 +40,10 @@ __attribute__((always_inline)) INLINE static void hydro_debug_particle( p->x[0], p->x[1], p->x[2], p->v[0], p->v[1], p->v[2], xp->v_full[0], xp->v_full[1], xp->v_full[2], p->a_hydro[0], p->a_hydro[1], p->a_hydro[2], p->h, p->density.wcount, p->density.wcount_dh, p->mass, p->density.rho_dh, - p->rho, p->rho_bar, hydro_get_pressure(p), p->density.pressure_dh, - p->force.P_over_rho2, p->entropy, p->entropy_one_over_gamma, - p->entropy_dt, p->force.soundspeed, p->force.v_sig, p->force.h_dt, - p->time_bin); + p->rho, p->rho_bar, hydro_get_comoving_pressure(p), + p->density.pressure_dh, p->force.P_over_rho2, p->entropy, + p->entropy_one_over_gamma, p->entropy_dt, p->force.soundspeed, + p->force.v_sig, p->force.h_dt, p->time_bin); } #endif /* SWIFT_PRESSURE_ENTROPY_HYDRO_DEBUG_H */ diff --git a/src/hydro/PressureEntropy/hydro_iact.h b/src/hydro/PressureEntropy/hydro_iact.h index 171f7911a31b53fce74713e6d7e244bc79c59828..c9e3c4ec7728df8a8e7d59b8c21f22bd613463d8 100644 --- a/src/hydro/PressureEntropy/hydro_iact.h +++ b/src/hydro/PressureEntropy/hydro_iact.h @@ -21,7 +21,7 @@ /** * @file PressureEntropy/hydro_iact.h - * @brief Pressure-Entropy implementation of SPH (Neighbour loop equations) + * @brief Pressure-Entropy implementation of SPH (Particle interactions) * * The thermal variable is the entropy (S) and the entropy is smoothed over * contact discontinuities to prevent spurious surface tension. @@ -31,10 +31,20 @@ */ /** - * @brief Density loop + * @brief Density interaction between two particles. + * + * @param r2 Comoving square distance between the two particles. + * @param dx Comoving vector separating both particles (pi - pj). + * @param hi Comoving smoothing-length of particle i. + * @param hj Comoving smoothing-length of particle j. + * @param pi First particle. + * @param pj Second particle. + * @param a Current scale factor. + * @param H Current Hubble parameter. */ __attribute__((always_inline)) INLINE static void runner_iact_density( - float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) { + float r2, const float *dx, float hi, float hj, struct part *restrict pi, + struct part *restrict pj, float a, float H) { float wi, wi_dx; float wj, wj_dx; @@ -111,10 +121,20 @@ __attribute__((always_inline)) INLINE static void runner_iact_density( } /** - * @brief Density loop (non-symmetric version) + * @brief Density interaction between two particles (non-symmetric). + * + * @param r2 Comoving square distance between the two particles. + * @param dx Comoving vector separating both particles (pi - pj). + * @param hi Comoving smoothing-length of particle i. + * @param hj Comoving smoothing-length of particle j. + * @param pi First particle. + * @param pj Second particle (not updated). + * @param a Current scale factor. + * @param H Current Hubble parameter. */ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_density( - float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) { + float r2, const float *dx, float hi, float hj, struct part *restrict pi, + const struct part *restrict pj, float a, float H) { float wi, wi_dx; float dv[3], curlvr[3]; @@ -164,14 +184,26 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_density( } /** - * @brief Force loop + * @brief Force interaction between two particles. + * + * @param r2 Comoving square distance between the two particles. + * @param dx Comoving vector separating both particles (pi - pj). + * @param hi Comoving smoothing-length of particle i. + * @param hj Comoving smoothing-length of particle j. + * @param pi First particle. + * @param pj Second particle. + * @param a Current scale factor. + * @param H Current Hubble parameter. */ __attribute__((always_inline)) INLINE static void runner_iact_force( - float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) { + float r2, const float *dx, float hi, float hj, struct part *restrict pi, + struct part *restrict pj, float a, float H) { float wi, wj, wi_dx, wj_dx; - const float fac_mu = 1.f; /* Will change with cosmological integration */ + /* Cosmological factors entering the EoMs */ + const float fac_mu = pow_three_gamma_minus_five_over_two(a); + const float a2_Hubble = a * a * H; const float r = sqrtf(r2); const float r_inv = 1.0f / r; @@ -215,7 +247,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_force( /* Compute dv dot r. */ const float dvdr = (pi->v[0] - pj->v[0]) * dx[0] + (pi->v[1] - pj->v[1]) * dx[1] + - (pi->v[2] - pj->v[2]) * dx[2]; + (pi->v[2] - pj->v[2]) * dx[2] + a2_Hubble * r2; /* Balsara term */ const float balsara_i = pi->force.balsara; @@ -265,14 +297,26 @@ __attribute__((always_inline)) INLINE static void runner_iact_force( } /** - * @brief Force loop (non-symmetric version) + * @brief Force interaction between two particles (non-symmetric). + * + * @param r2 Comoving square distance between the two particles. + * @param dx Comoving vector separating both particles (pi - pj). + * @param hi Comoving smoothing-length of particle i. + * @param hj Comoving smoothing-length of particle j. + * @param pi First particle. + * @param pj Second particle (not updated). + * @param a Current scale factor. + * @param H Current Hubble parameter. */ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force( - float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) { + float r2, const float *dx, float hi, float hj, struct part *restrict pi, + const struct part *restrict pj, float a, float H) { float wi, wj, wi_dx, wj_dx; - const float fac_mu = 1.f; /* Will change with cosmological integration */ + /* Cosmological factors entering the EoMs */ + const float fac_mu = pow_three_gamma_minus_five_over_two(a); + const float a2_Hubble = a * a * H; const float r = sqrtf(r2); const float r_inv = 1.0f / r; @@ -316,7 +360,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force( /* Compute dv dot r. */ const float dvdr = (pi->v[0] - pj->v[0]) * dx[0] + (pi->v[1] - pj->v[1]) * dx[1] + - (pi->v[2] - pj->v[2]) * dx[2]; + (pi->v[2] - pj->v[2]) * dx[2] + a2_Hubble * r2; /* Balsara term */ const float balsara_i = pi->force.balsara; diff --git a/src/hydro/PressureEntropy/hydro_io.h b/src/hydro/PressureEntropy/hydro_io.h index 3c06f60408c62b50964377917600c869652f3576..454d999b6dcd604e25da4c513d902854c43c781b 100644 --- a/src/hydro/PressureEntropy/hydro_io.h +++ b/src/hydro/PressureEntropy/hydro_io.h @@ -69,12 +69,12 @@ void hydro_read_particles(struct part* parts, struct io_props* list, void convert_u(const struct engine* e, const struct part* p, float* ret) { - ret[0] = hydro_get_internal_energy(p); + ret[0] = hydro_get_comoving_internal_energy(p); } void convert_P(const struct engine* e, const struct part* p, float* ret) { - ret[0] = hydro_get_pressure(p); + ret[0] = hydro_get_comoving_pressure(p); } void convert_part_pos(const struct engine* e, const struct part* p, diff --git a/src/hydro/PressureEntropy/hydro_part.h b/src/hydro/PressureEntropy/hydro_part.h index c9482cd1ace7c53863885155cbca1afc6dddeb5f..fb8424d66196b7013866acef6bec6ec9889a3353 100644 --- a/src/hydro/PressureEntropy/hydro_part.h +++ b/src/hydro/PressureEntropy/hydro_part.h @@ -45,6 +45,9 @@ struct xpart { /*! Velocity at the last full step. */ float v_full[3]; + /*! Gravitational acceleration at the last full step. */ + float a_grav[3]; + /*! Entropy at the last full step. */ float entropy_full; diff --git a/src/kick.h b/src/kick.h index 7ccea7d26974297cfebc605808c4443633140ec1..9b1f4f18112a1cb2affcff70e7773ba4c48681b5 100644 --- a/src/kick.h +++ b/src/kick.h @@ -32,16 +32,14 @@ * @brief Perform the 'kick' operation on a #gpart * * @param gp The #gpart to kick. - * @param ti_start The starting (integer) time of the kick - * @param ti_end The ending (integer) time of the kick - * @param timeBase The minimal allowed time-step size. + * @param dt_kick_grav The kick time-step for gravity accelerations. + * @param ti_start The starting (integer) time of the kick (for debugging + * checks). + * @param ti_end The ending (integer) time of the kick (for debugging checks). */ __attribute__((always_inline)) INLINE static void kick_gpart( - struct gpart *restrict gp, integertime_t ti_start, integertime_t ti_end, - double timeBase) { - - /* Time interval for this half-kick */ - const float dt = (ti_end - ti_start) * timeBase; + struct gpart *restrict gp, double dt_kick_grav, integertime_t ti_start, + integertime_t ti_end) { #ifdef SWIFT_DEBUG_CHECKS if (gp->ti_kick != ti_start) @@ -54,12 +52,12 @@ __attribute__((always_inline)) INLINE static void kick_gpart( #endif /* Kick particles in momentum space */ - gp->v_full[0] += gp->a_grav[0] * dt; - gp->v_full[1] += gp->a_grav[1] * dt; - gp->v_full[2] += gp->a_grav[2] * dt; + gp->v_full[0] += gp->a_grav[0] * dt_kick_grav; + gp->v_full[1] += gp->a_grav[1] * dt_kick_grav; + gp->v_full[2] += gp->a_grav[2] * dt_kick_grav; /* Kick extra variables */ - gravity_kick_extra(gp, dt); + gravity_kick_extra(gp, dt_kick_grav); } /** @@ -67,16 +65,17 @@ __attribute__((always_inline)) INLINE static void kick_gpart( * * @param p The #part to kick. * @param xp The #xpart of the particle. - * @param ti_start The starting (integer) time of the kick - * @param ti_end The ending (integer) time of the kick - * @param timeBase The minimal allowed time-step size. + * @param dt_kick_hydro The kick time-step for hydro accelerations. + * @param dt_kick_grav The kick time-step for gravity accelerations. + * @param dt_kick_therm The kick time-step for changes in thermal state. + * @param ti_start The starting (integer) time of the kick (for debugging + * checks). + * @param ti_end The ending (integer) time of the kick (for debugging checks). */ __attribute__((always_inline)) INLINE static void kick_part( - struct part *restrict p, struct xpart *restrict xp, integertime_t ti_start, - integertime_t ti_end, double timeBase) { - - /* Time interval for this half-kick */ - const float dt = (ti_end - ti_start) * timeBase; + struct part *restrict p, struct xpart *restrict xp, double dt_kick_hydro, + double dt_kick_grav, double dt_kick_therm, integertime_t ti_start, + integertime_t ti_end) { #ifdef SWIFT_DEBUG_CHECKS if (p->ti_kick != ti_start) @@ -88,18 +87,19 @@ __attribute__((always_inline)) INLINE static void kick_part( p->ti_kick = ti_end; #endif - /* Get the acceleration */ - float a_tot[3] = {p->a_hydro[0], p->a_hydro[1], p->a_hydro[2]}; + /* Kick particles in momentum space (hydro acc.) */ + xp->v_full[0] += p->a_hydro[0] * dt_kick_hydro; + xp->v_full[1] += p->a_hydro[1] * dt_kick_hydro; + xp->v_full[2] += p->a_hydro[2] * dt_kick_hydro; + + /* Kick particles in momentum space (grav acc.) */ 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]; + xp->v_full[0] += p->gpart->a_grav[0] * dt_kick_grav; + xp->v_full[1] += p->gpart->a_grav[1] * dt_kick_grav; + xp->v_full[2] += p->gpart->a_grav[2] * dt_kick_grav; } - /* Kick particles in momentum space */ - xp->v_full[0] += a_tot[0] * dt; - xp->v_full[1] += a_tot[1] * dt; - xp->v_full[2] += a_tot[2] * dt; + /* Give the gpart friend the same velocity */ if (p->gpart != NULL) { p->gpart->v_full[0] = xp->v_full[0]; p->gpart->v_full[1] = xp->v_full[1]; @@ -107,24 +107,22 @@ __attribute__((always_inline)) INLINE static void kick_part( } /* Extra kick work */ - hydro_kick_extra(p, xp, dt); - if (p->gpart != NULL) gravity_kick_extra(p->gpart, dt); + hydro_kick_extra(p, xp, dt_kick_therm); + if (p->gpart != NULL) gravity_kick_extra(p->gpart, dt_kick_grav); } /** * @brief Perform the 'kick' operation on a #spart * * @param sp The #spart to kick. - * @param ti_start The starting (integer) time of the kick - * @param ti_end The ending (integer) time of the kick - * @param timeBase The minimal allowed time-step size. + * @param dt_kick_grav The kick time-step for gravity accelerations. + * @param ti_start The starting (integer) time of the kick (for debugging + * checks). + * @param ti_end The ending (integer) time of the kick (for debugging checks). */ __attribute__((always_inline)) INLINE static void kick_spart( - struct spart *restrict sp, integertime_t ti_start, integertime_t ti_end, - double timeBase) { - - /* Time interval for this half-kick */ - const float dt = (ti_end - ti_start) * timeBase; + struct spart *restrict sp, double dt_kick_grav, integertime_t ti_start, + integertime_t ti_end) { #ifdef SWIFT_DEBUG_CHECKS if (sp->ti_kick != ti_start) @@ -136,20 +134,18 @@ __attribute__((always_inline)) INLINE static void kick_spart( sp->ti_kick = ti_end; #endif - /* Acceleration from gravity */ - const float a[3] = {sp->gpart->a_grav[0], sp->gpart->a_grav[1], - sp->gpart->a_grav[2]}; - /* Kick particles in momentum space */ - sp->v[0] += a[0] * dt; - sp->v[1] += a[1] * dt; - sp->v[2] += a[2] * dt; + sp->v[0] += sp->gpart->a_grav[0] * dt_kick_grav; + sp->v[1] += sp->gpart->a_grav[1] * dt_kick_grav; + sp->v[2] += sp->gpart->a_grav[2] * dt_kick_grav; + + /* Give the gpart friend the same velocity */ sp->gpart->v_full[0] = sp->v[0]; sp->gpart->v_full[1] = sp->v[1]; sp->gpart->v_full[2] = sp->v[2]; /* Kick extra variables */ - star_kick_extra(sp, dt); + star_kick_extra(sp, dt_kick_grav); } #endif /* SWIFT_KICK_H */ diff --git a/src/parallel_io.c b/src/parallel_io.c index 315c187e65f1a30b0401cb9368944f8f9968223a..d3f5f8dc36dd63ad1b7cf4d65311751cd15f887b 100644 --- a/src/parallel_io.c +++ b/src/parallel_io.c @@ -870,6 +870,8 @@ void prepare_file(struct engine* e, const char* baseName, long long N_total[6], io_write_attribute(h_grp, "Time", DOUBLE, &dblTime, 1); int dimension = (int)hydro_dimension; io_write_attribute(h_grp, "Dimension", INT, &dimension, 1); + io_write_attribute(h_grp, "Redshift", DOUBLE, &e->cosmology->z, 1); + io_write_attribute(h_grp, "Scale-factor", DOUBLE, &e->cosmology->a, 1); /* GADGET-2 legacy values */ /* Number of particles of each type */ @@ -899,6 +901,9 @@ void prepare_file(struct engine* e, const char* baseName, long long N_total[6], /* Print the code version */ io_write_code_description(h_file); + /* Print the run's policy */ + io_write_engine_policy(h_file, e); + /* Print the SPH parameters */ if (e->policy & engine_policy_hydro) { h_grp = H5Gcreate(h_file, "/HydroScheme", H5P_DEFAULT, H5P_DEFAULT, @@ -926,6 +931,15 @@ void prepare_file(struct engine* e, const char* baseName, long long N_total[6], H5Gclose(h_grp); } + /* Print the gravity parameters */ + if (e->policy & engine_policy_cosmology) { + h_grp = + H5Gcreate(h_file, "/Cosmology", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + if (h_grp < 0) error("Error while creating cosmology group"); + cosmology_write_model(h_grp, e->cosmology); + H5Gclose(h_grp); + } + /* Print the runtime parameters */ h_grp = H5Gcreate(h_file, "/Parameters", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); diff --git a/src/profiler.c b/src/profiler.c index 62ba881a15a32de63dba3cce95feab79d595aa84..1dd1a41cc336942d17790e96c8f883d65e54a51f 100644 --- a/src/profiler.c +++ b/src/profiler.c @@ -147,7 +147,7 @@ void profiler_write_timing_info(const struct engine *e, ticks time, FILE *file) { fprintf(file, " %6d %14e %14e %10zu %10zu %10zu %21.3f\n", e->step, e->time, - e->timeStep, e->updates, e->g_updates, e->s_updates, + e->time_step, e->updates, e->g_updates, e->s_updates, clocks_from_ticks(time)); fflush(file); } diff --git a/src/proxy.c b/src/proxy.c index 10df8d191db992bdd26b39cd18e950f41c4690b3..ff7d12d92f1c90e1339113fcbde20847fb902283 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -55,10 +55,10 @@ void proxy_cells_exch1(struct proxy *p) { p->size_pcells_out += p->cells_out[k]->pcell_size; /* Send the number of pcells. */ - if (MPI_Isend(&p->size_pcells_out, 1, MPI_INT, p->nodeID, - p->mynodeID * proxy_tag_shift + proxy_tag_count, MPI_COMM_WORLD, - &p->req_cells_count_out) != MPI_SUCCESS) - error("Failed to isend nr of pcells."); + int err = MPI_Isend(&p->size_pcells_out, 1, MPI_INT, p->nodeID, + p->mynodeID * proxy_tag_shift + proxy_tag_count, + MPI_COMM_WORLD, &p->req_cells_count_out); + if (err != MPI_SUCCESS) mpi_error(err, "Failed to isend nr of pcells."); // message( "isent pcell count (%i) from node %i to node %i." , // p->size_pcells_out , p->mynodeID , p->nodeID ); fflush(stdout); @@ -74,19 +74,20 @@ void proxy_cells_exch1(struct proxy *p) { } /* Send the pcell buffer. */ - if (MPI_Isend(p->pcells_out, sizeof(struct pcell) * p->size_pcells_out, - MPI_BYTE, p->nodeID, - p->mynodeID * proxy_tag_shift + proxy_tag_cells, MPI_COMM_WORLD, - &p->req_cells_out) != MPI_SUCCESS) - error("Failed to pcell_out buffer."); + err = MPI_Isend(p->pcells_out, sizeof(struct pcell) * p->size_pcells_out, + MPI_BYTE, p->nodeID, + p->mynodeID * proxy_tag_shift + proxy_tag_cells, + MPI_COMM_WORLD, &p->req_cells_out); + + if (err != MPI_SUCCESS) mpi_error(err, "Failed to pcell_out buffer."); // message( "isent pcells (%i) from node %i to node %i." , p->size_pcells_out // , p->mynodeID , p->nodeID ); fflush(stdout); /* Receive the number of pcells. */ - if (MPI_Irecv(&p->size_pcells_in, 1, MPI_INT, p->nodeID, - p->nodeID * proxy_tag_shift + proxy_tag_count, MPI_COMM_WORLD, - &p->req_cells_count_in) != MPI_SUCCESS) - error("Failed to irecv nr of pcells."); + err = MPI_Irecv(&p->size_pcells_in, 1, MPI_INT, p->nodeID, + p->nodeID * proxy_tag_shift + proxy_tag_count, MPI_COMM_WORLD, + &p->req_cells_count_in); + if (err != MPI_SUCCESS) mpi_error(err, "Failed to irecv nr of pcells."); // message( "irecv pcells count on node %i from node %i." , p->mynodeID , // p->nodeID ); fflush(stdout); @@ -106,11 +107,12 @@ void proxy_cells_exch2(struct proxy *p) { error("Failed to allocate pcell_in buffer."); /* Receive the particle buffers. */ - if (MPI_Irecv(p->pcells_in, sizeof(struct pcell) * p->size_pcells_in, - MPI_BYTE, p->nodeID, - p->nodeID * proxy_tag_shift + proxy_tag_cells, MPI_COMM_WORLD, - &p->req_cells_in) != MPI_SUCCESS) - error("Failed to irecv part data."); + int err = MPI_Irecv(p->pcells_in, sizeof(struct pcell) * p->size_pcells_in, + MPI_BYTE, p->nodeID, + p->nodeID * proxy_tag_shift + proxy_tag_cells, + MPI_COMM_WORLD, &p->req_cells_in); + + if (err != MPI_SUCCESS) mpi_error(err, "Failed to irecv part data."); // message( "irecv pcells (%i) on node %i from node %i." , p->size_pcells_in , // p->mynodeID , p->nodeID ); fflush(stdout); diff --git a/src/runner.c b/src/runner.c index 0738267cf340da1039071f96f7e3d296c4169ef5..1b8f9a2fc84b08c590396f1251a6bf3c5cc3189e 100644 --- a/src/runner.c +++ b/src/runner.c @@ -186,14 +186,17 @@ void runner_do_grav_external(struct runner *r, struct cell *c, int timer) { */ void runner_do_cooling(struct runner *r, struct cell *c, int timer) { - struct part *restrict parts = c->parts; - struct xpart *restrict xparts = c->xparts; - const int count = c->count; const struct engine *e = r->e; + const struct cosmology *cosmo = e->cosmology; + const int with_cosmology = (e->policy & engine_policy_cosmology); const struct cooling_function_data *cooling_func = e->cooling_func; const struct phys_const *constants = e->physical_constants; const struct unit_system *us = e->internal_units; - const double timeBase = e->timeBase; + const double time_base = e->time_base; + const integertime_t ti_current = e->ti_current; + struct part *restrict parts = c->parts; + struct xpart *restrict xparts = c->xparts; + const int count = c->count; TIMER_TIC; @@ -215,9 +218,19 @@ void runner_do_cooling(struct runner *r, struct cell *c, int timer) { if (part_is_active(p, e)) { + double dt_cool; + if (with_cosmology) { + const integertime_t ti_step = get_integer_timestep(p->time_bin); + const integertime_t ti_begin = + get_integer_time_begin(ti_current + 1, p->time_bin); + dt_cool = + cosmology_get_delta_time(cosmo, ti_begin, ti_begin + ti_step); + } else { + dt_cool = get_timestep(p->time_bin, time_base); + } + /* Let's cool ! */ - const double dt = get_timestep(p->time_bin, timeBase); - cooling_cool_part(constants, us, cooling_func, p, xp, dt); + cooling_cool_part(constants, us, cosmo, cooling_func, p, xp, dt_cool); } } } @@ -641,6 +654,9 @@ void runner_do_ghost(struct runner *r, struct cell *c, int timer) { struct xpart *restrict xparts = c->xparts; const struct engine *e = r->e; const struct space *s = e->s; + const struct hydro_space *hs = &s->hs; + const struct cosmology *cosmo = e->cosmology; + const struct chemistry_data *chemistry = e->chemistry; const float hydro_h_max = e->hydro_properties->h_max; const float eps = e->hydro_properties->h_tolerance; const float hydro_eta_dim = @@ -701,8 +717,8 @@ void runner_do_ghost(struct runner *r, struct cell *c, int timer) { } else { /* Finish the density calculation */ - hydro_end_density(p); - chemistry_end_density(p, e->chemistry); + hydro_end_density(p, cosmo); + chemistry_end_density(p, chemistry, cosmo); /* Compute one step of the Newton-Raphson scheme */ const float n_sum = p->density.wcount * h_old_dim; @@ -739,11 +755,12 @@ void runner_do_ghost(struct runner *r, struct cell *c, int timer) { redo += 1; /* Re-initialise everything */ - hydro_init_part(p, &s->hs); - chemistry_init_part(p, e->chemistry); + hydro_init_part(p, hs); + chemistry_init_part(p, chemistry); /* Off we go ! */ continue; + } else { /* Ok, this particle is a lost cause... */ @@ -751,7 +768,7 @@ void runner_do_ghost(struct runner *r, struct cell *c, int timer) { /* Do some damage control if no neighbours at all were found */ if (p->density.wcount == kernel_root * kernel_norm) - hydro_part_has_no_neighbours(p, xp); + hydro_part_has_no_neighbours(p, xp, cosmo); } } @@ -760,7 +777,7 @@ void runner_do_ghost(struct runner *r, struct cell *c, int timer) { /* As of here, particle force variables will be set. */ /* Compute variables required for the force loop */ - hydro_prepare_force(p, xp); + hydro_prepare_force(p, xp, cosmo); /* The particle force values are now set. Do _NOT_ try to read any particle density variables! */ @@ -963,6 +980,8 @@ void runner_do_drift_gpart(struct runner *r, struct cell *c, int timer) { void runner_do_kick1(struct runner *r, struct cell *c, int timer) { const struct engine *e = r->e; + const struct cosmology *cosmo = e->cosmology; + const int with_cosmology = (e->policy & engine_policy_cosmology); struct part *restrict parts = c->parts; struct xpart *restrict xparts = c->xparts; struct gpart *restrict gparts = c->gparts; @@ -971,7 +990,7 @@ void runner_do_kick1(struct runner *r, struct cell *c, int timer) { const int gcount = c->gcount; const int scount = c->scount; const integertime_t ti_current = e->ti_current; - const double timeBase = e->timeBase; + const double time_base = e->time_base; TIMER_TIC; @@ -1009,22 +1028,31 @@ void runner_do_kick1(struct runner *r, struct cell *c, int timer) { ti_end, ti_begin, ti_step, p->time_bin, ti_current); #endif + /* Time interval for this half-kick */ + double dt_kick_grav, dt_kick_hydro, dt_kick_therm; + if (with_cosmology) { + dt_kick_hydro = cosmology_get_hydro_kick_factor( + cosmo, ti_begin, ti_begin + ti_step / 2); + dt_kick_grav = cosmology_get_grav_kick_factor(cosmo, ti_begin, + ti_begin + ti_step / 2); + dt_kick_therm = cosmology_get_therm_kick_factor( + cosmo, ti_begin, ti_begin + ti_step / 2); + } else { + dt_kick_hydro = (ti_step / 2) * time_base; + dt_kick_grav = (ti_step / 2) * time_base; + dt_kick_therm = (ti_step / 2) * time_base; + } + /* do the kick */ - kick_part(p, xp, ti_begin, ti_begin + ti_step / 2, timeBase); + kick_part(p, xp, dt_kick_hydro, dt_kick_grav, dt_kick_therm, ti_begin, + ti_begin + ti_step / 2); /* Update the accelerations to be used in the drift for hydro */ if (p->gpart != NULL) { - const float a_tot[3] = {p->a_hydro[0] + p->gpart->a_grav[0], - p->a_hydro[1] + p->gpart->a_grav[1], - p->a_hydro[2] + p->gpart->a_grav[2]}; - - p->a_hydro[0] = a_tot[0]; - p->a_hydro[1] = a_tot[1]; - p->a_hydro[2] = a_tot[2]; - p->gpart->a_grav[0] = a_tot[0]; - p->gpart->a_grav[1] = a_tot[1]; - p->gpart->a_grav[2] = a_tot[2]; + xp->a_grav[0] = p->gpart->a_grav[0]; + xp->a_grav[1] = p->gpart->a_grav[1]; + xp->a_grav[2] = p->gpart->a_grav[2]; } } } @@ -1053,8 +1081,17 @@ void runner_do_kick1(struct runner *r, struct cell *c, int timer) { ti_end, ti_begin, ti_step, gp->time_bin, ti_current); #endif + /* Time interval for this half-kick */ + double dt_kick_grav; + if (with_cosmology) { + dt_kick_grav = cosmology_get_grav_kick_factor(cosmo, ti_begin, + ti_begin + ti_step / 2); + } else { + dt_kick_grav = (ti_step / 2) * time_base; + } + /* do the kick */ - kick_gpart(gp, ti_begin, ti_begin + ti_step / 2, timeBase); + kick_gpart(gp, dt_kick_grav, ti_begin, ti_begin + ti_step / 2); } } @@ -1082,8 +1119,17 @@ void runner_do_kick1(struct runner *r, struct cell *c, int timer) { ti_end, ti_begin, ti_step, sp->time_bin, ti_current); #endif + /* Time interval for this half-kick */ + double dt_kick_grav; + if (with_cosmology) { + dt_kick_grav = cosmology_get_grav_kick_factor(cosmo, ti_begin, + ti_begin + ti_step / 2); + } else { + dt_kick_grav = (ti_step / 2) * time_base; + } + /* do the kick */ - kick_spart(sp, ti_begin, ti_begin + ti_step / 2, timeBase); + kick_spart(sp, dt_kick_grav, ti_begin, ti_begin + ti_step / 2); } } } @@ -1103,8 +1149,8 @@ void runner_do_kick1(struct runner *r, struct cell *c, int timer) { void runner_do_kick2(struct runner *r, struct cell *c, int timer) { const struct engine *e = r->e; - const integertime_t ti_current = e->ti_current; - const double timeBase = e->timeBase; + const struct cosmology *cosmo = e->cosmology; + const int with_cosmology = (e->policy & engine_policy_cosmology); const int count = c->count; const int gcount = c->gcount; const int scount = c->scount; @@ -1112,6 +1158,8 @@ void runner_do_kick2(struct runner *r, struct cell *c, int timer) { struct xpart *restrict xparts = c->xparts; struct gpart *restrict gparts = c->gparts; struct spart *restrict sparts = c->sparts; + const integertime_t ti_current = e->ti_current; + const double time_base = e->time_base; TIMER_TIC; @@ -1145,9 +1193,24 @@ void runner_do_kick2(struct runner *r, struct cell *c, int timer) { "time_bin=%d ti_current=%lld", ti_begin, ti_step, p->time_bin, ti_current); #endif + /* Time interval for this half-kick */ + double dt_kick_grav, dt_kick_hydro, dt_kick_therm; + if (with_cosmology) { + dt_kick_hydro = cosmology_get_hydro_kick_factor( + cosmo, ti_begin + ti_step / 2, ti_begin + ti_step); + dt_kick_grav = cosmology_get_grav_kick_factor( + cosmo, ti_begin + ti_step / 2, ti_begin + ti_step); + dt_kick_therm = cosmology_get_therm_kick_factor( + cosmo, ti_begin + ti_step / 2, ti_begin + ti_step); + } else { + dt_kick_hydro = (ti_step / 2) * time_base; + dt_kick_grav = (ti_step / 2) * time_base; + dt_kick_therm = (ti_step / 2) * time_base; + } /* Finish the time-step with a second half-kick */ - kick_part(p, xp, ti_begin + ti_step / 2, ti_begin + ti_step, timeBase); + kick_part(p, xp, dt_kick_hydro, dt_kick_grav, dt_kick_therm, + ti_begin + ti_step / 2, ti_begin + ti_step); #ifdef SWIFT_DEBUG_CHECKS /* Check that kick and the drift are synchronized */ @@ -1177,8 +1240,18 @@ void runner_do_kick2(struct runner *r, struct cell *c, int timer) { error("Particle in wrong time-bin"); #endif + /* Time interval for this half-kick */ + double dt_kick_grav; + if (with_cosmology) { + dt_kick_grav = cosmology_get_grav_kick_factor( + cosmo, ti_begin + ti_step / 2, ti_begin + ti_step); + } else { + dt_kick_grav = (ti_step / 2) * time_base; + } + /* Finish the time-step with a second half-kick */ - kick_gpart(gp, ti_begin + ti_step / 2, ti_begin + ti_step, timeBase); + kick_gpart(gp, dt_kick_grav, ti_begin + ti_step / 2, + ti_begin + ti_step); #ifdef SWIFT_DEBUG_CHECKS /* Check that kick and the drift are synchronized */ @@ -1209,8 +1282,18 @@ void runner_do_kick2(struct runner *r, struct cell *c, int timer) { error("Particle in wrong time-bin"); #endif + /* Time interval for this half-kick */ + double dt_kick_grav; + if (with_cosmology) { + dt_kick_grav = cosmology_get_grav_kick_factor( + cosmo, ti_begin + ti_step / 2, ti_begin + ti_step); + } else { + dt_kick_grav = (ti_step / 2) * time_base; + } + /* Finish the time-step with a second half-kick */ - kick_spart(sp, ti_begin + ti_step / 2, ti_begin + ti_step, timeBase); + kick_spart(sp, dt_kick_grav, ti_begin + ti_step / 2, + ti_begin + ti_step); #ifdef SWIFT_DEBUG_CHECKS /* Check that kick and the drift are synchronized */ @@ -1245,7 +1328,6 @@ void runner_do_timestep(struct runner *r, struct cell *c, int timer) { struct xpart *restrict xparts = c->xparts; struct gpart *restrict gparts = c->gparts; struct spart *restrict sparts = c->sparts; - const double timeBase = e->timeBase; TIMER_TIC; @@ -1292,10 +1374,6 @@ void runner_do_timestep(struct runner *r, struct cell *c, int timer) { p->time_bin = get_time_bin(ti_new_step); if (p->gpart != NULL) p->gpart->time_bin = p->time_bin; - /* Tell the particle what the new physical time step is */ - float dt = get_timestep(p->time_bin, timeBase); - hydro_timestep_extra(p, dt); - /* Number of updated particles */ updated++; if (p->gpart != NULL) g_updated++; @@ -1503,6 +1581,7 @@ void runner_do_timestep(struct runner *r, struct cell *c, int timer) { void runner_do_end_force(struct runner *r, struct cell *c, int timer) { const struct engine *e = r->e; + const struct cosmology *cosmo = e->cosmology; const int count = c->count; const int gcount = c->gcount; const int scount = c->scount; @@ -1531,7 +1610,7 @@ void runner_do_end_force(struct runner *r, struct cell *c, int timer) { if (part_is_active(p, e)) { /* Finish the force loop */ - hydro_end_force(p); + hydro_end_force(p, cosmo); } } diff --git a/src/runner_doiact.h b/src/runner_doiact.h index 038c27a950d8748512b484d8941e2f029edaaab0..2ea4cbf24576e50607379d8659106a57a1f80356 100644 --- a/src/runner_doiact.h +++ b/src/runner_doiact.h @@ -138,6 +138,7 @@ void DOPAIR1_NAIVE(struct runner *r, struct cell *restrict ci, struct cell *restrict cj) { const struct engine *e = r->e; + const struct cosmology *cosmo = e->cosmology; TIMER_TIC; @@ -149,6 +150,10 @@ void DOPAIR1_NAIVE(struct runner *r, struct cell *restrict ci, struct part *restrict parts_i = ci->parts; struct part *restrict parts_j = cj->parts; + /* Cosmological terms */ + const float a = cosmo->a; + const float H = cosmo->H; + /* Get the relative distance between the pairs, wrapping. */ double shift[3] = {0.0, 0.0, 0.0}; for (int k = 0; k < 3; k++) { @@ -197,9 +202,9 @@ void DOPAIR1_NAIVE(struct runner *r, struct cell *restrict ci, /* Hit or miss? */ if (r2 < hig2 && pi_active) { - IACT_NONSYM(r2, dx, hi, hj, pi, pj); + IACT_NONSYM(r2, dx, hi, hj, pi, pj, a, H); #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) - runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj); + runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj, a, H); #endif } if (r2 < hjg2 && pj_active) { @@ -208,9 +213,9 @@ void DOPAIR1_NAIVE(struct runner *r, struct cell *restrict ci, dx[1] = -dx[1]; dx[2] = -dx[2]; - IACT_NONSYM(r2, dx, hj, hi, pj, pi); + IACT_NONSYM(r2, dx, hj, hi, pj, pi, a, H); #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) - runner_iact_nonsym_chemistry(r2, dx, hj, hi, pj, pi); + runner_iact_nonsym_chemistry(r2, dx, hj, hi, pj, pi, a, H); #endif } @@ -233,6 +238,7 @@ void DOPAIR2_NAIVE(struct runner *r, struct cell *restrict ci, struct cell *restrict cj) { const struct engine *e = r->e; + const struct cosmology *cosmo = e->cosmology; TIMER_TIC; @@ -244,6 +250,10 @@ void DOPAIR2_NAIVE(struct runner *r, struct cell *restrict ci, struct part *restrict parts_i = ci->parts; struct part *restrict parts_j = cj->parts; + /* Cosmological terms */ + const float a = cosmo->a; + const float H = cosmo->H; + /* Get the relative distance between the pairs, wrapping. */ double shift[3] = {0.0, 0.0, 0.0}; for (int k = 0; k < 3; k++) { @@ -294,15 +304,15 @@ void DOPAIR2_NAIVE(struct runner *r, struct cell *restrict ci, if (pi_active && pj_active) { - IACT(r2, dx, hi, hj, pi, pj); + IACT(r2, dx, hi, hj, pi, pj, a, H); #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) - runner_iact_chemistry(r2, dx, hi, hj, pi, pj); + runner_iact_chemistry(r2, dx, hi, hj, pi, pj, a, H); #endif } else if (pi_active) { - IACT_NONSYM(r2, dx, hi, hj, pi, pj); + IACT_NONSYM(r2, dx, hi, hj, pi, pj, a, H); #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) - runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj); + runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj, a, H); #endif } else if (pj_active) { @@ -310,9 +320,9 @@ void DOPAIR2_NAIVE(struct runner *r, struct cell *restrict ci, dx[1] = -dx[1]; dx[2] = -dx[2]; - IACT_NONSYM(r2, dx, hj, hi, pj, pi); + IACT_NONSYM(r2, dx, hj, hi, pj, pi, a, H); #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) - runner_iact_nonsym_chemistry(r2, dx, hj, hi, pj, pi); + runner_iact_nonsym_chemistry(r2, dx, hj, hi, pj, pi, a, H); #endif } } @@ -333,12 +343,17 @@ void DOPAIR2_NAIVE(struct runner *r, struct cell *restrict ci, void DOSELF1_NAIVE(struct runner *r, struct cell *restrict c) { const struct engine *e = r->e; + const struct cosmology *cosmo = e->cosmology; TIMER_TIC; /* Anything to do here? */ if (!cell_is_active_hydro(c, e)) return; + /* Cosmological terms */ + const float a = cosmo->a; + const float H = cosmo->H; + const int count = c->count; struct part *restrict parts = c->parts; @@ -384,15 +399,15 @@ void DOSELF1_NAIVE(struct runner *r, struct cell *restrict c) { /* Hit or miss? */ if (doi && doj) { - IACT(r2, dx, hi, hj, pi, pj); + IACT(r2, dx, hi, hj, pi, pj, a, H); #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) - runner_iact_chemistry(r2, dx, hi, hj, pi, pj); + runner_iact_chemistry(r2, dx, hi, hj, pi, pj, a, H); #endif } else if (doi) { - IACT_NONSYM(r2, dx, hi, hj, pi, pj); + IACT_NONSYM(r2, dx, hi, hj, pi, pj, a, H); #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) - runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj); + runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj, a, H); #endif } else if (doj) { @@ -400,9 +415,9 @@ void DOSELF1_NAIVE(struct runner *r, struct cell *restrict c) { dx[1] = -dx[1]; dx[2] = -dx[2]; - IACT_NONSYM(r2, dx, hj, hi, pj, pi); + IACT_NONSYM(r2, dx, hj, hi, pj, pi, a, H); #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) - runner_iact_nonsym_chemistry(r2, dx, hj, hi, pj, pi); + runner_iact_nonsym_chemistry(r2, dx, hj, hi, pj, pi, a, H); #endif } } /* loop over the parts in cj. */ @@ -422,12 +437,17 @@ void DOSELF1_NAIVE(struct runner *r, struct cell *restrict c) { void DOSELF2_NAIVE(struct runner *r, struct cell *restrict c) { const struct engine *e = r->e; + const struct cosmology *cosmo = e->cosmology; TIMER_TIC; /* Anything to do here? */ if (!cell_is_active_hydro(c, e)) return; + /* Cosmological terms */ + const float a = cosmo->a; + const float H = cosmo->H; + const int count = c->count; struct part *restrict parts = c->parts; @@ -473,15 +493,15 @@ void DOSELF2_NAIVE(struct runner *r, struct cell *restrict c) { /* Hit or miss? */ if (doi && doj) { - IACT(r2, dx, hi, hj, pi, pj); + IACT(r2, dx, hi, hj, pi, pj, a, H); #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) - runner_iact_chemistry(r2, dx, hi, hj, pi, pj); + runner_iact_chemistry(r2, dx, hi, hj, pi, pj, a, H); #endif } else if (doi) { - IACT_NONSYM(r2, dx, hi, hj, pi, pj); + IACT_NONSYM(r2, dx, hi, hj, pi, pj, a, H); #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) - runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj); + runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj, a, H); #endif } else if (doj) { @@ -489,9 +509,9 @@ void DOSELF2_NAIVE(struct runner *r, struct cell *restrict c) { dx[1] = -dx[1]; dx[2] = -dx[2]; - IACT_NONSYM(r2, dx, hj, hi, pj, pi); + IACT_NONSYM(r2, dx, hj, hi, pj, pi, a, H); #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) - runner_iact_nonsym_chemistry(r2, dx, hj, hi, pj, pi); + runner_iact_nonsym_chemistry(r2, dx, hj, hi, pj, pi, a, H); #endif } } /* loop over the parts in cj. */ @@ -519,11 +539,18 @@ void DOPAIR_SUBSET_NAIVE(struct runner *r, struct cell *restrict ci, int count, struct cell *restrict cj, const double *shift) { + const struct engine *e = r->e; + const struct cosmology *cosmo = e->cosmology; + TIMER_TIC; const int count_j = cj->count; struct part *restrict parts_j = cj->parts; + /* Cosmological terms */ + const float a = cosmo->a; + const float H = cosmo->H; + /* Loop over the parts_i. */ for (int pid = 0; pid < count; pid++) { @@ -535,7 +562,6 @@ void DOPAIR_SUBSET_NAIVE(struct runner *r, struct cell *restrict ci, const float hig2 = hi * hi * kernel_gamma2; #ifdef SWIFT_DEBUG_CHECKS - const struct engine *e = r->e; if (!part_is_active(pi, e)) error("Trying to correct smoothing length of inactive particle !"); #endif @@ -565,9 +591,9 @@ void DOPAIR_SUBSET_NAIVE(struct runner *r, struct cell *restrict ci, /* Hit or miss? */ if (r2 < hig2) { - IACT_NONSYM(r2, dx, hi, pj->h, pi, pj); + IACT_NONSYM(r2, dx, hi, pj->h, pi, pj, a, H); #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) - runner_iact_nonsym_chemistry(r2, dx, hi, pj->h, pi, pj); + runner_iact_nonsym_chemistry(r2, dx, hi, pj->h, pi, pj, a, H); #endif } } /* loop over the parts in cj. */ @@ -595,11 +621,18 @@ void DOPAIR_SUBSET(struct runner *r, struct cell *restrict ci, struct cell *restrict cj, const int sid, const int flipped, const double *shift) { + const struct engine *e = r->e; + const struct cosmology *cosmo = e->cosmology; + TIMER_TIC; const int count_j = cj->count; struct part *restrict parts_j = cj->parts; + /* Cosmological terms */ + const float a = cosmo->a; + const float H = cosmo->H; + /* Pick-out the sorted lists. */ const struct entry *restrict sort_j = cj->sort[sid]; const float dxj = cj->dx_max_sort; @@ -636,7 +669,6 @@ void DOPAIR_SUBSET(struct runner *r, struct cell *restrict ci, const float r2 = dx[0] * dx[0] + dx[1] * dx[1] + dx[2] * dx[2]; #ifdef SWIFT_DEBUG_CHECKS - const struct engine *e = r->e; /* Check that particles have been drifted to the current time */ if (pi->ti_drift != e->ti_current) error("Particle pi not drifted to current time"); @@ -647,9 +679,9 @@ void DOPAIR_SUBSET(struct runner *r, struct cell *restrict ci, /* Hit or miss? */ if (r2 < hig2) { - IACT_NONSYM(r2, dx, hi, hj, pi, pj); + IACT_NONSYM(r2, dx, hi, hj, pi, pj, a, H); #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) - runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj); + runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj, a, H); #endif } } /* loop over the parts in cj. */ @@ -688,7 +720,6 @@ void DOPAIR_SUBSET(struct runner *r, struct cell *restrict ci, const float r2 = dx[0] * dx[0] + dx[1] * dx[1] + dx[2] * dx[2]; #ifdef SWIFT_DEBUG_CHECKS - const struct engine *e = r->e; /* Check that particles have been drifted to the current time */ if (pi->ti_drift != e->ti_current) error("Particle pi not drifted to current time"); @@ -699,9 +730,9 @@ void DOPAIR_SUBSET(struct runner *r, struct cell *restrict ci, /* Hit or miss? */ if (r2 < hig2) { - IACT_NONSYM(r2, dx, hi, hj, pi, pj); + IACT_NONSYM(r2, dx, hi, hj, pi, pj, a, H); #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) - runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj); + runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj, a, H); #endif } } /* loop over the parts in cj. */ @@ -782,12 +813,15 @@ void DOPAIR_SUBSET_BRANCH(struct runner *r, struct cell *restrict ci, void DOSELF_SUBSET(struct runner *r, struct cell *restrict ci, struct part *restrict parts, int *restrict ind, int count) { -#ifdef SWIFT_DEBUG_CHECKS const struct engine *e = r->e; -#endif + const struct cosmology *cosmo = e->cosmology; TIMER_TIC; + /* Cosmological terms */ + const float a = cosmo->a; + const float H = cosmo->H; + const int count_i = ci->count; struct part *restrict parts_j = ci->parts; @@ -811,6 +845,7 @@ void DOSELF_SUBSET(struct runner *r, struct cell *restrict ci, /* Get a pointer to the jth particle. */ struct part *restrict pj = &parts_j[pjd]; + const float hj = pj->h; /* Compute the pairwise distance. */ const float pjx[3] = {(float)(pj->x[0] - ci->loc[0]), @@ -830,9 +865,9 @@ void DOSELF_SUBSET(struct runner *r, struct cell *restrict ci, /* Hit or miss? */ if (r2 > 0.f && r2 < hig2) { - IACT_NONSYM(r2, dx, hi, pj->h, pi, pj); + IACT_NONSYM(r2, dx, hi, hj, pi, pj, a, H); #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) - runner_iact_nonsym_chemistry(r2, dx, hi, pj->h, pi, pj); + runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj, a, H); #endif } } /* loop over the parts in cj. */ @@ -875,6 +910,7 @@ void DOPAIR1(struct runner *r, struct cell *ci, struct cell *cj, const int sid, const double *shift) { const struct engine *restrict e = r->e; + const struct cosmology *restrict cosmo = e->cosmology; TIMER_TIC; @@ -907,6 +943,10 @@ void DOPAIR1(struct runner *r, struct cell *ci, struct cell *cj, const int sid, const double dj_min = sort_j[0].d; const float dx_max = (ci->dx_max_sort + cj->dx_max_sort); + /* Cosmological terms */ + const float a = cosmo->a; + const float H = cosmo->H; + if (cell_is_active_hydro(ci, e)) { /* Loop over the parts in ci. */ @@ -981,9 +1021,9 @@ void DOPAIR1(struct runner *r, struct cell *ci, struct cell *cj, const int sid, /* Hit or miss? */ if (r2 < hig2) { - IACT_NONSYM(r2, dx, hi, hj, pi, pj); + IACT_NONSYM(r2, dx, hi, hj, pi, pj, a, H); #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) - runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj); + runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj, a, H); #endif } } /* loop over the parts in cj. */ @@ -1064,9 +1104,9 @@ void DOPAIR1(struct runner *r, struct cell *ci, struct cell *cj, const int sid, /* Hit or miss? */ if (r2 < hjg2) { - IACT_NONSYM(r2, dx, hj, hi, pj, pi); + IACT_NONSYM(r2, dx, hj, hi, pj, pi, a, H); #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) - runner_iact_nonsym_chemistry(r2, dx, hj, hi, pj, pi); + runner_iact_nonsym_chemistry(r2, dx, hj, hi, pj, pi, a, H); #endif } } /* loop over the parts in ci. */ @@ -1170,7 +1210,8 @@ void DOPAIR1_BRANCH(struct runner *r, struct cell *ci, struct cell *cj) { void DOPAIR2(struct runner *r, struct cell *ci, struct cell *cj, const int sid, const double *shift) { - struct engine *restrict e = r->e; + const struct engine *restrict e = r->e; + const struct cosmology *restrict cosmo = e->cosmology; TIMER_TIC; @@ -1200,6 +1241,10 @@ void DOPAIR2(struct runner *r, struct cell *ci, struct cell *cj, const int sid, struct part *restrict parts_i = ci->parts; struct part *restrict parts_j = cj->parts; + /* Cosmological terms */ + const float a = cosmo->a; + const float H = cosmo->H; + /* Maximal displacement since last rebuild */ const double dx_max = (ci->dx_max_sort + cj->dx_max_sort); @@ -1330,9 +1375,9 @@ void DOPAIR2(struct runner *r, struct cell *ci, struct cell *cj, const int sid, /* Hit or miss? (note that we will do the other condition in the reverse loop) */ if (r2 < hig2) { - IACT_NONSYM(r2, dx, hj, hi, pj, pi); + IACT_NONSYM(r2, dx, hj, hi, pj, pi, a, H); #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) - runner_iact_nonsym_chemistry(r2, dx, hj, hi, pj, pi); + runner_iact_nonsym_chemistry(r2, dx, hj, hi, pj, pi, a, H); #endif } } /* loop over the active parts in cj. */ @@ -1395,14 +1440,14 @@ void DOPAIR2(struct runner *r, struct cell *ci, struct cell *cj, const int sid, /* Does pj need to be updated too? */ if (part_is_active(pj, e)) { - IACT(r2, dx, hi, hj, pi, pj); + IACT(r2, dx, hi, hj, pi, pj, a, H); #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) - runner_iact_chemistry(r2, dx, hi, hj, pi, pj); + runner_iact_chemistry(r2, dx, hi, hj, pi, pj, a, H); #endif } else { - IACT_NONSYM(r2, dx, hi, hj, pi, pj); + IACT_NONSYM(r2, dx, hi, hj, pi, pj, a, H); #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) - runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj); + runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj, a, H); #endif } } @@ -1490,9 +1535,9 @@ void DOPAIR2(struct runner *r, struct cell *ci, struct cell *cj, const int sid, /* Hit or miss? (note that we must avoid the r2 < hig2 cases we already processed) */ if (r2 < hjg2 && r2 >= hig2) { - IACT_NONSYM(r2, dx, hi, hj, pi, pj); + IACT_NONSYM(r2, dx, hi, hj, pi, pj, a, H); #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) - runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj); + runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj, a, H); #endif } } /* loop over the active parts in ci. */ @@ -1558,14 +1603,14 @@ void DOPAIR2(struct runner *r, struct cell *ci, struct cell *cj, const int sid, /* Does pi need to be updated too? */ if (part_is_active(pi, e)) { - IACT(r2, dx, hj, hi, pj, pi); + IACT(r2, dx, hj, hi, pj, pi, a, H); #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) - runner_iact_chemistry(r2, dx, hj, hi, pj, pi); + runner_iact_chemistry(r2, dx, hj, hi, pj, pi, a, H); #endif } else { - IACT_NONSYM(r2, dx, hj, hi, pj, pi); + IACT_NONSYM(r2, dx, hj, hi, pj, pi, a, H); #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) - runner_iact_nonsym_chemistry(r2, dx, hj, hi, pj, pi); + runner_iact_nonsym_chemistry(r2, dx, hj, hi, pj, pi, a, H); #endif } } @@ -1673,6 +1718,7 @@ void DOPAIR2_BRANCH(struct runner *r, struct cell *ci, struct cell *cj) { void DOSELF1(struct runner *r, struct cell *restrict c) { const struct engine *e = r->e; + const struct cosmology *cosmo = e->cosmology; TIMER_TIC; @@ -1691,6 +1737,10 @@ void DOSELF1(struct runner *r, struct cell *restrict c) { countdt += 1; } + /* Cosmological terms */ + const float a = cosmo->a; + const float H = cosmo->H; + /* Loop over the particles in the cell. */ for (int pid = 0; pid < count; pid++) { @@ -1732,9 +1782,9 @@ void DOSELF1(struct runner *r, struct cell *restrict c) { /* Hit or miss? */ if (r2 < hj * hj * kernel_gamma2) { - IACT_NONSYM(r2, dx, hj, hi, pj, pi); + IACT_NONSYM(r2, dx, hj, hi, pj, pi, a, H); #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) - runner_iact_nonsym_chemistry(r2, dx, hj, hi, pj, pi); + runner_iact_nonsym_chemistry(r2, dx, hj, hi, pj, pi, a, H); #endif } } /* loop over all other particles. */ @@ -1776,22 +1826,22 @@ void DOSELF1(struct runner *r, struct cell *restrict c) { /* Which parts need to be updated? */ if (r2 < hig2 && doj) { - IACT(r2, dx, hi, hj, pi, pj); + IACT(r2, dx, hi, hj, pi, pj, a, H); #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) - runner_iact_chemistry(r2, dx, hi, hj, pi, pj); + runner_iact_chemistry(r2, dx, hi, hj, pi, pj, a, H); #endif } else if (!doj) { - IACT_NONSYM(r2, dx, hi, hj, pi, pj); + IACT_NONSYM(r2, dx, hi, hj, pi, pj, a, H); #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) - runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj); + runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj, a, H); #endif } else { dx[0] = -dx[0]; dx[1] = -dx[1]; dx[2] = -dx[2]; - IACT_NONSYM(r2, dx, hj, hi, pj, pi); + IACT_NONSYM(r2, dx, hj, hi, pj, pi, a, H); #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) - runner_iact_nonsym_chemistry(r2, dx, hj, hi, pj, pi); + runner_iact_nonsym_chemistry(r2, dx, hj, hi, pj, pi, a, H); #endif } } @@ -1845,6 +1895,7 @@ void DOSELF1_BRANCH(struct runner *r, struct cell *c) { void DOSELF2(struct runner *r, struct cell *restrict c) { const struct engine *e = r->e; + const struct cosmology *cosmo = e->cosmology; TIMER_TIC; @@ -1863,6 +1914,10 @@ void DOSELF2(struct runner *r, struct cell *restrict c) { countdt += 1; } + /* Cosmological terms */ + const float a = cosmo->a; + const float H = cosmo->H; + /* Loop over the particles in the cell. */ for (int pid = 0; pid < count; pid++) { @@ -1904,9 +1959,9 @@ void DOSELF2(struct runner *r, struct cell *restrict c) { /* Hit or miss? */ if (r2 < hig2 || r2 < hj * hj * kernel_gamma2) { - IACT_NONSYM(r2, dx, hj, hi, pj, pi); + IACT_NONSYM(r2, dx, hj, hi, pj, pi, a, H); #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) - runner_iact_nonsym_chemistry(r2, dx, hj, hi, pj, pi); + runner_iact_nonsym_chemistry(r2, dx, hj, hi, pj, pi, a, H); #endif } } /* loop over all other particles. */ @@ -1946,14 +2001,14 @@ void DOSELF2(struct runner *r, struct cell *restrict c) { /* Does pj need to be updated too? */ if (part_is_active(pj, e)) { - IACT(r2, dx, hi, hj, pi, pj); + IACT(r2, dx, hi, hj, pi, pj, a, H); #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) - runner_iact_chemistry(r2, dx, hi, hj, pi, pj); + runner_iact_chemistry(r2, dx, hi, hj, pi, pj, a, H); #endif } else { - IACT_NONSYM(r2, dx, hi, hj, pi, pj); + IACT_NONSYM(r2, dx, hi, hj, pi, pj, a, H); #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) - runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj); + runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj, a, H); #endif } } diff --git a/src/serial_io.c b/src/serial_io.c index 047c3d3f88ba56eca8720fa06bba9bf5c3db07b7..3e62bd7fda99ed7703a4fe67340d5a03e5dc45b8 100644 --- a/src/serial_io.c +++ b/src/serial_io.c @@ -778,6 +778,8 @@ void write_output_serial(struct engine* e, const char* baseName, io_write_attribute(h_grp, "Time", DOUBLE, &dblTime, 1); int dimension = (int)hydro_dimension; io_write_attribute(h_grp, "Dimension", INT, &dimension, 1); + io_write_attribute(h_grp, "Redshift", DOUBLE, &e->cosmology->z, 1); + io_write_attribute(h_grp, "Scale-factor", DOUBLE, &e->cosmology->a, 1); /* GADGET-2 legacy values */ /* Number of particles of each type */ @@ -807,6 +809,9 @@ void write_output_serial(struct engine* e, const char* baseName, /* Print the code version */ io_write_code_description(h_file); + /* Print the run's policy */ + io_write_engine_policy(h_file, e); + /* Print the SPH parameters */ if (e->policy & engine_policy_hydro) { h_grp = H5Gcreate(h_file, "/HydroScheme", H5P_DEFAULT, H5P_DEFAULT, @@ -834,6 +839,15 @@ void write_output_serial(struct engine* e, const char* baseName, H5Gclose(h_grp); } + /* Print the cosmological model */ + if (e->policy & engine_policy_cosmology) { + h_grp = H5Gcreate(h_file, "/Cosmology", H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT); + if (h_grp < 0) error("Error while creating cosmology group"); + cosmology_write_model(h_grp, e->cosmology); + H5Gclose(h_grp); + } + /* Print the runtime parameters */ h_grp = H5Gcreate(h_file, "/Parameters", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); diff --git a/src/single_io.c b/src/single_io.c index 4ba85c2b1b6970469b17ac2d475e297b848604c6..caa39e4a7cf583b210d3e9322abcd53c332cfe70 100644 --- a/src/single_io.c +++ b/src/single_io.c @@ -630,6 +630,8 @@ void write_output_single(struct engine* e, const char* baseName, io_write_attribute(h_grp, "Time", DOUBLE, &dblTime, 1); int dimension = (int)hydro_dimension; io_write_attribute(h_grp, "Dimension", INT, &dimension, 1); + io_write_attribute(h_grp, "Redshift", DOUBLE, &e->cosmology->z, 1); + io_write_attribute(h_grp, "Scale-factor", DOUBLE, &e->cosmology->a, 1); /* GADGET-2 legacy values */ /* Number of particles of each type */ @@ -659,6 +661,9 @@ void write_output_single(struct engine* e, const char* baseName, /* Print the code version */ io_write_code_description(h_file); + /* Print the run's policy */ + io_write_engine_policy(h_file, e); + /* Print the SPH parameters */ if (e->policy & engine_policy_hydro) { h_grp = H5Gcreate(h_file, "/HydroScheme", H5P_DEFAULT, H5P_DEFAULT, @@ -686,6 +691,15 @@ void write_output_single(struct engine* e, const char* baseName, H5Gclose(h_grp); } + /* Print the cosmological model */ + if (e->policy & engine_policy_cosmology) { + h_grp = + H5Gcreate(h_file, "/Cosmology", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + if (h_grp < 0) error("Error while creating cosmology group"); + cosmology_write_model(h_grp, e->cosmology); + H5Gclose(h_grp); + } + /* Print the runtime parameters */ h_grp = H5Gcreate(h_file, "/Parameters", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); diff --git a/src/statistics.c b/src/statistics.c index ed5e0f743411d501c11c7ada35d82d77c2398a3d..ed3197fbd0538394bb1c40d834c16e174a410068 100644 --- a/src/statistics.c +++ b/src/statistics.c @@ -105,17 +105,24 @@ void stats_collect_part_mapper(void *map_data, int nr_parts, void *extra_data) { /* Unpack the data */ const struct index_data *data = (struct index_data *)extra_data; const struct space *s = data->s; + const struct engine *e = s->e; + const int with_cosmology = (e->policy & engine_policy_cosmology); + const integertime_t ti_current = e->ti_current; + const double time_base = e->time_base; + const double time = e->time; const struct part *restrict parts = (struct part *)map_data; const struct xpart *restrict xparts = s->xparts + (ptrdiff_t)(parts - s->parts); - const integertime_t ti_current = s->e->ti_current; - const double timeBase = s->e->timeBase; - const double time = s->e->time; 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; + /* Some information about the physical model */ + const struct external_potential *potential = e->external_potential; + const struct phys_const *phys_const = e->physical_constants; + const struct cosmology *cosmo = e->cosmology; + + /* Some constants from cosmology */ + const float a_inv = cosmo->a_inv; + const float a_inv2 = a_inv * a_inv; /* Local accumulator */ struct statistics stats; @@ -130,17 +137,35 @@ void stats_collect_part_mapper(void *map_data, int nr_parts, void *extra_data) { const struct gpart *gp = (p->gpart != NULL) ? gp = p->gpart : NULL; /* Get useful time variables */ - const integertime_t ti_begin = + const integertime_t ti_beg = get_integer_time_begin(ti_current, p->time_bin); const integertime_t ti_end = get_integer_time_end(ti_current, p->time_bin); - const float dt = (ti_current - ((ti_begin + ti_end) / 2)) * timeBase; + + /* Get time-step since the last kick */ + float dt_kick_grav, dt_kick_hydro, dt_therm; + if (with_cosmology) { + dt_kick_grav = cosmology_get_grav_kick_factor(cosmo, ti_beg, ti_current); + dt_kick_grav -= + cosmology_get_grav_kick_factor(cosmo, ti_beg, (ti_beg + ti_end) / 2); + dt_kick_hydro = + cosmology_get_hydro_kick_factor(cosmo, ti_beg, ti_current); + dt_kick_hydro -= + cosmology_get_hydro_kick_factor(cosmo, ti_beg, (ti_beg + ti_end) / 2); + dt_therm = cosmology_get_therm_kick_factor(cosmo, ti_beg, ti_current); + dt_therm -= + cosmology_get_therm_kick_factor(cosmo, ti_beg, (ti_beg + ti_end) / 2); + } else { + dt_kick_grav = (ti_current - ((ti_beg + ti_end) / 2)) * time_base; + dt_kick_hydro = (ti_current - ((ti_beg + ti_end) / 2)) * time_base; + dt_therm = (ti_current - ((ti_beg + ti_end) / 2)) * time_base; + } float v[3]; - hydro_get_drifted_velocities(p, xp, dt, v); + hydro_get_drifted_velocities(p, xp, dt_kick_hydro, dt_kick_grav, v); const double x[3] = {p->x[0], p->x[1], p->x[2]}; const float m = hydro_get_mass(p); - const float entropy = hydro_get_entropy(p); - const float u_inter = hydro_get_internal_energy(p); + const float entropy = hydro_get_physical_entropy(p, cosmo); + const float u_inter = hydro_get_physical_internal_energy(p, cosmo); /* Collect mass */ stats.mass += m; @@ -161,11 +186,12 @@ void stats_collect_part_mapper(void *map_data, int nr_parts, void *extra_data) { stats.ang_mom[2] += m * (x[0] * v[1] - x[1] * v[0]); /* Collect energies. */ - stats.E_kin += 0.5f * m * (v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); + stats.E_kin += 0.5f * m * (v[0] * v[0] + v[1] * v[1] + v[2] * v[2]) * + a_inv2; /* 1/2 m a^2 \dot{r}^2 */ stats.E_int += m * u_inter; stats.E_rad += cooling_get_radiated_energy(xp); if (gp != NULL) { - stats.E_pot_self += m * gravity_get_potential(gp); + stats.E_pot_self += m * gravity_get_potential(gp) * a_inv; stats.E_pot_ext += m * external_gravity_get_potential_energy( time, potential, phys_const, gp); } @@ -192,15 +218,22 @@ void stats_collect_gpart_mapper(void *map_data, int nr_gparts, /* Unpack the data */ const struct index_data *data = (struct index_data *)extra_data; const struct space *s = data->s; + const struct engine *e = s->e; + const int with_cosmology = (e->policy & engine_policy_cosmology); + const integertime_t ti_current = e->ti_current; + const double time_base = e->time_base; + const double time = e->time; const struct gpart *restrict gparts = (struct gpart *)map_data; - const integertime_t ti_current = s->e->ti_current; - const double timeBase = s->e->timeBase; - const double time = s->e->time; 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; + /* Some information about the physical model */ + const struct external_potential *potential = e->external_potential; + const struct phys_const *phys_const = e->physical_constants; + const struct cosmology *cosmo = e->cosmology; + + /* Some constants from cosmology */ + const float a_inv = cosmo->a_inv; + const float a_inv2 = a_inv * a_inv; /* Local accumulator */ struct statistics stats; @@ -216,15 +249,24 @@ void stats_collect_gpart_mapper(void *map_data, int nr_gparts, if (gp->id_or_neg_offset < 0) continue; /* Get useful variables */ - const integertime_t ti_begin = + const integertime_t ti_beg = get_integer_time_begin(ti_current, gp->time_bin); const integertime_t ti_end = get_integer_time_end(ti_current, gp->time_bin); - const float dt = (ti_current - ((ti_begin + ti_end) / 2)) * timeBase; + + /* Get time-step since the last kick */ + float dt_kick_grav; + if (with_cosmology) { + dt_kick_grav = cosmology_get_grav_kick_factor(cosmo, ti_beg, ti_current); + dt_kick_grav -= + cosmology_get_grav_kick_factor(cosmo, ti_beg, (ti_beg + ti_end) / 2); + } else { + dt_kick_grav = (ti_current - ((ti_beg + ti_end) / 2)) * time_base; + } /* Extrapolate velocities */ - const float v[3] = {gp->v_full[0] + gp->a_grav[0] * dt, - gp->v_full[1] + gp->a_grav[1] * dt, - gp->v_full[2] + gp->a_grav[2] * dt}; + const float v[3] = {gp->v_full[0] + gp->a_grav[0] * dt_kick_grav, + gp->v_full[1] + gp->a_grav[1] * dt_kick_grav, + gp->v_full[2] + gp->a_grav[2] * dt_kick_grav}; const float m = gravity_get_mass(gp); const double x[3] = {gp->x[0], gp->x[1], gp->x[2]}; @@ -248,8 +290,9 @@ void stats_collect_gpart_mapper(void *map_data, int nr_gparts, stats.ang_mom[2] += m * (x[0] * v[1] - x[1] * v[0]); /* Collect energies. */ - stats.E_kin += 0.5f * m * (v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); - stats.E_pot_self += m * gravity_get_potential(gp); + stats.E_kin += 0.5f * m * (v[0] * v[0] + v[1] * v[1] + v[2] * v[2]) * + a_inv2; /* 1/2 m a^2 \dot{r}^2 */ + stats.E_pot_self += m * gravity_get_potential(gp) * a_inv; stats.E_pot_ext += m * external_gravity_get_potential_energy( time, potential, phys_const, gp); } diff --git a/src/swift.h b/src/swift.h index bd3c7fd5741b8c93f2931e1ec0f148d659249752..7691720942f32d29d3269ccdd7adbe8db32280bf 100644 --- a/src/swift.h +++ b/src/swift.h @@ -31,6 +31,7 @@ #include "clocks.h" #include "const.h" #include "cooling.h" +#include "cosmology.h" #include "cycle.h" #include "debug.h" #include "dump.h" diff --git a/src/timeline.h b/src/timeline.h index 0f38ff3e9421c122b61caf74290c170b62b2dd92..66b2c9456fb9e2e9f8b36272a9bbf3b7764523fc 100644 --- a/src/timeline.h +++ b/src/timeline.h @@ -40,6 +40,12 @@ typedef char timebin_t; /*! Fictious time-bin to hold inhibited particles */ #define time_bin_inhibited (num_time_bins + 2) +/*! Fictitious time-bin for particles not awaken */ +#define time_bin_not_awake (0) + +/*! Fictitious time-bin for particles woken up */ +#define time_bin_awake (-1) + /** * @brief Returns the integer time interval corresponding to a time bin * @@ -122,4 +128,17 @@ static INLINE timebin_t get_max_active_bin(integertime_t time) { return bin; } +/** + * @brief Returns the lowest active time bin at a given point on the time line. + * + * @param ti_current The current point on the time line. + * @param ti_old The last synchronisation point on the time line. + */ +static INLINE timebin_t get_min_active_bin(integertime_t ti_current, + integertime_t ti_old) { + + const timebin_t min_bin = get_max_active_bin(ti_current - ti_old); + return (ti_old > 0) ? min_bin : (min_bin - 1); +} + #endif /* SWIFT_TIMELINE_H */ diff --git a/src/timestep.h b/src/timestep.h index 309a0b1407d3ee634711e07fa9b9f0a04a25ba1c..4e715e1f15dd525d89b44ae3e716278cebe28a8d 100644 --- a/src/timestep.h +++ b/src/timestep.h @@ -33,14 +33,14 @@ * @param new_dt The time-step to convert. * @param old_bin The old time bin. * @param ti_current The current time on the integer time-line. - * @param timeBase_inv The inverse of the system's minimal time-step. + * @param time_base_inv The inverse of the system's minimal time-step. */ __attribute__((always_inline)) INLINE static integertime_t make_integer_timestep(float new_dt, timebin_t old_bin, integertime_t ti_current, - double timeBase_inv) { + double time_base_inv) { /* Convert to integer time */ - integertime_t new_dti = (integertime_t)(new_dt * timeBase_inv); + integertime_t new_dti = (integertime_t)(new_dt * time_base_inv); /* Current time-step */ integertime_t current_dti = get_integer_timestep(old_bin); @@ -51,7 +51,7 @@ make_integer_timestep(float new_dt, timebin_t old_bin, integertime_t ti_current, /* Put this timestep on the time line */ integertime_t dti_timeline = max_nr_timesteps; - while (new_dti < dti_timeline) dti_timeline /= 2LL; + while (new_dti < dti_timeline) dti_timeline /= ((integertime_t)2); new_dti = dti_timeline; /* Make sure we are allowed to increase the timestep size */ @@ -70,16 +70,22 @@ make_integer_timestep(float new_dt, timebin_t old_bin, integertime_t ti_current, __attribute__((always_inline)) INLINE static integertime_t get_gpart_timestep( const struct gpart *restrict gp, const struct engine *restrict e) { - float new_dt = FLT_MAX; + float new_dt_self = FLT_MAX, new_dt_ext = FLT_MAX; if (e->policy & engine_policy_external_gravity) - new_dt = - min(new_dt, external_gravity_timestep(e->time, e->external_potential, - e->physical_constants, gp)); + new_dt_ext = external_gravity_timestep(e->time, e->external_potential, + e->physical_constants, gp); + const float a_hydro[3] = {0.f, 0.f, 0.f}; if (e->policy & engine_policy_self_gravity) - new_dt = - min(new_dt, gravity_compute_timestep_self(gp, e->gravity_properties)); + new_dt_ext = gravity_compute_timestep_self( + gp, a_hydro, e->gravity_properties, e->cosmology); + + /* Take the minimum of all */ + float new_dt = min(new_dt_self, new_dt_ext); + + /* Apply cosmology correction */ + new_dt *= e->cosmology->time_step_factor; /* Limit timestep within the allowed range */ new_dt = min(new_dt, e->dt_max); @@ -89,7 +95,7 @@ __attribute__((always_inline)) INLINE static integertime_t get_gpart_timestep( /* Convert to integer time */ const integertime_t new_dti = make_integer_timestep( - new_dt, gp->time_bin, e->ti_current, e->timeBase_inv); + new_dt, gp->time_bin, e->ti_current, e->time_base_inv); return new_dti; } @@ -106,26 +112,29 @@ __attribute__((always_inline)) INLINE static integertime_t get_part_timestep( const struct engine *restrict e) { /* Compute the next timestep (hydro condition) */ - const float new_dt_hydro = hydro_compute_timestep(p, xp, e->hydro_properties); + const float new_dt_hydro = + hydro_compute_timestep(p, xp, e->hydro_properties, e->cosmology); /* Compute the next timestep (cooling condition) */ float new_dt_cooling = FLT_MAX; if (e->policy & engine_policy_cooling) new_dt_cooling = cooling_timestep(e->cooling_func, e->physical_constants, - e->internal_units, p); + e->cosmology, e->internal_units, p); /* Compute the next timestep (gravity condition) */ - float new_dt_grav = FLT_MAX; + float new_dt_grav = FLT_MAX, new_dt_self_grav = FLT_MAX, + new_dt_ext_grav = FLT_MAX; if (p->gpart != NULL) { if (e->policy & engine_policy_external_gravity) - new_dt_grav = min(new_dt_grav, external_gravity_timestep( - e->time, e->external_potential, - e->physical_constants, p->gpart)); + new_dt_ext_grav = external_gravity_timestep( + e->time, e->external_potential, e->physical_constants, p->gpart); if (e->policy & engine_policy_self_gravity) - new_dt_grav = min(new_dt_grav, gravity_compute_timestep_self( - p->gpart, e->gravity_properties)); + new_dt_self_grav = gravity_compute_timestep_self( + p->gpart, p->a_hydro, e->gravity_properties, e->cosmology); + + new_dt_grav = min(new_dt_self_grav, new_dt_ext_grav); } /* Final time-step is minimum of hydro and gravity */ @@ -139,6 +148,9 @@ __attribute__((always_inline)) INLINE static integertime_t get_part_timestep( new_dt = min(new_dt, dt_h_change); + /* Apply cosmology correction (H==1 if non-cosmological) */ + new_dt *= e->cosmology->time_step_factor; + /* Limit timestep within the allowed range */ new_dt = min(new_dt, e->dt_max); if (new_dt < e->dt_min) @@ -147,7 +159,7 @@ __attribute__((always_inline)) INLINE static integertime_t get_part_timestep( /* Convert to integer time */ const integertime_t new_dti = make_integer_timestep( - new_dt, p->time_bin, e->ti_current, e->timeBase_inv); + new_dt, p->time_bin, e->ti_current, e->time_base_inv); return new_dti; } @@ -161,16 +173,26 @@ __attribute__((always_inline)) INLINE static integertime_t get_part_timestep( __attribute__((always_inline)) INLINE static integertime_t get_spart_timestep( const struct spart *restrict sp, const struct engine *restrict e) { - float new_dt = star_compute_timestep(sp); + /* Stellar time-step */ + float new_dt_star = star_compute_timestep(sp); + + /* Gravity time-step */ + float new_dt_self = FLT_MAX, new_dt_ext = FLT_MAX; if (e->policy & engine_policy_external_gravity) - new_dt = min(new_dt, - external_gravity_timestep(e->time, e->external_potential, - e->physical_constants, sp->gpart)); + new_dt_ext = external_gravity_timestep(e->time, e->external_potential, + e->physical_constants, sp->gpart); + const float a_hydro[3] = {0.f, 0.f, 0.f}; if (e->policy & engine_policy_self_gravity) - new_dt = min(new_dt, gravity_compute_timestep_self(sp->gpart, - e->gravity_properties)); + new_dt_self = gravity_compute_timestep_self( + sp->gpart, a_hydro, e->gravity_properties, e->cosmology); + + /* Take the minimum of all */ + float new_dt = min3(new_dt_star, new_dt_self, new_dt_ext); + + /* Apply cosmology correction (H==1 if non-cosmological) */ + new_dt *= e->cosmology->time_step_factor; /* Limit timestep within the allowed range */ new_dt = min(new_dt, e->dt_max); @@ -180,7 +202,7 @@ __attribute__((always_inline)) INLINE static integertime_t get_spart_timestep( /* Convert to integer time */ const integertime_t new_dti = make_integer_timestep( - new_dt, sp->time_bin, e->ti_current, e->timeBase_inv); + new_dt, sp->time_bin, e->ti_current, e->time_base_inv); return new_dti; } diff --git a/src/tools.c b/src/tools.c index 89d89e62ea092ba6c6ec661e423d3e0ee44eb7fe..4653c2ef799f9256bd459d9dcc1cf5698a7db6f4 100644 --- a/src/tools.c +++ b/src/tools.c @@ -27,6 +27,8 @@ #include <stddef.h> #include <stdio.h> #include <stdlib.h> +#include <sys/resource.h> +#include <sys/time.h> /* This object's header. */ #include "tools.h" @@ -34,6 +36,7 @@ /* Local includes. */ #include "active.h" #include "cell.h" +#include "cosmology.h" #include "error.h" #include "gravity.h" #include "hydro.h" @@ -73,6 +76,7 @@ void pairs_n2(double *dim, struct part *restrict parts, int N, int periodic) { // double maxratio = 1.0; double r2, dx[3], rho = 0.0; double rho_max = 0.0, rho_min = 100; + float a = 1.f, H = 0.f; /* Loop over all particle pairs. */ for (j = 0; j < N; j++) { @@ -93,7 +97,7 @@ void pairs_n2(double *dim, struct part *restrict parts, int N, int periodic) { r2 = dx[0] * dx[0] + dx[1] * dx[1] + dx[2] * dx[2]; if (r2 < parts[j].h * parts[j].h || r2 < parts[k].h * parts[k].h) { runner_iact_density(r2, NULL, parts[j].h, parts[k].h, &parts[j], - &parts[k]); + &parts[k], a, H); /* if ( parts[j].h / parts[k].h > maxratio ) { maxratio = parts[j].h / parts[k].h; @@ -132,12 +136,10 @@ void pairs_n2(double *dim, struct part *restrict parts, int N, int periodic) { void pairs_single_density(double *dim, long long int pid, struct part *restrict parts, int N, int periodic) { int i, k; - // int mj, mk; - // double maxratio = 1.0; double r2, dx[3]; float fdx[3]; struct part p; - // double ih = 12.0/6.25; + float a = 1.f, H = 0.f; /* Find "our" part. */ for (k = 0; k < N && parts[k].id != pid; k++) @@ -163,7 +165,7 @@ void pairs_single_density(double *dim, long long int pid, } r2 = fdx[0] * fdx[0] + fdx[1] * fdx[1] + fdx[2] * fdx[2]; if (r2 < p.h * p.h) { - runner_iact_nonsym_density(r2, fdx, p.h, parts[k].h, &p, &parts[k]); + runner_iact_nonsym_density(r2, fdx, p.h, parts[k].h, &p, &parts[k], a, H); /* printf( "pairs_simple: interacting particles %lli [%i,%i,%i] and %lli [%i,%i,%i], r=%e.\n" , pid , (int)(p.x[0]*ih) , (int)(p.x[1]*ih) , (int)(p.x[2]*ih) , @@ -185,6 +187,7 @@ void pairs_all_density(struct runner *r, struct cell *ci, struct cell *cj) { struct part *pi, *pj; const double dim[3] = {r->e->s->dim[0], r->e->s->dim[1], r->e->s->dim[2]}; const struct engine *e = r->e; + float a = 1.f, H = 0.f; /* Implements a double-for loop and checks every interaction */ for (int i = 0; i < ci->count; ++i) { @@ -212,7 +215,7 @@ void pairs_all_density(struct runner *r, struct cell *ci, struct cell *cj) { if (r2 < hig2) { /* Interact */ - runner_iact_nonsym_density(r2, dx, hi, pj->h, pi, pj); + runner_iact_nonsym_density(r2, dx, hi, pj->h, pi, pj, a, H); } } } @@ -243,7 +246,7 @@ void pairs_all_density(struct runner *r, struct cell *ci, struct cell *cj) { if (r2 < hjg2) { /* Interact */ - runner_iact_nonsym_density(r2, dx, hj, pi->h, pj, pi); + runner_iact_nonsym_density(r2, dx, hj, pi->h, pj, pi, a, H); } } } @@ -255,6 +258,7 @@ void pairs_all_force(struct runner *r, struct cell *ci, struct cell *cj) { struct part *pi, *pj; const double dim[3] = {r->e->s->dim[0], r->e->s->dim[1], r->e->s->dim[2]}; const struct engine *e = r->e; + float a = 1.f, H = 0.f; /* Implements a double-for loop and checks every interaction */ for (int i = 0; i < ci->count; ++i) { @@ -284,7 +288,7 @@ void pairs_all_force(struct runner *r, struct cell *ci, struct cell *cj) { if (r2 < hig2 || r2 < hjg2) { /* Interact */ - runner_iact_nonsym_force(r2, dx, hi, hj, pi, pj); + runner_iact_nonsym_force(r2, dx, hi, hj, pi, pj, a, H); } } } @@ -317,7 +321,7 @@ void pairs_all_force(struct runner *r, struct cell *ci, struct cell *cj) { if (r2 < hjg2 || r2 < hig2) { /* Interact */ - runner_iact_nonsym_force(r2, dx, hj, pi->h, pj, pi); + runner_iact_nonsym_force(r2, dx, hj, pi->h, pj, pi, a, H); } } } @@ -327,6 +331,7 @@ void self_all_density(struct runner *r, struct cell *ci) { float r2, hi, hj, hig2, hjg2, dxi[3]; //, dxj[3]; struct part *pi, *pj; const struct engine *e = r->e; + float a = 1.f, H = 0.f; /* Implements a double-for loop and checks every interaction */ for (int i = 0; i < ci->count; ++i) { @@ -354,7 +359,7 @@ void self_all_density(struct runner *r, struct cell *ci) { if (r2 < hig2 && part_is_active(pi, e)) { /* Interact */ - runner_iact_nonsym_density(r2, dxi, hi, hj, pi, pj); + runner_iact_nonsym_density(r2, dxi, hi, hj, pi, pj, a, H); } /* Hit or miss? */ @@ -365,7 +370,7 @@ void self_all_density(struct runner *r, struct cell *ci) { dxi[2] = -dxi[2]; /* Interact */ - runner_iact_nonsym_density(r2, dxi, hj, hi, pj, pi); + runner_iact_nonsym_density(r2, dxi, hj, hi, pj, pi, a, H); } } } @@ -374,6 +379,7 @@ void self_all_density(struct runner *r, struct cell *ci) { void self_all_force(struct runner *r, struct cell *ci) { float r2, hi, hj, hig2, hjg2, dxi[3]; //, dxj[3]; struct part *pi, *pj; + float a = 1.f, H = 0.f; /* Implements a double-for loop and checks every interaction */ for (int i = 0; i < ci->count; ++i) { @@ -401,7 +407,7 @@ void self_all_force(struct runner *r, struct cell *ci) { if (r2 < hig2 || r2 < hjg2) { /* Interact */ - runner_iact_force(r2, dxi, hi, hj, pi, pj); + runner_iact_force(r2, dxi, hi, hj, pi, pj, a, H); } } } @@ -411,10 +417,12 @@ void self_all_force(struct runner *r, struct cell *ci) { * @brief Compute the force on a single particle brute-force. */ void engine_single_density(double *dim, long long int pid, - struct part *restrict parts, int N, int periodic) { + struct part *restrict parts, int N, int periodic, + const struct cosmology *cosmo) { double r2, dx[3]; float fdx[3]; struct part p; + float a = 1.f, H = 0.f; /* Find "our" part. */ int k; @@ -441,14 +449,14 @@ void engine_single_density(double *dim, long long int pid, } r2 = fdx[0] * fdx[0] + fdx[1] * fdx[1] + fdx[2] * fdx[2]; if (r2 < p.h * p.h * kernel_gamma2) { - runner_iact_nonsym_density(r2, fdx, p.h, parts[k].h, &p, &parts[k]); + runner_iact_nonsym_density(r2, fdx, p.h, parts[k].h, &p, &parts[k], a, H); } } /* Dump the result. */ - hydro_end_density(&p); + hydro_end_density(&p, cosmo); message("part %lli (h=%e) has wcount=%e, rho=%e.", p.id, p.h, - p.density.wcount, hydro_get_density(&p)); + p.density.wcount, hydro_get_comoving_density(&p)); fflush(stdout); } @@ -458,6 +466,7 @@ void engine_single_force(double *dim, long long int pid, double r2, dx[3]; float fdx[3]; struct part p; + float a = 1.f, H = 0.f; /* Find "our" part. */ for (k = 0; k < N && parts[k].id != pid; k++) @@ -486,7 +495,7 @@ void engine_single_force(double *dim, long long int pid, if (r2 < p.h * p.h * kernel_gamma2 || r2 < parts[k].h * parts[k].h * kernel_gamma2) { hydro_reset_acceleration(&p); - runner_iact_nonsym_force(r2, fdx, p.h, parts[k].h, &p, &parts[k]); + runner_iact_nonsym_force(r2, fdx, p.h, parts[k].h, &p, &parts[k], a, H); } } @@ -694,3 +703,14 @@ int compare_particles(struct part a, struct part b, double threshold) { #endif } + +/** + * @brief return the resident memory use of the process and its children. + * + * @result memory use in Kb. + */ +long get_maxrss() { + struct rusage usage; + getrusage(RUSAGE_SELF, &usage); + return usage.ru_maxrss; +} diff --git a/src/tools.h b/src/tools.h index 4d9e8d3ef86f9ad2661118acf008797893ea5bd7..bb141101a3bf6fad38a83a15ea7f6bb5de86e9f8 100644 --- a/src/tools.h +++ b/src/tools.h @@ -52,4 +52,6 @@ int compare_values(double a, double b, double threshold, double *absDiff, double *absSum, double *relDiff); int compare_particles(struct part a, struct part b, double threshold); +long get_maxrss(); + #endif /* SWIFT_TOOL_H */ diff --git a/src/version.c b/src/version.c index f4177e5c83c776ea063ad32fd00895199c94b182..54749721de96bde010f56965152c536b08672230 100644 --- a/src/version.c +++ b/src/version.c @@ -37,6 +37,10 @@ #include <fftw3.h> #endif +#ifdef HAVE_LIBGSL +#include <gsl/gsl_version.h> +#endif + /* Some standard headers. */ #include <stdio.h> #include <stdlib.h> @@ -332,6 +336,22 @@ const char *fftw3_version(void) { return version; } +/** + * @brief return the GSL version used when SWIFT was built. + * + * @result description of the GSL version. + */ +const char *libgsl_version(void) { + + static char version[256] = {0}; +#if defined(HAVE_LIBGSL) + sprintf(version, "%s", gsl_version); +#else + sprintf(version, "Unknown version"); +#endif + return version; +} + /** * @brief return the thread barrier used in SWIFT. * @@ -376,6 +396,9 @@ void greetings(void) { #ifdef HAVE_FFTW printf(" FFTW library version: %s\n", fftw3_version()); #endif +#ifdef HAVE_LIBGSL + printf(" GSL library version: %s\n", libgsl_version()); +#endif #ifdef WITH_MPI printf(" MPI library: %s\n", mpi_version()); #ifdef HAVE_METIS diff --git a/src/version.h b/src/version.h index 1af76b647b2d401bb4a7998b281864fb3e63a0c8..3163f242c50e56c64cc709b13dfe926f93672a00 100644 --- a/src/version.h +++ b/src/version.h @@ -34,6 +34,7 @@ const char* mpi_version(void); const char* metis_version(void); const char* hdf5_version(void); const char* fftw3_version(void); +const char* libgsl_version(void); const char* thread_barrier_version(void); void greetings(void); diff --git a/tests/test125cells.c b/tests/test125cells.c index 7c6a161093c0cb823efb04f62e0ba570a5dd1651..6098b8969874a3bb942de770b84220c047af6e1c 100644 --- a/tests/test125cells.c +++ b/tests/test125cells.c @@ -1,4 +1,3 @@ - /******************************************************************************* * This file is part of SWIFT. * Copyright (C) 2016 Matthieu Schaller (matthieu.schaller@durham.ac.uk). @@ -403,16 +402,16 @@ void dump_particle_fields(char *fileName, struct cell *main_cell, main_cell->parts[pid].x[1], main_cell->parts[pid].x[2], main_cell->parts[pid].v[0], main_cell->parts[pid].v[1], main_cell->parts[pid].v[2], main_cell->parts[pid].h, - hydro_get_density(&main_cell->parts[pid]), + hydro_get_comoving_density(&main_cell->parts[pid]), #if defined(MINIMAL_SPH) || defined(SHADOWFAX_SPH) 0.f, #else main_cell->parts[pid].density.div_v, #endif - hydro_get_entropy(&main_cell->parts[pid]), - hydro_get_internal_energy(&main_cell->parts[pid]), - hydro_get_pressure(&main_cell->parts[pid]), - hydro_get_soundspeed(&main_cell->parts[pid]), + hydro_get_comoving_entropy(&main_cell->parts[pid]), + hydro_get_comoving_internal_energy(&main_cell->parts[pid]), + hydro_get_comoving_pressure(&main_cell->parts[pid]), + hydro_get_comoving_soundspeed(&main_cell->parts[pid]), main_cell->parts[pid].a_hydro[0], main_cell->parts[pid].a_hydro[1], main_cell->parts[pid].a_hydro[2], main_cell->parts[pid].force.h_dt, #if defined(GADGET2_SPH) @@ -597,6 +596,10 @@ int main(int argc, char *argv[]) { engine.max_active_bin = num_time_bins; engine.nodeID = NODE_ID; + struct cosmology cosmo; + cosmology_init_no_cosmo(&cosmo); + engine.cosmology = &cosmo; + struct runner runner; runner.e = &engine; diff --git a/tests/test27cells.c b/tests/test27cells.c index 0b8d96a29649d2af14deaefd105901936d337842..6b275094de8f2f1a54e94f35ae10e347adb19b4f 100644 --- a/tests/test27cells.c +++ b/tests/test27cells.c @@ -225,9 +225,9 @@ void zero_particle_fields(struct cell *c) { /** * @brief Ends the loop by adding the appropriate coefficients */ -void end_calculation(struct cell *c) { +void end_calculation(struct cell *c, const struct cosmology *cosmo) { for (int pid = 0; pid < c->count; pid++) { - hydro_end_density(&c->parts[pid]); + hydro_end_density(&c->parts[pid], cosmo); /* Recover the common "Neighbour number" definition */ c->parts[pid].density.wcount *= pow_dimension(c->parts[pid].h); @@ -260,7 +260,7 @@ void dump_particle_fields(char *fileName, struct cell *main_cell, main_cell->parts[pid].x[1], main_cell->parts[pid].x[2], main_cell->parts[pid].v[0], main_cell->parts[pid].v[1], main_cell->parts[pid].v[2], - hydro_get_density(&main_cell->parts[pid]), + hydro_get_comoving_density(&main_cell->parts[pid]), #if defined(GIZMO_SPH) || defined(SHADOWFAX_SPH) 0.f, #else @@ -297,7 +297,7 @@ void dump_particle_fields(char *fileName, struct cell *main_cell, "%13e %13e %13e\n", cj->parts[pjd].id, cj->parts[pjd].x[0], cj->parts[pjd].x[1], cj->parts[pjd].x[2], cj->parts[pjd].v[0], cj->parts[pjd].v[1], - cj->parts[pjd].v[2], hydro_get_density(&cj->parts[pjd]), + cj->parts[pjd].v[2], hydro_get_comoving_density(&cj->parts[pjd]), #if defined(GIZMO_SPH) || defined(SHADOWFAX_SPH) 0.f, #else @@ -450,6 +450,10 @@ int main(int argc, char *argv[]) { engine.hydro_properties = &hp; engine.nodeID = NODE_ID; + struct cosmology cosmo; + cosmology_init_no_cosmo(&cosmo); + engine.cosmology = &cosmo; + struct runner runner; runner.e = &engine; @@ -539,7 +543,7 @@ int main(int argc, char *argv[]) { time += toc - tic; /* Let's get physical ! */ - end_calculation(main_cell); + end_calculation(main_cell, &cosmo); /* Dump if necessary */ if (i % 50 == 0) { @@ -587,7 +591,7 @@ int main(int argc, char *argv[]) { const ticks toc = getticks(); /* Let's get physical ! */ - end_calculation(main_cell); + end_calculation(main_cell, &cosmo); /* Dump */ sprintf(outputFileName, "brute_force_27_%s.dat", outputFileNameExtension); diff --git a/tests/testActivePair.c b/tests/testActivePair.c index 447f812df63db97d2b4320f898289bd521eaab3f..62d46c5c0a21d49bf1cb8317ad192c9eabf59c4d 100644 --- a/tests/testActivePair.c +++ b/tests/testActivePair.c @@ -179,9 +179,9 @@ void zero_particle_fields(struct cell *c) { /** * @brief Ends the loop by adding the appropriate coefficients */ -void end_calculation(struct cell *c) { +void end_calculation(struct cell *c, const struct cosmology *cosmo) { for (int pid = 0; pid < c->count; pid++) { - hydro_end_density(&c->parts[pid]); + hydro_end_density(&c->parts[pid], cosmo); /* Recover the common "Neighbour number" definition */ c->parts[pid].density.wcount *= pow_dimension(c->parts[pid].h); @@ -246,8 +246,8 @@ void test_pair_interactions(struct runner *runner, struct cell **ci, vec_interaction(runner, *ci, *cj); /* Let's get physical ! */ - end_calculation(*ci); - end_calculation(*cj); + end_calculation(*ci, runner->e->cosmology); + end_calculation(*cj, runner->e->cosmology); /* Dump if necessary */ dump_particle_fields(swiftOutputFileName, *ci, *cj); @@ -262,8 +262,8 @@ void test_pair_interactions(struct runner *runner, struct cell **ci, serial_interaction(runner, *ci, *cj); /* Let's get physical ! */ - end_calculation(*ci); - end_calculation(*cj); + end_calculation(*ci, runner->e->cosmology); + end_calculation(*cj, runner->e->cosmology); dump_particle_fields(bruteForceOutputFileName, *ci, *cj); } @@ -425,6 +425,7 @@ int main(int argc, char *argv[]) { double perturbation = 0.1, h_pert = 1.1; struct space space; struct engine engine; + struct cosmology cosmo; struct runner *runner; char c; static long long partId = 0; @@ -507,6 +508,9 @@ int main(int argc, char *argv[]) { engine.max_active_bin = num_time_bins; engine.nodeID = NODE_ID; + cosmology_init_no_cosmo(&cosmo); + engine.cosmology = &cosmo; + if (posix_memalign((void **)&runner, SWIFT_STRUCT_ALIGNMENT, sizeof(struct runner)) != 0) { error("couldn't allocate runner"); diff --git a/tests/testAdiabaticIndex.c b/tests/testAdiabaticIndex.c index e0c8c4f54bd2d6e5ddadb25bc44b96f1ca19aad2..64a60fd2aa1f85a9a28fa312922f5fd68daa62d7 100644 --- a/tests/testAdiabaticIndex.c +++ b/tests/testAdiabaticIndex.c @@ -17,22 +17,25 @@ * ******************************************************************************/ -#include "adiabatic_index.h" -#include "error.h" +#include "../config.h" + +#include <fenv.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "swift.h" /** - * @brief Check that a and b are consistent (up to some absolute error) + * @brief Check that a and b are consistent (up to some relative error) * * @param a First value * @param b Second value * @param s String used to identify this check in messages */ void check_value(float a, float b, const char* s) { - if (fabsf(a - b) > 1.e-5f) { - error("Values are inconsistent: %g %g (%s)!", a, b, s); - } else { - message("Values are consistent: %g %g (%s).", a, b, s); - } + if (fabsf(a - b) / fabsf(a + b) > 1.e-6f) + error("Values are inconsistent: %12.15e %12.15e (%s)!", a, b, s); } /** @@ -72,33 +75,41 @@ void check_constants() { * @brief Check that the adiabatic index power functions return the correct * values */ -void check_functions() { +void check_functions(float x) { + float val_a, val_b; - const float x = 0.4; - val_a = pow(x, -hydro_gamma); + val_a = powf(x, -hydro_gamma); val_b = pow_minus_gamma(x); check_value(val_a, val_b, "x^(-gamma)"); - val_a = pow(x, 2.0f / (hydro_gamma - 1.0f)); + val_a = powf(x, 2.0f / (hydro_gamma - 1.0f)); val_b = pow_two_over_gamma_minus_one(x); check_value(val_a, val_b, "x^(2/(gamma-1))"); - val_a = pow(x, 2.0f * hydro_gamma / (hydro_gamma - 1.0f)); + val_a = powf(x, 2.0f * hydro_gamma / (hydro_gamma - 1.0f)); val_b = pow_two_gamma_over_gamma_minus_one(x); check_value(val_a, val_b, "x^((2 gamma)/(gamma-1))"); - val_a = pow(x, 0.5f * (hydro_gamma - 1.0f) / hydro_gamma); + val_a = powf(x, 0.5f * (hydro_gamma - 1.0f) / hydro_gamma); val_b = pow_gamma_minus_one_over_two_gamma(x); check_value(val_a, val_b, "x^((gamma-1)/(2 gamma))"); - val_a = pow(x, -0.5f * (hydro_gamma + 1.0f) / hydro_gamma); + val_a = powf(x, -0.5f * (hydro_gamma + 1.0f) / hydro_gamma); val_b = pow_minus_gamma_plus_one_over_two_gamma(x); check_value(val_a, val_b, "x^(-(gamma+1)/(2 gamma))"); - val_a = pow(x, 1.0f / hydro_gamma); + val_a = powf(x, 1.0f / hydro_gamma); val_b = pow_one_over_gamma(x); check_value(val_a, val_b, "x^(1/gamma)"); + + val_a = powf(x, 3.f * hydro_gamma - 2.f); + val_b = pow_three_gamma_minus_two(x); + check_value(val_a, val_b, "x^(3gamma - 2)"); + + val_a = powf(x, (3.f * hydro_gamma - 5.f) / 2.f); + val_b = pow_three_gamma_minus_five_over_two(x); + check_value(val_a, val_b, "x^((3gamma - 5)/2)"); } /** @@ -106,11 +117,34 @@ void check_functions() { */ int main() { + /* Initialize CPU frequency, this also starts time. */ + unsigned long long cpufreq = 0; + clocks_set_cpufreq(cpufreq); + +/* Choke on FPEs */ +#ifdef HAVE_FE_ENABLE_EXCEPT + feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW); +#endif + + message("Testing for gamma=%f", hydro_gamma); + + /* Get some randomness going */ + const int seed = time(NULL); + message("Seed = %d", seed); + srand(seed); + /* check the values of the adiabatic index constants */ check_constants(); - /* check the adiabatic index power functions */ - check_functions(); + for (int i = 0; i < 100; ++i) { + + const float x = random_uniform(0., 100.); + + message("Random test %d/100 (x=%e)", i, x); + + /* check the adiabatic index power functions */ + check_functions(x); + } return 0; } diff --git a/tests/testInteractions.c b/tests/testInteractions.c index 76ee5078819882c38e3e57ac33bc4ee3ae6fc67e..31b7eb431da6fc12e767bc9053a21dc9ef010598 100644 --- a/tests/testInteractions.c +++ b/tests/testInteractions.c @@ -130,15 +130,15 @@ void dump_indv_particle_fields(char *fileName, struct part *p) { "%8.5f " "%8.5f %8.5f %13e %13e %13e %13e %13e %8.5f %8.5f\n", p->id, p->x[0], p->x[1], p->x[2], p->v[0], p->v[1], p->v[2], p->h, - hydro_get_density(p), + hydro_get_comoving_density(p), #if defined(MINIMAL_SPH) || defined(SHADOWFAX_SPH) 0.f, #else p->density.div_v, #endif - hydro_get_entropy(p), hydro_get_internal_energy(p), - hydro_get_pressure(p), hydro_get_soundspeed(p), p->a_hydro[0], - p->a_hydro[1], p->a_hydro[2], p->force.h_dt, + hydro_get_comoving_entropy(p), hydro_get_comoving_internal_energy(p), + hydro_get_comoving_pressure(p), hydro_get_comoving_soundspeed(p), + p->a_hydro[0], p->a_hydro[1], p->a_hydro[2], p->force.h_dt, #if defined(GADGET2_SPH) p->force.v_sig, p->entropy_dt, 0.f #elif defined(DEFAULT_SPH) @@ -213,6 +213,9 @@ void test_interactions(struct part test_part, struct part *parts, size_t count, ticks serial_time = 0; ticks vec_time = 0; + const float a = 1.f; + const float H = 0.f; + char serial_filename[200] = ""; char vec_filename[200] = ""; @@ -274,7 +277,7 @@ void test_interactions(struct part test_part, struct part *parts, size_t count, #endif for (size_t i = 0; i < count; i++) { IACT(r2[i], &(dx[3 * i]), pi_serial.h, pj_serial[i].h, &pi_serial, - &pj_serial[i]); + &pj_serial[i], a, H); } serial_time += getticks() - tic; } @@ -419,6 +422,9 @@ void test_force_interactions(struct part test_part, struct part *parts, char serial_filename[200] = ""; char vec_filename[200] = ""; + const float a = 1.f; + const float H = 0.f; + strcpy(serial_filename, filePrefix); strcpy(vec_filename, filePrefix); sprintf(serial_filename + strlen(serial_filename), "_serial.dat"); @@ -497,7 +503,7 @@ void test_force_interactions(struct part test_part, struct part *parts, #endif for (size_t i = 0; i < count; i++) { runner_iact_nonsym_force(r2[i], &(dx[3 * i]), pi_serial.h, pj_serial[i].h, - &pi_serial, &pj_serial[i]); + &pi_serial, &pj_serial[i], a, H); } serial_time += getticks() - tic; } diff --git a/tests/testPeriodicBC.c b/tests/testPeriodicBC.c index f2929061a2449a76f5e5cee0412bd7c90865fbf8..ffbb37a99781e6a4aed6e34fe016f239d949c870 100644 --- a/tests/testPeriodicBC.c +++ b/tests/testPeriodicBC.c @@ -204,9 +204,9 @@ void zero_particle_fields(struct cell *c) { /** * @brief Ends the loop by adding the appropriate coefficients */ -void end_calculation(struct cell *c) { +void end_calculation(struct cell *c, const struct cosmology *cosmo) { for (int pid = 0; pid < c->count; pid++) { - hydro_end_density(&c->parts[pid]); + hydro_end_density(&c->parts[pid], cosmo); } } @@ -236,7 +236,7 @@ void dump_particle_fields(char *fileName, struct cell *main_cell, int i, int j, main_cell->parts[pid].x[1], main_cell->parts[pid].x[2], main_cell->parts[pid].v[0], main_cell->parts[pid].v[1], main_cell->parts[pid].v[2], - hydro_get_density(&main_cell->parts[pid]), + hydro_get_comoving_density(&main_cell->parts[pid]), #if defined(GIZMO_SPH) || defined(SHADOWFAX_SPH) 0.f, #else @@ -332,7 +332,7 @@ void test_boundary_conditions(struct cell **cells, struct runner runner, #endif /* Let's get physical ! */ - end_calculation(main_cell); + end_calculation(main_cell, runner.e->cosmology); /* Dump particles from the main cell. */ dump_particle_fields(swiftOutputFileName, main_cell, loc_i, loc_j, loc_k); @@ -370,7 +370,7 @@ void test_boundary_conditions(struct cell **cells, struct runner runner, #endif /* Let's get physical ! */ - end_calculation(main_cell); + end_calculation(main_cell, runner.e->cosmology); /* Dump */ dump_particle_fields(bruteForceOutputFileName, main_cell, loc_i, loc_j, @@ -496,6 +496,10 @@ int main(int argc, char *argv[]) { struct runner runner; runner.e = &engine; + struct cosmology cosmo; + cosmology_init_no_cosmo(&cosmo); + engine.cosmology = &cosmo; + /* Construct some cells */ struct cell *cells[dim * dim * dim]; static long long partId = 0; diff --git a/tests/testSymmetry.c b/tests/testSymmetry.c index 2e950c5c79f84d601b8d034927b174ac0454de68..7a62f735b57b3a8fe5b91308b4dfe8ce00706e0e 100644 --- a/tests/testSymmetry.c +++ b/tests/testSymmetry.c @@ -41,6 +41,10 @@ void test() { /* voronoi_set_box(box_anchor, box_side);*/ #endif + /* Start with some values for the cosmological paramters */ + const float a = (float)random_uniform(0.8, 1.); + const float H = 1.f; + /* Create two random particles (don't do this at home !) */ struct part pi, pj; for (size_t i = 0; i < sizeof(struct part) / sizeof(float); ++i) { @@ -137,20 +141,17 @@ void test() { /* --- Test the density loop --- */ /* Call the symmetric version */ - runner_iact_density(r2, dx, pi.h, pj.h, &pi, &pj); - /* Now the chemistry. WARNING chemistry is not initialized */ - runner_iact_chemistry(r2, dx, pi.h, pj.h, &pi, &pj); + runner_iact_density(r2, dx, pi.h, pj.h, &pi, &pj, a, H); + runner_iact_chemistry(r2, dx, pi.h, pj.h, &pi, &pj, a, H); /* Call the non-symmetric version */ - runner_iact_nonsym_density(r2, dx, pi2.h, pj2.h, &pi2, &pj2); - /* Now the chemistry. WARNING chemistry is not initialized */ - runner_iact_nonsym_chemistry(r2, dx, pi2.h, pj2.h, &pi2, &pj2); + runner_iact_nonsym_density(r2, dx, pi2.h, pj2.h, &pi2, &pj2, a, H); + runner_iact_nonsym_chemistry(r2, dx, pi2.h, pj2.h, &pi2, &pj2, a, H); dx[0] = -dx[0]; dx[1] = -dx[1]; dx[2] = -dx[2]; - runner_iact_nonsym_density(r2, dx, pj2.h, pi2.h, &pj2, &pi2); - /* Now the chemistry. WARNING chemistry is not initialized */ - runner_iact_nonsym_chemistry(r2, dx, pj2.h, pi2.h, &pj2, &pi2); + runner_iact_nonsym_density(r2, dx, pj2.h, pi2.h, &pj2, &pi2, a, H); + runner_iact_nonsym_chemistry(r2, dx, pj2.h, pi2.h, &pj2, &pi2, a, H); /* Check that the particles are the same */ i_not_ok = memcmp(&pi, &pi2, sizeof(struct part)); @@ -162,14 +163,14 @@ void test() { /* --- Test the force loop --- */ /* Call the symmetric version */ - runner_iact_force(r2, dx, pi.h, pj.h, &pi, &pj); + runner_iact_force(r2, dx, pi.h, pj.h, &pi, &pj, a, H); /* Call the non-symmetric version */ - runner_iact_nonsym_force(r2, dx, pi2.h, pj2.h, &pi2, &pj2); + runner_iact_nonsym_force(r2, dx, pi2.h, pj2.h, &pi2, &pj2, a, H); dx[0] = -dx[0]; dx[1] = -dx[1]; dx[2] = -dx[2]; - runner_iact_nonsym_force(r2, dx, pj2.h, pi2.h, &pj2, &pi2); + runner_iact_nonsym_force(r2, dx, pj2.h, pi2.h, &pj2, &pi2, a, H); /* Check that the particles are the same */ #if defined(GIZMO_SPH) diff --git a/tests/testTimeIntegration.c b/tests/testTimeIntegration.c index 42a3d224f43d580e512119edc55051bd22719a3b..972e6f2323c0401c70de2990bcb088f95b3dfd83 100644 --- a/tests/testTimeIntegration.c +++ b/tests/testTimeIntegration.c @@ -95,8 +95,8 @@ int main() { run.e = ŋ eng.time = 0.; - eng.timeBegin = 0.; - eng.timeEnd = N_orbits * T; + eng.time_begin = 0.; + eng.time_end = N_orbits * T; eng.dt_min = dt; /* This forces the time-step to be dt */ eng.dt_max = dt; /* irrespective of the state of the particle */ @@ -104,7 +104,7 @@ int main() { for (i = 0; i < N; i++) { /* Move forward in time */ - eng.timeOld = eng.time; + eng.time_old = eng.time; eng.time += dt; /* Compute gravitational acceleration */ diff --git a/theory/Cosmology/bibliography.bib b/theory/Cosmology/bibliography.bib new file mode 100644 index 0000000000000000000000000000000000000000..6979bf7dd23bdb8543ac8752c12432837480d4ed --- /dev/null +++ b/theory/Cosmology/bibliography.bib @@ -0,0 +1,140 @@ +@ARTICLE{Springel2005, + author = {{Springel}, V.}, + title = "{The cosmological simulation code GADGET-2}", + journal = {\mnras}, + eprint = {astro-ph/0505010}, + keywords = {methods: numerical, galaxies: interactions, dark matter}, + year = 2005, + month = dec, + volume = 364, + pages = {1105-1134}, + doi = {10.1111/j.1365-2966.2005.09655.x}, + adsurl = {http://adsabs.harvard.edu/abs/2005MNRAS.364.1105S}, + adsnote = {Provided by the SAO/NASA Astrophysics Data System} +} + +@ARTICLE{Wright2006, + author = {{Wright}, E.~L.}, + title = "{A Cosmology Calculator for the World Wide Web}", + journal = {\pasp}, + eprint = {astro-ph/0609593}, + keywords = {Cosmology: Miscellaneous, Methods: Miscellaneous}, + year = 2006, + month = dec, + volume = 118, + pages = {1711-1715}, + doi = {10.1086/510102}, + adsurl = {http://adsabs.harvard.edu/abs/2006PASP..118.1711W}, + adsnote = {Provided by the SAO/NASA Astrophysics Data System} +} + + +@ARTICLE{Quinn1997, + author = {{Quinn}, T. and {Katz}, N. and {Stadel}, J. and {Lake}, G.}, + title = "{Time stepping N-body simulations}", + journal = {ArXiv Astrophysics e-prints}, + eprint = {astro-ph/9710043}, + keywords = {Astrophysics}, + year = 1997, + month = oct, + adsurl = {http://adsabs.harvard.edu/abs/1997astro.ph.10043Q}, + adsnote = {Provided by the SAO/NASA Astrophysics Data System} +} + +@ARTICLE{Linder2003, + author = {{Linder}, E.~V. and {Jenkins}, A.}, + title = "{Cosmic structure growth and dark energy}", + journal = {\mnras}, + eprint = {astro-ph/0305286}, + keywords = {gravitation, methods: numerical, cosmological parameters}, + year = 2003, + month = dec, + volume = 346, + pages = {573-583}, + doi = {10.1046/j.1365-2966.2003.07112.x}, + adsurl = {http://adsabs.harvard.edu/abs/2003MNRAS.346..573L}, + adsnote = {Provided by the SAO/NASA Astrophysics Data System} +} + +@book{GSL, + author = {Gough, Brian}, + title = {GNU Scientific Library Reference Manual - Third Edition}, + year = {2009}, + isbn = {0954612078, 9780954612078}, + edition = {3rd}, + publisher = {Network Theory Ltd.}, +} + +@ARTICLE{Springel2002, + author = {{Springel}, V. and {Hernquist}, L.}, + title = "{Cosmological smoothed particle hydrodynamics simulations: the entropy equation}", + journal = {\mnras}, + eprint = {astro-ph/0111016}, + keywords = {methods: numerical, galaxies: evolution, galaxies: starburst, methods: numerical, galaxies: evolution, galaxies: starburst}, + year = 2002, + month = jul, + volume = 333, + pages = {649-664}, + doi = {10.1046/j.1365-8711.2002.05445.x}, + adsurl = {http://adsabs.harvard.edu/abs/2002MNRAS.333..649S}, + adsnote = {Provided by the SAO/NASA Astrophysics Data System} +} + + +@BOOK{Peebles1980, + author = {{Peebles}, P.~J.~E.}, + title = "{The large-scale structure of the universe}", + keywords = {Cosmology, Galactic Clusters, Galactic Evolution, Universe, Astronomical Models, Correlation, Mass Distribution, Particle Motion, Relativistic Theory, Statistical Distributions}, +booktitle = {Research supported by the National Science Foundation.~Princeton, N.J., Princeton University Press, 1980.~435 p.}, + year = 1980, + adsurl = {http://adsabs.harvard.edu/abs/1980lssu.book.....P}, + adsnote = {Provided by the SAO/NASA Astrophysics Data System} +} + + + +@ARTICLE{Hopkins2013, + author = {{Hopkins}, P.~F.}, + title = "{A general class of Lagrangian smoothed particle hydrodynamics methods and implications for fluid mixing problems}", + journal = {\mnras}, +archivePrefix = "arXiv", + eprint = {1206.5006}, + primaryClass = "astro-ph.IM", + keywords = {hydrodynamics, instabilities, turbulence, methods: numerical, cosmology: theory}, + year = 2013, + month = feb, + volume = 428, + pages = {2840-2856}, + doi = {10.1093/mnras/sts210}, + adsurl = {http://adsabs.harvard.edu/abs/2013MNRAS.428.2840H}, + adsnote = {Provided by the SAO/NASA Astrophysics Data System} +} + +@ARTICLE{Price2012, + author = {{Price}, D.~J.}, + title = "{Smoothed particle hydrodynamics and magnetohydrodynamics}", + journal = {Journal of Computational Physics}, +archivePrefix = "arXiv", + eprint = {1012.1885}, + primaryClass = "astro-ph.IM", + year = 2012, + month = feb, + volume = 231, + pages = {759-794}, + doi = {10.1016/j.jcp.2010.12.011}, + adsurl = {http://adsabs.harvard.edu/abs/2012JCoPh.231..759P}, + adsnote = {Provided by the SAO/NASA Astrophysics Data System} +} + +@article{Monaghan1997, +title = "SPH and Riemann Solvers", +journal = "Journal of Computational Physics", +volume = "136", +number = "2", +pages = "298 - 307", +year = "1997", +issn = "0021-9991", +doi = "https://doi.org/10.1006/jcph.1997.5732", +url = "http://www.sciencedirect.com/science/article/pii/S0021999197957326", +author = "J.J. Monaghan" +} \ No newline at end of file diff --git a/theory/Cosmology/coordinates.tex b/theory/Cosmology/coordinates.tex new file mode 100644 index 0000000000000000000000000000000000000000..56354623ea5a4127306c13f122e6f45223c7309d --- /dev/null +++ b/theory/Cosmology/coordinates.tex @@ -0,0 +1,126 @@ +\subsection{Choice of co-moving coordinates} +\label{ssec:ccordinates} + +Note that, unlike the \gadget convention, we do not express quantities with +``little h'' ($h$) included; for instance units of length are expressed in +units of $\rm{Mpc}$ and not ${\rm{Mpc}}/h$. Similarly, the time integration +operators (see below) also include an $h$-factor via the explicit appearance of +the Hubble constant.\\ +In physical coordinates, the Lagrangian for a particle $i$ in the +\cite{Springel2002} flavour of SPH with gravity reads +\begin{equation} + \Lag = + \frac{1}{2} m_i \dot{\mathbf{r}}_i^2 - + \frac{1}{\gamma-1}m_iA_i\rho_i^{\gamma-1} - + m_i \phi +\end{equation} +Introducing the comoving positions $\mathbf{r}'$ such that $\mathbf{r} += a(t) \mathbf{r}'$ and comoving densities $\rho' \equiv a^3(t)\rho$, +\begin{equation} + \Lag = + \frac{1}{2} m_i \left(a\dot{\mathbf{r}}_i' + \dot{a}\mathbf{r}_i' + \right)^2 - + \frac{1}{\gamma-1}m_iA_i'\left(\frac{\rho_i'}{a^3}\right)^{\gamma-1} + - m_i \phi, +\end{equation} +where $A'=A$ is chosen such that the equation of state for +the gas and thermodynamic relations between quantities have the same +form (i.e. are scale-factor free) in the primed coordinates as +well. This implies +\begin{equation} + P' = a^{3\gamma}P,\quad u'=a^{3(\gamma-1)}u, \quad c'=a^{3(\gamma-1)/2}c, +\end{equation} +for the pressure, internal energy and sound-speed +respectively. Following \cite{Peebles1980} (ch.7), we introduce the +gauge transformation $\Lag \rightarrow \Lag + \frac{d}{dt}\Psi$ with +$\Psi \equiv \frac{1}{2}a\dot{a}\mathbf{r}_i^2$ and obtain +\begin{align} + \Lag &= \frac{1}{2}m_ia^2 \dot{\mathbf{r}}_i^2 - + \frac{1}{\gamma-1}m_iA_i'\left(\frac{\rho_i'}{a^3}\right)^{\gamma-1} + -\frac{\phi'}{a},\\ + \phi' &= a\phi + \frac{1}{2}a^2\ddot{a}\mathbf{r}_i'^2.\nonumber +\end{align} +Finally, we introduce the velocities $\mathbf{v}' \equiv +a^2\dot{\mathbf{r}'}$ that are used internally by the code. Note that these +velocities \emph{do not} have a physical interpretation. We caution that they +are not the peculiar velocities, nor the Hubble flow, nor the total +velocities\footnote{One additional inconvenience of our choice of + generalised coordinates is that our velocities $\mathbf{v}'$ and + sound-speed $c'$ do not have the same dependencies on the + scale-factor. The signal velocity entering the time-step calculation + will hence read $v_{\rm sig} = a\dot{\mathbf{r}'} + c = \frac{1}{a} \left( + |\mathbf{v}'| + a^{(5 - 3\gamma)/2}c'\right)$.}. +This choice implies that $\dot{v}' = a \ddot{r}$. Using the SPH +definition of density, $\rho_i = +\sum_jm_jW(\mathbf{r}_{j}'-\mathbf{r}_{i}',h_i') = +\sum_jm_jW_{ij}'(h_i')$, we can follow \cite{Price2012} and apply the +Euler-Lagrange equations to write +\begin{alignat}{3} + \dot{\mathbf{r}}_i'&= \frac{1}{a^2} \mathbf{v}_i'& \label{eq:cosmo_eom_r} \\ + \dot{\mathbf{v}}_i' &= -\sum_j m_j &&\left[\frac{1}{a^{3(\gamma-1)}}f_i'A_i'\rho_i'^{\gamma-2}\mathbf{\nabla}_i'W_{ij}'(h_i)\right. \nonumber\\ + & && + \left. \frac{1}{a^{3(\gamma-1)}}f_j'A_j'\rho_j'^{\gamma-2}\mathbf{\nabla}_i'W_{ij}'(h_j)\right. \nonumber\\ + & && + \left. \frac{1}{a}\mathbf{\nabla}_i'\phi'\right] \label{eq:cosmo_eom_v} +\end{alignat} +with +\begin{equation} + f_i' = \left[1 + \frac{h_i'}{3\rho_i'}\frac{\partial + \rho_i'}{\partial h_i'}\right]^{-1}, \qquad \mathbf{\nabla}_i' + \equiv \frac{\partial}{\partial \mathbf{r}_{i}'}. \nonumber +\end{equation} +These correspond to the equations of motion for density-entropy SPH +\citep[e.g. eq. 14 of][]{Hopkins2013} with cosmological and +gravitational terms. SPH flavours that evolve the internal energy $u$ instead of the +entropy require the additional equation of motion describing the evolution of +$u'$: +\begin{equation} + \dot{u}_i' = \frac{P_i'}{\rho_i'^2}\left[3H\rho_i' + \frac{1}{a^2}f_i'\sum_jm_j\left(\mathbf{v}_i' - + \mathbf{v}_j'\right)\cdot\mathbf{\nabla}_i'W_{ij}'(h_i)\right], + \label{eq:cosmo_eom_u} +\end{equation} +where the first term in the brackets accounts for the change in energy +due to the expansion of the Universe. The scale-factors appearing in +the equations are later absorbed in the time-integration operators +(Sec.~\ref{ssec:operators}) such that the RHS of the equations of +motions is identical for the primed quantities to the ones obtained in +the non-cosmological case for the physical quantities. + +Additional terms in the SPH equations of motion (e.g. viscosity +switches) often rely on the velocity divergence and curl. Their SPH +estimators $\langle\cdot\rangle$ in physical coordinates can be +related to their estimators based on our primed-coordinates using: +\begin{align} + \left\langle \mathbf{\nabla}\cdot\dot{\mathbf{r}}_i \right\rangle &= + \frac{1}{a^2} \left\langle + \mathbf{\nabla}'\cdot\mathbf{v}_i'\right\rangle = + \frac{1}{a^2\rho_i'}\sum_j m_j\left(\mathbf{v}_j' - + \mathbf{v}_i'\right) \cdot \mathbf{\nabla}_i'W_{ij}'(h_i), \nonumber \\ + \left\langle \mathbf{\nabla}\times\dot{\mathbf{r}}_i \right\rangle &= + \frac{1}{a^2} \left\langle + \mathbf{\nabla}'\times\mathbf{v}_i'\right\rangle = + \frac{1}{a^2\rho_i'}\sum_j m_j\left(\mathbf{v}_j' - + \mathbf{v}_i'\right) \times \mathbf{\nabla}_i'W_{ij}'(h_i). \nonumber +\end{align} +We finally give the expressions for the \cite{Monaghan1997} viscosity +term, that enters most SPH flavours, in our system of coordinates. The +viscosity ``tensor'' $\Pi_{ij} \equiv \frac{1}{2}\alpha_{\rm visc} v_{\rm + sig}'\mu_{ij}/\left(\rho_i + \rho_j\right)$ can be computed + in the primmed coordinates from the following quantities +\begin{align} + \omega_{ij}' &= \left(\mathbf{v}_i' - \mathbf{v}_j'\right) \cdot + \left(\mathbf{r}_i' - \mathbf{r}_j'\right), \\ + \mu_{ij}' &= + a^{(3\gamma-5)/2} \left(\omega_{ij}' + a^2H\left|\mathbf{r}_i' - + \mathbf{r}_j'\right|^2 \right) / |\mathbf{r}_i' - \mathbf{r}_j' |, + \\ + v_{\rm sig}' &= c_i' + c_j' - 3 \mu_{ij}'. +\end{align} +which leads to $\Pi_{ij}'=a^{3\gamma}\Pi_{ij}$. Note that he last quantity is +also used to compute the time-step size. The evolution of entropy is +then +\begin{equation} + \dot{A}_i = \dot{A}_i' = \frac{1}{a^2}\frac{1}{2}\frac{\gamma-1}{\rho_i'^{\gamma-1}} \sum_j + m_j \Pi_{ij}' \left(\mathbf{v}_i' - + \mathbf{v}_j'\right)\cdot\mathbf{\nabla}_i'W_{ij}'(h_i), +\end{equation} +indicating that the entropy evolves with the same scale-factor +dependence as the comoving positions (eq.~\ref{eq:cosmo_eom_r}). diff --git a/theory/Cosmology/cosmology_standalone.tex b/theory/Cosmology/cosmology_standalone.tex new file mode 100644 index 0000000000000000000000000000000000000000..7f4e7afd3f0d7725b7ee36a245428e19376d1d0c --- /dev/null +++ b/theory/Cosmology/cosmology_standalone.tex @@ -0,0 +1,48 @@ +\documentclass[fleqn, usenatbib, useAMS, a4paper]{mnras} +\usepackage{graphicx} +\usepackage{amsmath,paralist,xcolor,xspace,amssymb} +\usepackage{times} +\usepackage{comment} +\usepackage[super]{nth} + +\newcommand{\todo}[1]{{\textcolor{red}{#1}}} +\newcommand{\gadget}{{\sc Gadget}\xspace} +\newcommand{\swift}{{\sc Swift}\xspace} +\newcommand{\nbody}{$N$-body\xspace} +\newcommand{\Lag}{\mathcal{L}} + +%opening +\title{Cosmology equations in SWIFT} +\author{Matthieu Schaller} +\begin{document} + +\date{\today} + +\pagerange{\pageref{firstpage}--\pageref{lastpage}} \pubyear{2018} + +\maketitle + +\label{firstpage} + +\begin{abstract} +Making cosmology great again. +\end{abstract} + +\begin{keywords} +\end{keywords} + +\section{Cosmology equations in \swift} +\label{sec:cosmo} + +\input{flrw} + +\input{coordinates} + +\input{operators} + +\bibliographystyle{mnras} +\bibliography{./bibliography.bib} + +\label{lastpage} + +\end{document} diff --git a/theory/Cosmology/flrw.tex b/theory/Cosmology/flrw.tex new file mode 100644 index 0000000000000000000000000000000000000000..c50f44c19cfd4da2ad6ff187759edf721001c326 --- /dev/null +++ b/theory/Cosmology/flrw.tex @@ -0,0 +1,58 @@ +\subsection{Background evolution} +\label{ssec:flrw} + +In \swift we assume a standard FLRW metric for the evolution of the background +density of the Universe and use the Friedmann equations to describe the +evolution of the scale-factor $a(t)$. We scale $a$ such that its present-day +value is $a_0 \equiv a(t=t_{\rm now}) = 1$. We also define redshift $z \equiv +1/a - 1$ and the Hubble parameter +\begin{equation} +H(t) \equiv \frac{\dot{a}(t)}{a(t)} +\end{equation} +with its present-day value denoted as $H_0 = H(t=t_{\rm now})$. Following +normal conventions we write $H_0 = 100 +h~\rm{km}\cdot\rm{s}^{-1}\cdot\rm{Mpc}^{-1}$ and use $h$ as the input parameter +for the Hubble constant. + +To allow for general expansion histories we use the full Friedmann equations +and write +\begin{align} +H(a) &\equiv H_0 E(a) \\ E(a) &\equiv\sqrt{\Omega_m a^{-3} + \Omega_r + a^{-4} + \Omega_k a^{-2} + \Omega_\Lambda \exp\left(3\tilde{w}(a)\right)}, +\\ +\tilde{w}(a) &= (a-1)w_a - (1+w_0 + w_a)\log\left(a\right), +\label{eq:friedmann} +\end{align} +where we followed \cite{Linder2003} to parametrize the evolution of +the dark-energy equation-of-state\footnote{Note that $\tilde{w}(z)\equiv + \int_0^z \frac{1+w(z')}{1+z'}dz'$, which leads to the analytic + expression we use.} as: +\begin{equation} +w(a) \equiv w_0 + w_a~(1-a). +\end{equation} +The cosmological model is hence fully defined by specifying the dimensionless +constants $\Omega_m$, $\Omega_r$, $\Omega_k$, $\Omega_\Lambda$, $h$, $w_0$ and +$w_a$ as well as the starting redshift (or scale-factor of the simulation) +$a_{\rm start}$ and final time $a_{\rm end}$. \\ At any scale-factor $a_{\rm +age}$, the time $t_{\rm age}$ since the Big Bang (age of the Universe) can be +computed as \citep[e.g.][]{Wright2006}: +\begin{equation} + t_{\rm age} = \int_{0}^{a_{\rm age}} dt = \int_{0}^{a_{\rm age}} + \frac{da}{a H(a)} = \frac{1}{H_0} \int_{0}^{a_{\rm age}} + \frac{da}{a E(a)}. +\end{equation} +For a general set of cosmological parameters, this integral can only be +evaluated numerically, which is too slow to be evaluated accurately during a +run. At the start of the simulation we tabulate this integral for $10^4$ values +of $a_{\rm age}$ equally spaced between $\log(a_{\rm start})$ and $\log(a_{\rm +end})$. The values are obtained via adaptive quadrature using the 61-points +Gauss-Konrod rule implemented in the {\sc gsl} library \citep{GSL} with a +relative error limit of $\epsilon=10^{-10}$. The value for a specific $a$ (over +the course of a simulation run) is then obtained by linear interpolation of the +table. + +\subsubsection{Typical Values of the Cosmological Parameters} + +Typical values for the constants are: $\Omega_m = 0.3, \Omega_\Lambda=0.7, 0 < +\Omega_r<10^{-3}, |\Omega_k | < 10^{-2}, h=0.7, a_{\rm start} = 10^{-2}, a_{\rm +end} = 1, w_0 = -1\pm 0.1, w_a=0\pm0.2$ and $\gamma = 5/3$. diff --git a/theory/Cosmology/operators.tex b/theory/Cosmology/operators.tex new file mode 100644 index 0000000000000000000000000000000000000000..89aa32bae554dceba8f1525cb209728a17154f5b --- /dev/null +++ b/theory/Cosmology/operators.tex @@ -0,0 +1,55 @@ +\subsection{Time-integration operators} +\label{ssec:operators} +For the choice of cosmological coordinates made in \swift, the normal +``kick'' and ``drift'' operators get modified to account for the +expansion of the Universe. The derivation of these operators from the +system's Lagrangian is given in appendix A of \cite{Quinn1997} for the +collision-less case. We do not repeat that derivation here but, for +completeness, give the expressions we use as well as the ones used for +the hydro-dynamics. + +The ``drift'' operator gets modified such that $\Delta t$ for a +time-step running from a scale-factor $a_{n}$ to $a_{n+1}$ becomes + +\begin{equation} + \Delta t_{\rm drift} \equiv \int_{a_n}^{a_{n+1}} \frac{dt}{a^2} = \frac{1}{H_0} \int_{a_n}^{a_{n+1}} \frac{da}{a^3E(a)}, +\end{equation} +with $E(a)$ given by eq.~\ref{eq:friedmann}. Similarly, the time-step +entering ``kick'' operator for collision-less acceleration reads +\begin{equation} + \Delta t_{\rm kick,g} \equiv \int_{a_n}^{a_{n+1}} \frac{dt}{a} = \frac{1}{H_0} \int_{a_n}^{a_{n+1}} \frac{da}{a^2E(a)}. +\end{equation} +However, for the case of gas dynamics, given our choice of +coordinates, the ``kick'' operator has a second variant that reads +\begin{equation} + \Delta t_{\rm kick,h} \equiv \int_{a_n}^{a_{n+1}} \frac{dt}{a^{3(\gamma-1)}} = \frac{1}{H_0} \int_{a_n}^{a_{n+1}} \frac{da}{a^{3\gamma - 2}E(a)}, +\end{equation} +where $\gamma$ is the adiabatic index of the gas. Accelerations +arising from hydrodynamic forces (\nth{1} and \nth{2} term in +eq.~\ref{eq:cosmo_eom_v}) are integrated forward in time using $\Delta +t_{\rm kick,h}$, whilst the accelerations given by the gravity forces +(\nth{3} term in eq.~\ref{eq:cosmo_eom_v}) use $\Delta t_{\rm + kick,g}$. The entropy or internal energy is integrated forward in +time using $\Delta t_{\rm kick,A} = \Delta t_{\rm + drift}$\footnote{Note that {\sc gadget-2} uses a slightly different + operator here. They first multiply $\dot{A}_i'$ by $1/H$ and do not + not consider the $1/a^2$ term as part of the time-integration + operator. They then use $\int H dt$ as the operator, which + integrates out trivially. This slight inconsistency with the rest of + the time-integration operators is unlikely to lead to any practical + difference.}, whilst the change in energy due to the expansion of +the Universe (first term in eq.~\ref{eq:cosmo_eom_u}) can be computed +using +\begin{equation} + \int_{a_n}^{a_{n+1}} H dt = \int_{a_n}^{a_{n+1}} \frac{da}{a} = + \log{a_{n+1}} - \log{a_n}. +\end{equation} +Following the same method as for the age of the Universe +(sec. \ref{ssec:flrw}), the three non-trivial integrals are evaluated +numerically at the start of the simulation for a series $10^4$ values +of $a$ placed at regular intervals between $\log a_{\rm begin}$ and +$\log a_{\rm end}$. The values for a specific pair of scale-factors +$a_n$ and $a_{n+1}$ are then obtained by interpolating that table +linearly. + + diff --git a/theory/Cosmology/run.sh b/theory/Cosmology/run.sh new file mode 100755 index 0000000000000000000000000000000000000000..b386ecadda7046ac886d32bd3ceb278e90f4d81c --- /dev/null +++ b/theory/Cosmology/run.sh @@ -0,0 +1,6 @@ +#!/bin/bash +echo "Generating PDF..." +pdflatex -jobname=cosmology cosmology_standalone.tex +bibtex cosmology.aux +pdflatex -jobname=cosmology cosmology_standalone.tex +pdflatex -jobname=cosmology cosmology_standalone.tex