diff --git a/INSTALL.swift b/INSTALL.swift index db6c6677b202e55e76114373f3e037cf50de10cc..bf8dbc92f5ccb06f6988c5672e5fdac54d2d2598 100644 --- a/INSTALL.swift +++ b/INSTALL.swift @@ -154,6 +154,12 @@ before you can build it. distributing the threads among the different cores on each computing node. + Note that if you have libNUMA outside of the system include + directories it may fail to compile as the headers do not pass + the -Wstrict-prototype check of GCC. In that case you will need + to use --enable-compiler-warnings=yes configure option to stop + this being an error. + - tcmalloc / jemalloc / TBBmalloc: a build of the tcmalloc library (part of gperftools), jemalloc or TBBmalloc can be used be used to obtain faster and more diff --git a/README b/README index 97d096ef1804a4348e88dfaf67c22b2c427a3ad8..5b0b5f3ebf8b322e121e0398ca01062e226be649 100644 --- a/README +++ b/README @@ -6,7 +6,7 @@ /____/ |__/|__/___/_/ /_/ SPH With Inter-dependent Fine-grained Tasking -Website: www.swiftsim.com + Website: www.swiftsim.com Twitter: @SwiftSimulation See INSTALL.swift for install instructions. @@ -27,7 +27,7 @@ Parameters: -D, --drift-all Always drift all particles even the ones far from active particles. This emulates Gadget-[23] and GIZMO's default behaviours. - -F, --sourceterms + -F, --star-formation Run with star formation -g, --external-gravity Run with an external gravitational potential. -G, --self-gravity Run with self-gravity. -M, --multipole-reconstruction Reconstruct the multipoles every time-step. diff --git a/README.md b/README.md index 94e95776cd80c1bb822f0f68290c2add9d2bb58b..92925017d9a8f44521a542e1df3760cc58ba73cb 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ Parameters: -D, --drift-all Always drift all particles even the ones far from active particles. This emulates Gadget-[23] and GIZMO's default behaviours. - -F, --sourceterms + -F, --star-formation Run with star formation -g, --external-gravity Run with an external gravitational potential. -G, --self-gravity Run with self-gravity. -M, --multipole-reconstruction Reconstruct the multipoles every time-step. diff --git a/configure.ac b/configure.ac index ca1aeb626b30d3170f71420e9700673f9597e07e..bf909a315c59cd0234c31461de88cad7d93f819e 100644 --- a/configure.ac +++ b/configure.ac @@ -19,6 +19,22 @@ AC_INIT([SWIFT],[0.8.0],[https://gitlab.cosma.dur.ac.uk/swift/swiftsim]) swift_config_flags="$*" +# We want to stop when given unrecognised options. No subdirs so this is safe. +enable_option_checking=${enable_option_checking:-fatal} +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) + ;; + fatal) + { $as_echo "$as_me: error: unrecognized options: $ac_unrecognized_opts" >&2 + { (exit 1); exit 1; }; } + ;; + *) + $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 + ;; + esac +fi + AC_COPYRIGHT AC_CONFIG_SRCDIR([src/space.c]) AC_CONFIG_AUX_DIR([.]) @@ -335,7 +351,7 @@ AC_ARG_ENABLE([vec], [enable_vec="yes"] ) -# Disable hand written vectorisation. Slightly odd implementation as want +# Disable hand written vectorisation. Slightly odd implementation as want # to describe as --disable-hand-vec, but macro is enable (there is no enable action). AC_ARG_ENABLE([hand-vec], [AS_HELP_STRING([--disable-hand-vec], @@ -941,7 +957,7 @@ if test "x$with_velociraptor" != "xno"; then AC_PROG_FC AC_FC_LIBRARY_LDFLAGS if test "x$with_velociraptor" != "xyes" -a "x$with_velociraptor" != "x"; then - VELOCIRAPTOR_LIBS="-L$with_velociraptor -lstf -lstdc++ -lhdf5_cpp" + VELOCIRAPTOR_LIBS="-L$with_velociraptor -lvelociraptor -lstdc++ -lhdf5_cpp" CFLAGS="$CFLAGS -fopenmp" else VELOCIRAPTOR_LIBS="" @@ -950,7 +966,7 @@ if test "x$with_velociraptor" != "xno"; then have_velociraptor="yes" AC_CHECK_LIB( - [stf], + [velociraptor], [InitVelociraptor], [AC_DEFINE([HAVE_VELOCIRAPTOR],1,[The VELOCIraptor library appears to be present.])], [AC_MSG_ERROR(Cannot find VELOCIraptor library at $with_velociraptor)], @@ -986,16 +1002,55 @@ AC_CHECK_FUNC(pthread_setaffinity_np, AC_DEFINE([HAVE_SETAFFINITY],[1], AM_CONDITIONAL(HAVESETAFFINITY, [test "$ac_cv_func_pthread_setaffinity_np" = "yes"]) +# If available check for NUMA as well. There is a problem with the headers of +# this library, mainly that they do not pass the strict prototypes check when +# installed outside of the system directories. So we actually do this check +# in two phases. The basic ones first (before strict-prototypes is added to CFLAGS). have_numa="no" -if test "$ac_cv_func_pthread_setaffinity_np" = "yes"; then - # Check for libnuma. - AC_CHECK_HEADER([numa.h]) - if test "$ac_cv_header_numa_h" = "yes"; then - AC_CHECK_LIB([numa], [numa_available]) - have_numa="yes" - fi -fi +AC_ARG_WITH([numa], + [AS_HELP_STRING([--with-numa=PATH], + [Directory where the NUMA library exists @<:@yes/no@:>@] + )], + [with_numa="$withval"], + [with_numa="yes"] +) +if test "$ac_cv_func_pthread_setaffinity_np" = "yes" -a "x$with_numa" != "xno"; then + if test "x$with_numa" != "xyes" -a "x$with_numa" != "x"; then + NUMA_LIBS="-L$with_numa/lib -lnuma" + NUMA_INCS="-I$with_numa/include" + else + NUMA_LIBS="-lnuma" + NUMA_INCS="" + fi + + # Test for header file. + old_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $NUMA_INCS" + AC_CHECK_HEADER([numa.h]) + CPPFLAGS="$old_CPPFLAGS" + if test "$ac_cv_header_numa_h" = "yes"; then + + # If NUMA location is specified check if we have it. + if test "x$with_numa" != "xyes" -a "x$with_numa" != "x"; then + AC_CHECK_LIB([numa],[numa_available], + AC_DEFINE([HAVE_LIBNUMA],1,[The NUMA library appears to be present.]), + AC_MSG_ERROR(something is wrong with the NUMA library!), $NUMA_LIBS) + have_numa="yes" + else + AC_CHECK_LIB([numa],[numa_available],[have_numa="yes"],[have_numa="no"],$NUMA_LIBS) + if test "x$have_numa" != "xno"; then + AC_DEFINE([HAVE_LIBNUMA],1,[The NUMA library appears to be present.]) + fi + fi + fi + + # We can live without this. + if test "$have_numa" = "no"; then + NUMA_LIBS="" + fi +fi +AC_SUBST([NUMA_LIBS]) # Check for Intel and PowerPC intrinsics header optionally used by vector.h. AC_CHECK_HEADERS([immintrin.h]) @@ -1082,6 +1137,35 @@ if test "$enable_warn" != "no"; then [CFLAGS="$CFLAGS"],[$CFLAGS],[AC_LANG_SOURCE([int main(void){return 0;}])]) fi +# Second part of the NUMA library checks. We now decide if we need to use +# -isystem to get around the strict-prototypes problem. Assumes isystem +# is available when strict-prototypes is. +if test "$have_numa" != "no"; then + if test "x$with_numa" != "xyes" -a "x$with_numa" != "x"; then + case "$CFLAGS" in + *strict-prototypes*) + NUMA_INCS="-isystem$with_numa/include" + # This may still fail if CPATH is used, so we check if the + # headers are usable. + AS_UNSET(ac_cv_header_numa_h) + old_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $NUMA_INCS" + numa_failed="no" + AC_CHECK_HEADER([numa.h],[numa_failed="no"], + [numa_failed="yes"]) + if test "$numa_failed" = "yes"; then + AC_MSG_ERROR([Failed to compile the numa.h header file: you may need to set --enable-compiler-warnings to yes or no]) + fi + CPPFLAGS="$old_CPPFLAGS" + ;; + *) + NUMA_INCS="-I$with_numa/include" + ;; + esac + fi +fi +AC_SUBST([NUMA_INCS]) + # Various package configuration options. # Master subgrid options diff --git a/doc/RTD/source/CommandLineOptions/index.rst b/doc/RTD/source/CommandLineOptions/index.rst index 9fb9d784d6057e4d9aa4a923143d622e577f142c..de969730bebc6c20950086cb1ba9a20b94e01af6 100644 --- a/doc/RTD/source/CommandLineOptions/index.rst +++ b/doc/RTD/source/CommandLineOptions/index.rst @@ -22,7 +22,7 @@ can be found by typing ``./swift -h``:: -D, --drift-all Always drift all particles even the ones far from active particles. This emulates Gadget-[23] and GIZMO's default behaviours. - -F, --sourceterms + -F, --star-formation Run with star formation -g, --external-gravity Run with an external gravitational potential. -G, --self-gravity Run with self-gravity. -M, --multipole-reconstruction Reconstruct the multipoles every time-step. diff --git a/doc/RTD/source/GettingStarted/compiling_code.rst b/doc/RTD/source/GettingStarted/compiling_code.rst index c40f06965e15146c41bf210aec3b195032cef0e7..a0ce1c08eaf6b08a298ac4b720017273d4fa6559 100644 --- a/doc/RTD/source/GettingStarted/compiling_code.rst +++ b/doc/RTD/source/GettingStarted/compiling_code.rst @@ -38,7 +38,7 @@ METIS is used for domain decomposition and load balancing. libNUMA ~~~~~~~ -libNUMA is used to pin threads. +libNUMA is used to pin threads (but see INSTALL.swift). GSL ~~~ diff --git a/doc/RTD/source/VELOCIraptorInterface/stfalone.rst b/doc/RTD/source/VELOCIraptorInterface/stfalone.rst index 191d990c3d485bbc548c435d9b548686b9446397..e6bd0a72b207d7ca54bae67283326e7dcff51c02 100644 --- a/doc/RTD/source/VELOCIraptorInterface/stfalone.rst +++ b/doc/RTD/source/VELOCIraptorInterface/stfalone.rst @@ -23,24 +23,18 @@ git repository as:: git clone https://github.com/pelahi/VELOCIraptor-STF Similar to the SWIFT with VELOCIraptor configuration, we can use the -swift-interface branch to analyse individual snapshots. We can use this branch +master to analyse individual snapshots. We can use this branch by doing:: cd VELOCIraptor-STF git fetch - git checkout swift-interface -Again we need to copy the default SWIFT config file to a other config file by -doing:: +Again we need to configure VELOCIraptor:: - cd stf - cp Makefile.config.SWIFT-template Makefile.config + cmake . -DVR_USE_GAS=ON -Similar to configuring VELOCIraptor with swift we need to change the first 20 -lines of ``Makefile.config`` to work with our compiler, but we also need to -change the fact that we do not use the swift-interface but the standalone -version of the code, so change ``SWIFTINTERFACE="on"`` to -``SWIFTINTERFACE="off"``. +In this case, we do not need the SWIFT interface, therefore we can drop +this option (disabled by default). Compiling VELOCIraptor ---------------------- @@ -50,9 +44,7 @@ configuration with SWIFT. In this case we can compile the code as:: make -After this an additional folder is created in ``VELOCIraptor-stf/stf`` called -``bin``, in which the binary files of ``stf-gas`` is present (assuming you -run a simulation with SPH [#nosph]_) +After this an executable is created (``VELOCIraptor-stf/stf``). Running VELOCIraptor on a Snapshot ---------------------------------- @@ -61,10 +53,12 @@ After the code is compile the next step is using VELOCIraptor on a single snapshot of a simulation. The code has several options which can be used, which can be displayed by running a terminal command of an invalid letter like:: - ./stf-gas -h + ./stf -h which gives the information about the usage of the command:: + VELOCIraptor/STF running with MPI. Number of mpi threads: 1 + VELOCIraptor/STF running with OpenMP. Number of openmp threads: 8 USAGE: -C <configuration file (overrides other options)> @@ -80,13 +74,6 @@ which gives the information about the usage of the command:: ===== EXTRA OPTIONS REQUIRED FOR RAMSES INPUT ====== -t <ramses snapnumber> -After this we can run a VELOCIraptor on a snapshot as:: +After this we can run VELOCIraptor on a snapshot as:: - ./stf-gas -i input -o output -C configfile.txt - - -.. [#nosph] In the case that in the ``Makefile.config`` it is indicate that the - simulation does only contain dark matter this will reflect back on the - generated binary file. So ``stf-gas`` will change to ``stf`` in the case of - a dark matter only simulation. - + ./stf -i input -o output -C configfile.txt diff --git a/doc/RTD/source/VELOCIraptorInterface/stfwithswift.rst b/doc/RTD/source/VELOCIraptorInterface/stfwithswift.rst index 245b455d583d3ccdca02463e2afc6100e14dfb31..a663c37f93a6cede8c4528583c44183059414432 100644 --- a/doc/RTD/source/VELOCIraptorInterface/stfwithswift.rst +++ b/doc/RTD/source/VELOCIraptorInterface/stfwithswift.rst @@ -22,23 +22,17 @@ VELOCIraptor. This can be done by cloning the repository on GitHub_:: git clone https://github.com/pelahi/VELOCIraptor-STF -Currently the best version that works with SWIFT is the swift-interface branch +Currently the best version that works with SWIFT is the master of VELOCIraptor, to get this branch use:: cd VELOCIraptor-STF git fetch - git checkout swift-interface -To get the default that works with SWIFT simply copy the SWIFT template file in -the ``Makefile.config``:: +To get VELOCIraptor working with SWIFT simply use:: - cd stf - cp Makefile.config.SWIFT-template Makefile.config - -Depending on your compiler you want to change the first 20 lines of your -``Makefile.config`` to work with your compiler and whether you want to use MPI -or not. + cmake . -DVR_USE_SWIFT_INTERFACE=ON -DCMAKE_CXX_FLAGS="-fPIC" -DVR_USE_GAS=ON +If you wish to run swift without MPI, you will need to add ``-DVR_MPI=OFF``. Compiling VELOCIraptor ---------------------- @@ -46,13 +40,11 @@ Compiling VELOCIraptor After we downloaded the files and made a configuration file we can compile VELOCIraptor as follows:: - make lib - make libstf + make -j 4 -After the compilation of your code, there is an additional folder created in -the ``VELOCIraptor-stf/stf`` directory called ``lib`` this directory has the -library of VELOCIraptor and is required to run SWIFT with -VELOCIraptor. Note that VELOCIraptor needs a serial version of the +After the compilation of your code, you will find a static library ``libvelociraptor.a``, +that is required to run SWIFT with VELOCIraptor. +Note that VELOCIraptor needs a serial version of the HDF5 library, not a parallel build. Compiling SWIFT @@ -61,7 +53,7 @@ The next part is compiling SWIFT with VELOCIraptor and assumes you already downloaded SWIFT from the GitLab_, this can be done by running:: ./autogen.sh - ./configure --with-velociraptor=/path/to/VELOCIraptor-STF/stf/lib + ./configure --with-velociraptor=/path/to/VELOCIraptor-STF/src make In which ``./autogen.sh`` only needs to be run once after the code is cloned diff --git a/examples/ComovingSodShock_1D/makeIC.py b/examples/ComovingSodShock_1D/makeIC.py new file mode 100644 index 0000000000000000000000000000000000000000..371acc685cd00bd211e024ecc17c976ea5a08f68 --- /dev/null +++ b/examples/ComovingSodShock_1D/makeIC.py @@ -0,0 +1,123 @@ +############################################################################### + # This file is part of SWIFT. + # Copyright (c) 2016 Matthieu Schaller (matthieu.schaller@durham.ac.uk) + # 2018 Bert Vandenbroucke (bert.vandenbroucke@gmail.com) + # + # This program is free software: you can redistribute it and/or modify + # it under the terms of the GNU Lesser General Public License as published + # by the Free Software Foundation, either version 3 of the License, or + # (at your option) any later version. + # + # This program is distributed in the hope that it will be useful, + # but WITHOUT ANY WARRANTY; without even the implied warranty of + # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + # GNU General Public License for more details. + # + # You should have received a copy of the GNU Lesser General Public License + # along with this program. If not, see <http://www.gnu.org/licenses/>. + # + ############################################################################## + +import h5py +from numpy import * + +# Generates a swift IC file for the 1D Sod Shock in a periodic box + +unit_l_in_cgs = 3.086e18 +unit_m_in_cgs = 2.94e55 +unit_t_in_cgs = 3.086e18 + +# Parameters +gamma = 5./3. # Gas adiabatic index +numPart_L = 800 # Number of particles in the left state +x_min = -1. +x_max = 1. +rho_L = 1. # Density left state +rho_R = 0.125 # Density right state +v_L = 0. # Velocity left state +v_R = 0. # Velocity right state +P_L = 1. # Pressure left state +P_R = 0.1 # Pressure right state +a_beg = 0.001 +fileName = "sodShock.hdf5" + + +#--------------------------------------------------- + +# Find how many particles we actually have +boxSize = x_max - x_min +numPart_R = int(numPart_L * (rho_R / rho_L)) +numPart = numPart_L + numPart_R + +# Now get the distances +delta_L = (boxSize/2) / numPart_L +delta_R = (boxSize/2) / numPart_R +offset_L = delta_L / 2 +offset_R = delta_R / 2 + +# Build the arrays +coords = zeros((numPart, 3)) +v = zeros((numPart, 3)) +ids = linspace(1, numPart, numPart) +m = zeros(numPart) +h = zeros(numPart) +u = zeros(numPart) + +# Set the particles on the left +for i in range(numPart_L): + coords[i,0] = x_min + offset_L + i * delta_L + u[i] = P_L / (rho_L * (gamma - 1.)) + h[i] = 1.2348 * delta_L + m[i] = boxSize * rho_L / (2. * numPart_L) + v[i,0] = v_L + +# Set the particles on the right +for j in range(numPart_R): + i = numPart_L + j + coords[i,0] = offset_R + j * delta_R + u[i] = P_R / (rho_R * (gamma - 1.)) + h[i] = 1.2348 * delta_R + m[i] = boxSize * rho_R / (2. * numPart_R) + v[i,0] = v_R + +# Shift particles +coords[:,0] -= x_min + +u /= (a_beg**(3. * (gamma - 1.))) + +#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"] = 1 + +#Units +grp = file.create_group("/Units") +grp.attrs["Unit length in cgs (U_L)"] = unit_l_in_cgs +grp.attrs["Unit mass in cgs (U_M)"] = unit_m_in_cgs +grp.attrs["Unit time in cgs (U_t)"] = unit_t_in_cgs +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") +grp.create_dataset('Coordinates', data=coords, dtype='d') +grp.create_dataset('Velocities', data=v, dtype='f') +grp.create_dataset('Masses', data=m, dtype='f') +grp.create_dataset('SmoothingLength', data=h, dtype='f') +grp.create_dataset('InternalEnergy', data=u, dtype='f') +grp.create_dataset('ParticleIDs', data=ids, dtype='L') + + +file.close() + + diff --git a/examples/ComovingSodShock_1D/plotSolution.py b/examples/ComovingSodShock_1D/plotSolution.py new file mode 100644 index 0000000000000000000000000000000000000000..95674c04bfafd0cd549b69814df82f9a4f80a949 --- /dev/null +++ b/examples/ComovingSodShock_1D/plotSolution.py @@ -0,0 +1,310 @@ +############################################################################### + # This file is part of SWIFT. + # Copyright (c) 2016 Matthieu Schaller (matthieu.schaller@durham.ac.uk) + # 2018 Bert Vandenbroucke (bert.vandenbroucke@gmail.com) + # + # 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/>. + # + ############################################################################## + +# Computes the analytical solution of the Sod shock and plots the SPH answer + + +# Generates the analytical solution for the Sod shock test case +# The script works for a given left (x<0) and right (x>0) state and computes the solution at a later time t. +# This follows the solution given in (Toro, 2009) + + +# Parameters +gas_gamma = 5./3. # Polytropic index +rho_L = 1. # Density left state +rho_R = 0.125 # Density right state +v_L = 0. # Velocity left state +v_R = 0. # Velocity right state +P_L = 1. # Pressure left state +P_R = 0.1 # Pressure right state + + +import matplotlib +matplotlib.use("Agg") +from pylab import * +import h5py + +# Plot parameters +params = {'axes.labelsize': 10, +'axes.titlesize': 10, +'font.size': 12, +'legend.fontsize': 12, +'xtick.labelsize': 10, +'ytick.labelsize': 10, +'text.usetex': True, + 'figure.figsize' : (9.90,6.45), +'figure.subplot.left' : 0.045, +'figure.subplot.right' : 0.99, +'figure.subplot.bottom' : 0.05, +'figure.subplot.top' : 0.99, +'figure.subplot.wspace' : 0.15, +'figure.subplot.hspace' : 0.12, +'lines.markersize' : 6, +'lines.linewidth' : 3., +'text.latex.unicode': True +} +rcParams.update(params) +rc('font',**{'family':'sans-serif','sans-serif':['Times']}) + + +snap = int(sys.argv[1]) + + +# Read the simulation data +sim = h5py.File("sodShock_%04d.hdf5"%snap, "r") +boxSize = sim["/Header"].attrs["BoxSize"][0] +anow = sim["/Header"].attrs["Scale-factor"] +a_i = sim["/Cosmology"].attrs["a_beg"] +H_0 = sim["/Cosmology"].attrs["H0 [internal units]"] +time = 2. * (1. / np.sqrt(a_i) - 1. / np.sqrt(anow)) / H_0 +scheme = str(sim["/HydroScheme"].attrs["Scheme"]) +kernel = str(sim["/HydroScheme"].attrs["Kernel function"]) +neighbours = sim["/HydroScheme"].attrs["Kernel target N_ngb"] +eta = sim["/HydroScheme"].attrs["Kernel eta"] +git = str(sim["Code"].attrs["Git Revision"]) + +x = sim["/PartType0/Coordinates"][:,0] +v = sim["/PartType0/Velocities"][:,0] * anow +u = sim["/PartType0/InternalEnergy"][:] +S = sim["/PartType0/Entropy"][:] +P = sim["/PartType0/Pressure"][:] +rho = sim["/PartType0/Density"][:] +try: + alpha = sim["/PartType0/Viscosity"][:] + plot_alpha = True +except: + plot_alpha = False + +N = 1000 # Number of points +x_min = -1. +x_max = 1. + +x += x_min + +# --------------------------------------------------------------- +# Don't touch anything after this. +# --------------------------------------------------------------- + +c_L = sqrt(gas_gamma * P_L / rho_L) # Speed of the rarefaction wave +c_R = sqrt(gas_gamma * P_R / rho_R) # Speed of the shock front + +# Helpful variable +Gama = (gas_gamma - 1.) / (gas_gamma + 1.) +beta = (gas_gamma - 1.) / (2. * gas_gamma) + +# Characteristic function and its derivative, following Toro (2009) +def compute_f(P_3, P, c): + u = P_3 / P + if u > 1: + term1 = gas_gamma*((gas_gamma+1.)*u + gas_gamma-1.) + term2 = sqrt(2./term1) + fp = (u - 1.)*c*term2 + dfdp = c*term2/P + (u - 1.)*c/term2*(-1./term1**2)*gas_gamma*(gas_gamma+1.)/P + else: + fp = (u**beta - 1.)*(2.*c/(gas_gamma-1.)) + dfdp = 2.*c/(gas_gamma-1.)*beta*u**(beta-1.)/P + return (fp, dfdp) + +# Solution of the Riemann problem following Toro (2009) +def RiemannProblem(rho_L, P_L, v_L, rho_R, P_R, v_R): + P_new = ((c_L + c_R + (v_L - v_R)*0.5*(gas_gamma-1.))/(c_L / P_L**beta + c_R / P_R**beta))**(1./beta) + P_3 = 0.5*(P_R + P_L) + f_L = 1. + while fabs(P_3 - P_new) > 1e-6: + P_3 = P_new + (f_L, dfdp_L) = compute_f(P_3, P_L, c_L) + (f_R, dfdp_R) = compute_f(P_3, P_R, c_R) + f = f_L + f_R + (v_R - v_L) + df = dfdp_L + dfdp_R + dp = -f/df + prnew = P_3 + dp + v_3 = v_L - f_L + return (P_new, v_3) + + +# Solve Riemann problem for post-shock region +(P_3, v_3) = RiemannProblem(rho_L, P_L, v_L, rho_R, P_R, v_R) + +# Check direction of shocks and wave +shock_R = (P_3 > P_R) +shock_L = (P_3 > P_L) + +# Velocity of shock front and and rarefaction wave +if shock_R: + v_right = v_R + c_R**2*(P_3/P_R - 1.)/(gas_gamma*(v_3-v_R)) +else: + v_right = c_R + 0.5*(gas_gamma+1.)*v_3 - 0.5*(gas_gamma-1.)*v_R + +if shock_L: + v_left = v_L + c_L**2*(P_3/p_L - 1.)/(gas_gamma*(v_3-v_L)) +else: + v_left = c_L - 0.5*(gas_gamma+1.)*v_3 + 0.5*(gas_gamma-1.)*v_L + +# Compute position of the transitions +x_23 = -fabs(v_left) * time +if shock_L : + x_12 = -fabs(v_left) * time +else: + x_12 = -(c_L - v_L) * time + +x_34 = v_3 * time + +x_45 = fabs(v_right) * time +if shock_R: + x_56 = fabs(v_right) * time +else: + x_56 = (c_R + v_R) * time + + +# Prepare arrays +delta_x = (x_max - x_min) / N +x_s = arange(x_min, x_max, delta_x) +rho_s = zeros(N) +P_s = zeros(N) +v_s = zeros(N) + +# Compute solution in the different regions +for i in range(N): + if x_s[i] <= x_12: + rho_s[i] = rho_L + P_s[i] = P_L + v_s[i] = v_L + if x_s[i] >= x_12 and x_s[i] < x_23: + if shock_L: + rho_s[i] = rho_L*(Gama + P_3/P_L)/(1. + Gama * P_3/P_L) + P_s[i] = P_3 + v_s[i] = v_3 + else: + rho_s[i] = rho_L*(Gama * (0. - x_s[i])/(c_L * time) + Gama * v_L/c_L + (1.-Gama))**(2./(gas_gamma-1.)) + P_s[i] = P_L*(rho_s[i] / rho_L)**gas_gamma + v_s[i] = (1.-Gama)*(c_L -(0. - x_s[i]) / time) + Gama*v_L + if x_s[i] >= x_23 and x_s[i] < x_34: + if shock_L: + rho_s[i] = rho_L*(Gama + P_3/P_L)/(1+Gama * P_3/p_L) + else: + rho_s[i] = rho_L*(P_3 / P_L)**(1./gas_gamma) + P_s[i] = P_3 + v_s[i] = v_3 + if x_s[i] >= x_34 and x_s[i] < x_45: + if shock_R: + rho_s[i] = rho_R*(Gama + P_3/P_R)/(1. + Gama * P_3/P_R) + else: + rho_s[i] = rho_R*(P_3 / P_R)**(1./gas_gamma) + P_s[i] = P_3 + v_s[i] = v_3 + if x_s[i] >= x_45 and x_s[i] < x_56: + if shock_R: + rho_s[i] = rho_R + P_s[i] = P_R + v_s[i] = v_R + else: + rho_s[i] = rho_R*(Gama*(x_s[i])/(c_R*time) - Gama*v_R/c_R + (1.-Gama))**(2./(gas_gamma-1.)) + P_s[i] = p_R*(rho_s[i]/rho_R)**gas_gamma + v_s[i] = (1.-Gama)*(-c_R - (-x_s[i])/time) + Gama*v_R + if x_s[i] >= x_56: + rho_s[i] = rho_R + P_s[i] = P_R + v_s[i] = v_R + + +# Additional arrays +u_s = P_s / (rho_s * (gas_gamma - 1.)) #internal energy +s_s = P_s / rho_s**gas_gamma # entropic function + + +# Plot the interesting quantities +figure() + +# Velocity profile -------------------------------- +subplot(231) +plot(x, v, '.', color='r', ms=4.0) +plot(x_s, v_s, '--', color='k', alpha=0.8, lw=1.2) +xlabel("${\\rm{Position}}~x$", labelpad=0) +ylabel("${\\rm{Velocity}}~v_x$", labelpad=0) +xlim(-0.5, 0.5) +ylim(-0.1, 0.95) + +# Density profile -------------------------------- +subplot(232) +plot(x, rho, '.', color='r', ms=4.0) +plot(x_s, rho_s, '--', color='k', alpha=0.8, lw=1.2) +xlabel("${\\rm{Position}}~x$", labelpad=0) +ylabel("${\\rm{Density}}~\\rho$", labelpad=0) +xlim(-0.5, 0.5) +ylim(0.05, 1.1) + +# Pressure profile -------------------------------- +subplot(233) +plot(x, P, '.', color='r', ms=4.0) +plot(x_s, P_s, '--', color='k', alpha=0.8, lw=1.2) +xlabel("${\\rm{Position}}~x$", labelpad=0) +ylabel("${\\rm{Pressure}}~P$", labelpad=0) +xlim(-0.5, 0.5) +ylim(0.01, 1.1) + +# Internal energy profile ------------------------- +subplot(234) +plot(x, u, '.', color='r', ms=4.0) +plot(x_s, u_s, '--', color='k', alpha=0.8, lw=1.2) +xlabel("${\\rm{Position}}~x$", labelpad=0) +ylabel("${\\rm{Internal~Energy}}~u$", labelpad=0) +xlim(-0.5, 0.5) +ylim(0.8, 2.2) + +# Entropy/alpha profile --------------------------------- +subplot(235) + +if plot_alpha: + plot(x, alpha, '.', color='r', ms=4.0) + ylabel(r"${\rm{Viscosity}}~\alpha$", labelpad=0) + # Show location of shock + plot([x_56, x_56], [-100, 100], color="k", alpha=0.5, ls="dashed", lw=1.2) + ylim(0, 1) +else: + plot(x, S, '.', color='r', ms=4.0) + plot(x_s, s_s, '--', color='k', alpha=0.8, lw=1.2) + ylabel("${\\rm{Entropy}}~S$", labelpad=0) + ylim(0.8, 3.8) + +xlabel("${\\rm{Position}}~x$", labelpad=0) +xlim(-0.5, 0.5) + +# Information ------------------------------------- +subplot(236, frameon=False) + +z_now = 1. / anow - 1. +text(-0.49, 0.9, "Sod shock with $\\gamma=%.3f$ in 1D at $z=%.2f$"%(gas_gamma,z_now), fontsize=10) +text(-0.49, 0.8, "Left:~~ $(P_L, \\rho_L, v_L) = (%.3f, %.3f, %.3f)$"%(P_L, rho_L, v_L), fontsize=10) +text(-0.49, 0.7, "Right: $(P_R, \\rho_R, v_R) = (%.3f, %.3f, %.3f)$"%(P_R, rho_R, v_R), fontsize=10) +z_i = 1. / a_i - 1. +text(-0.49, 0.6, "Initial redshift: $%.2f$"%z_i, fontsize=10) +plot([-0.49, 0.1], [0.52, 0.52], 'k-', lw=1) +text(-0.49, 0.4, "$\\textsc{Swift}$ %s"%git, fontsize=10) +text(-0.49, 0.3, scheme, fontsize=10) +text(-0.49, 0.2, kernel, fontsize=10) +text(-0.49, 0.1, "$%.2f$ neighbours ($\\eta=%.3f$)"%(neighbours, eta), fontsize=10) +xlim(-0.5, 0.5) +ylim(0, 1) +xticks([]) +yticks([]) + +tight_layout() + +savefig("SodShock.png", dpi=200) diff --git a/examples/ComovingSodShock_1D/run.sh b/examples/ComovingSodShock_1D/run.sh new file mode 100755 index 0000000000000000000000000000000000000000..0d1fc4f1be8699929b2cf3b2ea2c8813ebef9f10 --- /dev/null +++ b/examples/ComovingSodShock_1D/run.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +# Generate the initial conditions if they are not present. +if [ ! -e sodShock.hdf5 ] +then + echo "Generating initial conditions for the 1D SodShock example..." + python makeIC.py +fi + +# Run SWIFT +../swift --cosmology --hydro --threads=1 sodShock.yml 2>&1 | tee output.log + +# Plot the result +python plotSolution.py 1 diff --git a/examples/ComovingSodShock_1D/sodShock.yml b/examples/ComovingSodShock_1D/sodShock.yml new file mode 100644 index 0000000000000000000000000000000000000000..2d7a5727cbbc2cd417527ce05d7a8ea8ea05dd71 --- /dev/null +++ b/examples/ComovingSodShock_1D/sodShock.yml @@ -0,0 +1,43 @@ +# Define the system of units to use internally. +InternalUnitSystem: + UnitMass_in_cgs: 2.94e55 # Grams + UnitLength_in_cgs: 3.086e18 # pc + UnitVelocity_in_cgs: 1. # km per s + UnitCurrent_in_cgs: 1 # Amperes + UnitTemp_in_cgs: 1 # Kelvin + +# Parameters governing the time integration +TimeIntegration: + dt_min: 1e-7 # The minimal time-step size of the simulation (in internal units). + dt_max: 1e-3 # The maximal time-step size of the simulation (in internal units). + +# Parameters governing the snapshots +Snapshots: + basename: sodShock # Common part of the name of output files + time_first: 0. # Time of the first output (in internal units) + delta_time: 1.06638 # Time difference between consecutive outputs (in internal units) + scale_factor_first: 0.001 + compression: 1 + +# Parameters governing the conserved quantities statistics +Statistics: + delta_time: 1.02 # 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: ./sodShock.hdf5 # The file to read + periodic: 1 + +Cosmology: + Omega_m: 1. + Omega_lambda: 0. + Omega_b: 1. + h: 1. + a_begin: 0.001 + a_end: 0.00106638 + diff --git a/examples/ComovingSodShock_2D/getGlass.sh b/examples/ComovingSodShock_2D/getGlass.sh new file mode 100755 index 0000000000000000000000000000000000000000..f4cb4ebcb4b452b2b123462bc97eed532f43ba25 --- /dev/null +++ b/examples/ComovingSodShock_2D/getGlass.sh @@ -0,0 +1,3 @@ +#!/bin/bash +wget http://virgodb.cosma.dur.ac.uk/swift-webstorage/ICs/glassPlane_128.hdf5 +wget http://virgodb.cosma.dur.ac.uk/swift-webstorage/ICs/glassPlane_48.hdf5 diff --git a/examples/ComovingSodShock_2D/makeIC.py b/examples/ComovingSodShock_2D/makeIC.py new file mode 100644 index 0000000000000000000000000000000000000000..51a408866047534f86fbded071d604ec294ed0b7 --- /dev/null +++ b/examples/ComovingSodShock_2D/makeIC.py @@ -0,0 +1,127 @@ +############################################################################### + # This file is part of SWIFT. + # Copyright (c) 2016 Matthieu Schaller (matthieu.schaller@durham.ac.uk) + # 2018 Bert Vandenbroucke (bert.vandenbroucke@gmail.com) + # + # This program is free software: you can redistribute it and/or modify + # it under the terms of the GNU Lesser General Public License as published + # by the Free Software Foundation, either version 3 of the License, or + # (at your option) any later version. + # + # This program is distributed in the hope that it will be useful, + # but WITHOUT ANY WARRANTY; without even the implied warranty of + # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + # GNU General Public License for more details. + # + # You should have received a copy of the GNU Lesser General Public License + # along with this program. If not, see <http://www.gnu.org/licenses/>. + # + ############################################################################## + +import h5py +from numpy import * + +# Generates a swift IC file for the 2D Sod Shock in a periodic box + +unit_l_in_cgs = 3.086e18 +unit_m_in_cgs = 2.94e55 +unit_t_in_cgs = 3.086e18 + +# Parameters +gamma = 5./3. # Gas adiabatic index +x_min = -1. +x_max = 1. +rho_L = 1. # Density left state +rho_R = 0.140625 # Density right state +v_L = 0. # Velocity left state +v_R = 0. # Velocity right state +P_L = 1. # Pressure left state +P_R = 0.1 # Pressure right state +a_beg = 0.001 +fileName = "sodShock.hdf5" + + +#--------------------------------------------------- +boxSize = (x_max - x_min) + +glass_L = h5py.File("glassPlane_128.hdf5", "r") +glass_R = h5py.File("glassPlane_48.hdf5", "r") + +pos_L = glass_L["/PartType0/Coordinates"][:,:] * 0.5 +pos_R = glass_R["/PartType0/Coordinates"][:,:] * 0.5 +h_L = glass_L["/PartType0/SmoothingLength"][:] * 0.5 +h_R = glass_R["/PartType0/SmoothingLength"][:] * 0.5 + +# Merge things +aa = pos_L - array([0.5, 0., 0.]) +pos_LL = append(pos_L, pos_L + array([0.5, 0., 0.]), axis=0) +pos_RR = append(pos_R, pos_R + array([0.5, 0., 0.]), axis=0) +pos = append(pos_LL - array([1.0, 0., 0.]), pos_RR, axis=0) +h_LL = append(h_L, h_L) +h_RR = append(h_R, h_R) +h = append(h_LL, h_RR) + +numPart_L = size(h_LL) +numPart_R = size(h_RR) +numPart = size(h) + +vol_L = 0.5 +vol_R = 0.5 + +# Generate extra arrays +v = zeros((numPart, 3)) +ids = linspace(1, numPart, numPart) +m = zeros(numPart) +u = zeros(numPart) + +for i in range(numPart): + x = pos[i,0] + + if x < 0: #left + u[i] = P_L / (rho_L * (gamma - 1.)) + m[i] = rho_L * vol_L / numPart_L + v[i,0] = v_L + else: #right + u[i] = P_R / (rho_R * (gamma - 1.)) + m[i] = rho_R * vol_R / numPart_R + v[i,0] = v_R + +# Shift particles +pos[:,0] -= x_min + +u /= (a_beg**(3. * (gamma - 1.))) + +#File +file = h5py.File(fileName, 'w') + +# Header +grp = file.create_group("/Header") +grp.attrs["BoxSize"] = [boxSize, 0.5, 1.0] +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"] = 2 + +#Units +grp = file.create_group("/Units") +grp.attrs["Unit length in cgs (U_L)"] = unit_l_in_cgs +grp.attrs["Unit mass in cgs (U_M)"] = unit_m_in_cgs +grp.attrs["Unit time in cgs (U_t)"] = unit_t_in_cgs +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") +grp.create_dataset('Coordinates', data=pos, dtype='d') +grp.create_dataset('Velocities', data=v, dtype='f') +grp.create_dataset('Masses', data=m, dtype='f') +grp.create_dataset('SmoothingLength', data=h, dtype='f') +grp.create_dataset('InternalEnergy', data=u, dtype='f') +grp.create_dataset('ParticleIDs', data=ids, dtype='L') + + +file.close() diff --git a/examples/ComovingSodShock_2D/plotSolution.py b/examples/ComovingSodShock_2D/plotSolution.py new file mode 100644 index 0000000000000000000000000000000000000000..8adb3cf5c550ab9724f6a8f34c1a1260a25712e1 --- /dev/null +++ b/examples/ComovingSodShock_2D/plotSolution.py @@ -0,0 +1,318 @@ +############################################################################### + # This file is part of SWIFT. + # Copyright (c) 2016 Matthieu Schaller (matthieu.schaller@durham.ac.uk) + # 2018 Bert Vandenbroucke (bert.vandenbroucke@gmail.com) + # + # 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/>. + # + ############################################################################## + +# Computes the analytical solution of the Sod shock and plots the SPH answer + + +# Generates the analytical solution for the Sod shock test case +# The script works for a given left (x<0) and right (x>0) state and computes the solution at a later time t. +# This follows the solution given in (Toro, 2009) + + +# Parameters +gas_gamma = 5./3. # Polytropic index +rho_L = 1. # Density left state +rho_R = 0.140625 # Density right state +v_L = 0. # Velocity left state +v_R = 0. # Velocity right state +P_L = 1. # Pressure left state +P_R = 0.1 # Pressure right state + + +import matplotlib +matplotlib.use("Agg") +from pylab import * +from scipy import stats +import h5py + +# Plot parameters +params = {'axes.labelsize': 10, +'axes.titlesize': 10, +'font.size': 12, +'legend.fontsize': 12, +'xtick.labelsize': 10, +'ytick.labelsize': 10, +'text.usetex': True, + 'figure.figsize' : (9.90,6.45), +'figure.subplot.left' : 0.045, +'figure.subplot.right' : 0.99, +'figure.subplot.bottom' : 0.05, +'figure.subplot.top' : 0.99, +'figure.subplot.wspace' : 0.15, +'figure.subplot.hspace' : 0.12, +'lines.markersize' : 6, +'lines.linewidth' : 3., +'text.latex.unicode': True +} +rcParams.update(params) +rc('font',**{'family':'sans-serif','sans-serif':['Times']}) + + +snap = int(sys.argv[1]) + + +# Read the simulation data +sim = h5py.File("sodShock_%04d.hdf5"%snap, "r") +boxSize = sim["/Header"].attrs["BoxSize"][0] +anow = sim["/Header"].attrs["Scale-factor"] +a_i = sim["/Cosmology"].attrs["a_beg"] +H_0 = sim["/Cosmology"].attrs["H0 [internal units]"] +time = 2. * (1. / np.sqrt(a_i) - 1. / np.sqrt(anow)) / H_0 +scheme = sim["/HydroScheme"].attrs["Scheme"] +kernel = sim["/HydroScheme"].attrs["Kernel function"] +neighbours = sim["/HydroScheme"].attrs["Kernel target N_ngb"] +eta = sim["/HydroScheme"].attrs["Kernel eta"] +git = sim["Code"].attrs["Git Revision"] + +x = sim["/PartType0/Coordinates"][:,0] +v = sim["/PartType0/Velocities"][:,0] * anow +u = sim["/PartType0/InternalEnergy"][:] +S = sim["/PartType0/Entropy"][:] +P = sim["/PartType0/Pressure"][:] +rho = sim["/PartType0/Density"][:] + +N = 1000 # Number of points +x_min = -1. +x_max = 1. +x += x_min + + +# Bin te data +x_bin_edge = np.arange(-0.6, 0.6, 0.02) +x_bin = 0.5*(x_bin_edge[1:] + x_bin_edge[:-1]) +rho_bin,_,_ = stats.binned_statistic(x, rho, statistic='mean', bins=x_bin_edge) +v_bin,_,_ = stats.binned_statistic(x, v, statistic='mean', bins=x_bin_edge) +P_bin,_,_ = stats.binned_statistic(x, P, statistic='mean', bins=x_bin_edge) +S_bin,_,_ = stats.binned_statistic(x, S, statistic='mean', bins=x_bin_edge) +u_bin,_,_ = stats.binned_statistic(x, u, statistic='mean', bins=x_bin_edge) +rho2_bin,_,_ = stats.binned_statistic(x, rho**2, statistic='mean', bins=x_bin_edge) +v2_bin,_,_ = stats.binned_statistic(x, v**2, statistic='mean', bins=x_bin_edge) +P2_bin,_,_ = stats.binned_statistic(x, P**2, statistic='mean', bins=x_bin_edge) +S2_bin,_,_ = stats.binned_statistic(x, S**2, statistic='mean', bins=x_bin_edge) +u2_bin,_,_ = stats.binned_statistic(x, u**2, statistic='mean', bins=x_bin_edge) +rho_sigma_bin = np.sqrt(rho2_bin - rho_bin**2) +v_sigma_bin = np.sqrt(v2_bin - v_bin**2) +P_sigma_bin = np.sqrt(P2_bin - P_bin**2) +S_sigma_bin = np.sqrt(S2_bin - S_bin**2) +u_sigma_bin = np.sqrt(u2_bin - u_bin**2) + + +# Analytic solution +c_L = sqrt(gas_gamma * P_L / rho_L) # Speed of the rarefaction wave +c_R = sqrt(gas_gamma * P_R / rho_R) # Speed of the shock front + +# Helpful variable +Gama = (gas_gamma - 1.) / (gas_gamma + 1.) +beta = (gas_gamma - 1.) / (2. * gas_gamma) + +# Characteristic function and its derivative, following Toro (2009) +def compute_f(P_3, P, c): + u = P_3 / P + if u > 1: + term1 = gas_gamma*((gas_gamma+1.)*u + gas_gamma-1.) + term2 = sqrt(2./term1) + fp = (u - 1.)*c*term2 + dfdp = c*term2/P + (u - 1.)*c/term2*(-1./term1**2)*gas_gamma*(gas_gamma+1.)/P + else: + fp = (u**beta - 1.)*(2.*c/(gas_gamma-1.)) + dfdp = 2.*c/(gas_gamma-1.)*beta*u**(beta-1.)/P + return (fp, dfdp) + +# Solution of the Riemann problem following Toro (2009) +def RiemannProblem(rho_L, P_L, v_L, rho_R, P_R, v_R): + P_new = ((c_L + c_R + (v_L - v_R)*0.5*(gas_gamma-1.))/(c_L / P_L**beta + c_R / P_R**beta))**(1./beta) + P_3 = 0.5*(P_R + P_L) + f_L = 1. + while fabs(P_3 - P_new) > 1e-6: + P_3 = P_new + (f_L, dfdp_L) = compute_f(P_3, P_L, c_L) + (f_R, dfdp_R) = compute_f(P_3, P_R, c_R) + f = f_L + f_R + (v_R - v_L) + df = dfdp_L + dfdp_R + dp = -f/df + prnew = P_3 + dp + v_3 = v_L - f_L + return (P_new, v_3) + + +# Solve Riemann problem for post-shock region +(P_3, v_3) = RiemannProblem(rho_L, P_L, v_L, rho_R, P_R, v_R) + +# Check direction of shocks and wave +shock_R = (P_3 > P_R) +shock_L = (P_3 > P_L) + +# Velocity of shock front and and rarefaction wave +if shock_R: + v_right = v_R + c_R**2*(P_3/P_R - 1.)/(gas_gamma*(v_3-v_R)) +else: + v_right = c_R + 0.5*(gas_gamma+1.)*v_3 - 0.5*(gas_gamma-1.)*v_R + +if shock_L: + v_left = v_L + c_L**2*(P_3/p_L - 1.)/(gas_gamma*(v_3-v_L)) +else: + v_left = c_L - 0.5*(gas_gamma+1.)*v_3 + 0.5*(gas_gamma-1.)*v_L + +# Compute position of the transitions +x_23 = -fabs(v_left) * time +if shock_L : + x_12 = -fabs(v_left) * time +else: + x_12 = -(c_L - v_L) * time + +x_34 = v_3 * time + +x_45 = fabs(v_right) * time +if shock_R: + x_56 = fabs(v_right) * time +else: + x_56 = (c_R + v_R) * time + + +# Prepare arrays +delta_x = (x_max - x_min) / N +x_s = arange(x_min, x_max, delta_x) +rho_s = zeros(N) +P_s = zeros(N) +v_s = zeros(N) + +# Compute solution in the different regions +for i in range(N): + if x_s[i] <= x_12: + rho_s[i] = rho_L + P_s[i] = P_L + v_s[i] = v_L + if x_s[i] >= x_12 and x_s[i] < x_23: + if shock_L: + rho_s[i] = rho_L*(Gama + P_3/P_L)/(1. + Gama * P_3/P_L) + P_s[i] = P_3 + v_s[i] = v_3 + else: + rho_s[i] = rho_L*(Gama * (0. - x_s[i])/(c_L * time) + Gama * v_L/c_L + (1.-Gama))**(2./(gas_gamma-1.)) + P_s[i] = P_L*(rho_s[i] / rho_L)**gas_gamma + v_s[i] = (1.-Gama)*(c_L -(0. - x_s[i]) / time) + Gama*v_L + if x_s[i] >= x_23 and x_s[i] < x_34: + if shock_L: + rho_s[i] = rho_L*(Gama + P_3/P_L)/(1+Gama * P_3/p_L) + else: + rho_s[i] = rho_L*(P_3 / P_L)**(1./gas_gamma) + P_s[i] = P_3 + v_s[i] = v_3 + if x_s[i] >= x_34 and x_s[i] < x_45: + if shock_R: + rho_s[i] = rho_R*(Gama + P_3/P_R)/(1. + Gama * P_3/P_R) + else: + rho_s[i] = rho_R*(P_3 / P_R)**(1./gas_gamma) + P_s[i] = P_3 + v_s[i] = v_3 + if x_s[i] >= x_45 and x_s[i] < x_56: + if shock_R: + rho_s[i] = rho_R + P_s[i] = P_R + v_s[i] = v_R + else: + rho_s[i] = rho_R*(Gama*(x_s[i])/(c_R*time) - Gama*v_R/c_R + (1.-Gama))**(2./(gas_gamma-1.)) + P_s[i] = p_R*(rho_s[i]/rho_R)**gas_gamma + v_s[i] = (1.-Gama)*(-c_R - (-x_s[i])/time) + Gama*v_R + if x_s[i] >= x_56: + rho_s[i] = rho_R + P_s[i] = P_R + v_s[i] = v_R + + +# Additional arrays +u_s = P_s / (rho_s * (gas_gamma - 1.)) #internal energy +s_s = P_s / rho_s**gas_gamma # entropic function + + +# Plot the interesting quantities +figure() + +# Velocity profile -------------------------------- +subplot(231) +plot(x, v, '.', color='r', ms=0.2) +plot(x_s, v_s, '--', color='k', alpha=0.8, lw=1.2) +errorbar(x_bin, v_bin, yerr=v_sigma_bin, fmt='.', ms=8.0, color='b', lw=1.2) +xlabel("${\\rm{Position}}~x$", labelpad=0) +ylabel("${\\rm{Velocity}}~v_x$", labelpad=0) +xlim(-0.5, 0.5) +ylim(-0.1, 0.95) + +# Density profile -------------------------------- +subplot(232) +plot(x, rho, '.', color='r', ms=0.2) +plot(x_s, rho_s, '--', color='k', alpha=0.8, lw=1.2) +errorbar(x_bin, rho_bin, yerr=rho_sigma_bin, fmt='.', ms=8.0, color='b', lw=1.2) +xlabel("${\\rm{Position}}~x$", labelpad=0) +ylabel("${\\rm{Density}}~\\rho$", labelpad=0) +xlim(-0.5, 0.5) +ylim(0.05, 1.1) + +# Pressure profile -------------------------------- +subplot(233) +plot(x, P, '.', color='r', ms=0.2) +plot(x_s, P_s, '--', color='k', alpha=0.8, lw=1.2) +errorbar(x_bin, P_bin, yerr=P_sigma_bin, fmt='.', ms=8.0, color='b', lw=1.2) +xlabel("${\\rm{Position}}~x$", labelpad=0) +ylabel("${\\rm{Pressure}}~P$", labelpad=0) +xlim(-0.5, 0.5) +ylim(0.01, 1.1) + +# Internal energy profile ------------------------- +subplot(234) +plot(x, u, '.', color='r', ms=0.2) +plot(x_s, u_s, '--', color='k', alpha=0.8, lw=1.2) +errorbar(x_bin, u_bin, yerr=u_sigma_bin, fmt='.', ms=8.0, color='b', lw=1.2) +xlabel("${\\rm{Position}}~x$", labelpad=0) +ylabel("${\\rm{Internal~Energy}}~u$", labelpad=0) +xlim(-0.5, 0.5) +ylim(0.8, 2.2) + +# Entropy profile --------------------------------- +subplot(235) +plot(x, S, '.', color='r', ms=0.2) +plot(x_s, s_s, '--', color='k', alpha=0.8, lw=1.2) +errorbar(x_bin, S_bin, yerr=S_sigma_bin, fmt='.', ms=8.0, color='b', lw=1.2) +xlabel("${\\rm{Position}}~x$", labelpad=0) +ylabel("${\\rm{Entropy}}~S$", labelpad=0) +xlim(-0.5, 0.5) +ylim(0.8, 3.8) + +# Information ------------------------------------- +subplot(236, frameon=False) + +z_now = 1. / anow - 1. +text(-0.49, 0.9, "Sod shock with $\\gamma=%.3f$ in 2D at $z=%.2f$"%(gas_gamma,z_now), fontsize=10) +text(-0.49, 0.8, "Left:~~ $(P_L, \\rho_L, v_L) = (%.3f, %.3f, %.3f)$"%(P_L, rho_L, v_L), fontsize=10) +text(-0.49, 0.7, "Right: $(P_R, \\rho_R, v_R) = (%.3f, %.3f, %.3f)$"%(P_R, rho_R, v_R), fontsize=10) +z_i = 1. / a_i - 1. +text(-0.49, 0.6, "Initial redshift: $%.2f$"%z_i, fontsize=10) +plot([-0.49, 0.1], [0.52, 0.52], 'k-', lw=1) +text(-0.49, 0.4, "$\\textsc{Swift}$ %s"%git, fontsize=10) +text(-0.49, 0.3, scheme, fontsize=10) +text(-0.49, 0.2, kernel, fontsize=10) +text(-0.49, 0.1, "$%.2f$ neighbours ($\\eta=%.3f$)"%(neighbours, eta), fontsize=10) +xlim(-0.5, 0.5) +ylim(0, 1) +xticks([]) +yticks([]) + +tight_layout() +savefig("SodShock.png", dpi=200) diff --git a/examples/ComovingSodShock_2D/run.sh b/examples/ComovingSodShock_2D/run.sh new file mode 100755 index 0000000000000000000000000000000000000000..bd6cc317d75a3bd415f074c9eaf48511ab693598 --- /dev/null +++ b/examples/ComovingSodShock_2D/run.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +# Generate the initial conditions if they are not present. +if [ ! -e glassPlane_128.hdf5 ] +then + echo "Fetching initial glass file for the Sod shock example..." + ./getGlass.sh +fi +if [ ! -e sodShock.hdf5 ] +then + echo "Generating initial conditions for the Sod shock example..." + python makeIC.py +fi + +# Run SWIFT +../swift --cosmology --hydro --threads=4 sodShock.yml 2>&1 | tee output.log + +python plotSolution.py 1 diff --git a/examples/ComovingSodShock_2D/sodShock.yml b/examples/ComovingSodShock_2D/sodShock.yml new file mode 100644 index 0000000000000000000000000000000000000000..2d7a5727cbbc2cd417527ce05d7a8ea8ea05dd71 --- /dev/null +++ b/examples/ComovingSodShock_2D/sodShock.yml @@ -0,0 +1,43 @@ +# Define the system of units to use internally. +InternalUnitSystem: + UnitMass_in_cgs: 2.94e55 # Grams + UnitLength_in_cgs: 3.086e18 # pc + UnitVelocity_in_cgs: 1. # km per s + UnitCurrent_in_cgs: 1 # Amperes + UnitTemp_in_cgs: 1 # Kelvin + +# Parameters governing the time integration +TimeIntegration: + dt_min: 1e-7 # The minimal time-step size of the simulation (in internal units). + dt_max: 1e-3 # The maximal time-step size of the simulation (in internal units). + +# Parameters governing the snapshots +Snapshots: + basename: sodShock # Common part of the name of output files + time_first: 0. # Time of the first output (in internal units) + delta_time: 1.06638 # Time difference between consecutive outputs (in internal units) + scale_factor_first: 0.001 + compression: 1 + +# Parameters governing the conserved quantities statistics +Statistics: + delta_time: 1.02 # 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: ./sodShock.hdf5 # The file to read + periodic: 1 + +Cosmology: + Omega_m: 1. + Omega_lambda: 0. + Omega_b: 1. + h: 1. + a_begin: 0.001 + a_end: 0.00106638 + diff --git a/examples/ComovingSodShock_3D/README.txt b/examples/ComovingSodShock_3D/README.txt new file mode 100644 index 0000000000000000000000000000000000000000..2b2f0d16207079f5d29e9ec281fe5255cc5886fb --- /dev/null +++ b/examples/ComovingSodShock_3D/README.txt @@ -0,0 +1,20 @@ +Cosmological version of the standard Sod shock test. + +In the co-moving coordinates that SWIFT uses, the Euler equations of +hydrodynamics have an elegant form with a few additional factors that +involve the scale factor a. For the specific case of a polytropic index +gamma = 5/3, all additional factors are in fact the same: 1/a^2. For +this case, hydrodynamics in the co-moving frame is identical to +hydrodynamics in a physical non-cosmological frame with a rescaled time +variable dt'=a^2*dt. + +We choose an Einstein-de Sitter cosmology with H(a)=H_0*a^(3/2) and a +box size of 1 pc and rescale the Sod shock initial conditions so that +the internal coordinates, density and pressure values are still the same +as for the original Sod shock in the non-cosmological case. We then +evolve the initial condition from z=999 to z=960.5, which corresponds to +a rescaled time interval dt'~0.12. If the co-moving coordinates are +implemented correctly, the resulting co-moving density, internal +velocity and co-moving pressure profiles should match those for the +non-co-moving variables in the ordinary non-cosmological Sod shock at +t=0.12. diff --git a/examples/ComovingSodShock_3D/getGlass.sh b/examples/ComovingSodShock_3D/getGlass.sh new file mode 100755 index 0000000000000000000000000000000000000000..f61b61d4e6c51b44576fd7cdd6242cb9f0133039 --- /dev/null +++ b/examples/ComovingSodShock_3D/getGlass.sh @@ -0,0 +1,3 @@ +#!/bin/bash +wget http://virgodb.cosma.dur.ac.uk/swift-webstorage/ICs/glassCube_64.hdf5 +wget http://virgodb.cosma.dur.ac.uk/swift-webstorage/ICs/glassCube_32.hdf5 diff --git a/examples/ComovingSodShock_3D/makeIC.py b/examples/ComovingSodShock_3D/makeIC.py new file mode 100644 index 0000000000000000000000000000000000000000..b6528bc5ab3670d4423945d194fc537c1bb672a1 --- /dev/null +++ b/examples/ComovingSodShock_3D/makeIC.py @@ -0,0 +1,126 @@ +############################################################################### + # This file is part of SWIFT. + # Copyright (c) 2016 Matthieu Schaller (matthieu.schaller@durham.ac.uk) + # 2018 Bert Vandenbroucke (bert.vandenbroucke@gmail.com) + # + # This program is free software: you can redistribute it and/or modify + # it under the terms of the GNU Lesser General Public License as published + # by the Free Software Foundation, either version 3 of the License, or + # (at your option) any later version. + # + # This program is distributed in the hope that it will be useful, + # but WITHOUT ANY WARRANTY; without even the implied warranty of + # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + # GNU General Public License for more details. + # + # You should have received a copy of the GNU Lesser General Public License + # along with this program. If not, see <http://www.gnu.org/licenses/>. + # + ############################################################################## + +import h5py +from numpy import * + +# Generates a swift IC file for the 3D Sod Shock in a periodic box + +unit_l_in_cgs = 3.086e18 +unit_m_in_cgs = 2.94e55 +unit_t_in_cgs = 3.086e18 + +# Parameters +gamma = 5./3. # Gas adiabatic index +x_min = -1. +x_max = 1. +rho_L = 1. # Density left state +rho_R = 0.125 # Density right state +v_L = 0. # Velocity left state +v_R = 0. # Velocity right state +P_L = 1. # Pressure left state +P_R = 0.1 # Pressure right state +a_beg = 0.001 +fileName = "sodShock.hdf5" + + +#--------------------------------------------------- +boxSize = (x_max - x_min) + +glass_L = h5py.File("glassCube_64.hdf5", "r") +glass_R = h5py.File("glassCube_32.hdf5", "r") + +pos_L = glass_L["/PartType0/Coordinates"][:,:] * 0.5 +pos_R = glass_R["/PartType0/Coordinates"][:,:] * 0.5 +h_L = glass_L["/PartType0/SmoothingLength"][:] * 0.5 +h_R = glass_R["/PartType0/SmoothingLength"][:] * 0.5 + +# Merge things +aa = pos_L - array([0.5, 0., 0.]) +pos_LL = append(pos_L, pos_L + array([0.5, 0., 0.]), axis=0) +pos_RR = append(pos_R, pos_R + array([0.5, 0., 0.]), axis=0) +pos = append(pos_LL - array([1.0, 0., 0.]), pos_RR, axis=0) +h_LL = append(h_L, h_L) +h_RR = append(h_R, h_R) +h = append(h_LL, h_RR) + +numPart_L = size(h_LL) +numPart_R = size(h_RR) +numPart = size(h) + +vol_L = (0.25 * boxSize)**2 * (0.5 * boxSize) +vol_R = (0.25 * boxSize)**2 * (0.5 * boxSize) + +# Generate extra arrays +v = zeros((numPart, 3)) +ids = linspace(1, numPart, numPart) +m = zeros(numPart) +u = zeros(numPart) + +for i in range(numPart): + x = pos[i,0] + + if x < 0: #left + u[i] = P_L / (rho_L * (gamma - 1.)) + m[i] = rho_L * vol_L / numPart_L + v[i,0] = v_L + else: #right + u[i] = P_R / (rho_R * (gamma - 1.)) + m[i] = rho_R * vol_R / numPart_R + v[i,0] = v_R + +# Shift particles +pos[:,0] -= x_min + +u /= (a_beg**(3. * (gamma - 1.))) + +#File +file = h5py.File(fileName, 'w') + +# Header +grp = file.create_group("/Header") +grp.attrs["BoxSize"] = [boxSize, 0.25 * boxSize, 0.25 * 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 + +#Units +grp = file.create_group("/Units") +grp.attrs["Unit length in cgs (U_L)"] = unit_l_in_cgs +grp.attrs["Unit mass in cgs (U_M)"] = unit_m_in_cgs +grp.attrs["Unit time in cgs (U_t)"] = unit_t_in_cgs +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") +grp.create_dataset('Coordinates', data=pos, dtype='d') +grp.create_dataset('Velocities', data=v, dtype='f') +grp.create_dataset('Masses', data=m, dtype='f') +grp.create_dataset('SmoothingLength', data=h, dtype='f') +grp.create_dataset('InternalEnergy', data=u, dtype='f') +grp.create_dataset('ParticleIDs', data=ids, dtype='L') + +file.close() diff --git a/examples/ComovingSodShock_3D/plotSolution.py b/examples/ComovingSodShock_3D/plotSolution.py new file mode 100644 index 0000000000000000000000000000000000000000..f05a385e8620b18189d2e7abca8aebb8ae65060e --- /dev/null +++ b/examples/ComovingSodShock_3D/plotSolution.py @@ -0,0 +1,316 @@ +############################################################################### + # This file is part of SWIFT. + # Copyright (c) 2016 Matthieu Schaller (matthieu.schaller@durham.ac.uk) + # 2018 Bert Vandenbroucke (bert.vandenbroucke@gmail.com) + # + # 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/>. + # + ############################################################################## + +# Computes the analytical solution of the Sod shock and plots the SPH answer + + +# Generates the analytical solution for the Sod shock test case +# The script works for a given left (x<0) and right (x>0) state and computes the solution at a later time t. +# This follows the solution given in (Toro, 2009) + + +# Parameters +gas_gamma = 5./3. # Polytropic index +rho_L = 1. # Density left state +rho_R = 0.125 # Density right state +v_L = 0. # Velocity left state +v_R = 0. # Velocity right state +P_L = 1. # Pressure left state +P_R = 0.1 # Pressure right state + + +import matplotlib +matplotlib.use("Agg") +from pylab import * +from scipy import stats +import h5py + +# Plot parameters +params = {'axes.labelsize': 10, +'axes.titlesize': 10, +'font.size': 12, +'legend.fontsize': 12, +'xtick.labelsize': 10, +'ytick.labelsize': 10, +'text.usetex': True, + 'figure.figsize' : (9.90,6.45), +'figure.subplot.left' : 0.045, +'figure.subplot.right' : 0.99, +'figure.subplot.bottom' : 0.05, +'figure.subplot.top' : 0.99, +'figure.subplot.wspace' : 0.15, +'figure.subplot.hspace' : 0.12, +'lines.markersize' : 6, +'lines.linewidth' : 3., +'text.latex.unicode': True +} +rcParams.update(params) +rc('font',**{'family':'sans-serif','sans-serif':['Times']}) + + +snap = int(sys.argv[1]) + + +# Read the simulation data +sim = h5py.File("sodShock_%04d.hdf5"%snap, "r") +boxSize = sim["/Header"].attrs["BoxSize"][0] +anow = sim["/Header"].attrs["Scale-factor"] +a_i = sim["/Cosmology"].attrs["a_beg"] +H_0 = sim["/Cosmology"].attrs["H0 [internal units]"] +time = 2. * (1. / np.sqrt(a_i) - 1. / np.sqrt(anow)) / H_0 +scheme = sim["/HydroScheme"].attrs["Scheme"] +kernel = sim["/HydroScheme"].attrs["Kernel function"] +neighbours = sim["/HydroScheme"].attrs["Kernel target N_ngb"] +eta = sim["/HydroScheme"].attrs["Kernel eta"] +git = sim["Code"].attrs["Git Revision"] + +x = sim["/PartType0/Coordinates"][:,0] +v = sim["/PartType0/Velocities"][:,0] * anow +u = sim["/PartType0/InternalEnergy"][:] +S = sim["/PartType0/Entropy"][:] +P = sim["/PartType0/Pressure"][:] +rho = sim["/PartType0/Density"][:] + +x_min = -1. +x_max = 1. +x += x_min +N = 1000 + +# Bin te data +x_bin_edge = np.arange(-0.6, 0.6, 0.02) +x_bin = 0.5*(x_bin_edge[1:] + x_bin_edge[:-1]) +rho_bin,_,_ = stats.binned_statistic(x, rho, statistic='mean', bins=x_bin_edge) +v_bin,_,_ = stats.binned_statistic(x, v, statistic='mean', bins=x_bin_edge) +P_bin,_,_ = stats.binned_statistic(x, P, statistic='mean', bins=x_bin_edge) +S_bin,_,_ = stats.binned_statistic(x, S, statistic='mean', bins=x_bin_edge) +u_bin,_,_ = stats.binned_statistic(x, u, statistic='mean', bins=x_bin_edge) +rho2_bin,_,_ = stats.binned_statistic(x, rho**2, statistic='mean', bins=x_bin_edge) +v2_bin,_,_ = stats.binned_statistic(x, v**2, statistic='mean', bins=x_bin_edge) +P2_bin,_,_ = stats.binned_statistic(x, P**2, statistic='mean', bins=x_bin_edge) +S2_bin,_,_ = stats.binned_statistic(x, S**2, statistic='mean', bins=x_bin_edge) +u2_bin,_,_ = stats.binned_statistic(x, u**2, statistic='mean', bins=x_bin_edge) +rho_sigma_bin = np.sqrt(rho2_bin - rho_bin**2) +v_sigma_bin = np.sqrt(v2_bin - v_bin**2) +P_sigma_bin = np.sqrt(P2_bin - P_bin**2) +S_sigma_bin = np.sqrt(S2_bin - S_bin**2) +u_sigma_bin = np.sqrt(u2_bin - u_bin**2) + + +# Analytic solution +c_L = sqrt(gas_gamma * P_L / rho_L) # Speed of the rarefaction wave +c_R = sqrt(gas_gamma * P_R / rho_R) # Speed of the shock front + +# Helpful variable +Gama = (gas_gamma - 1.) / (gas_gamma + 1.) +beta = (gas_gamma - 1.) / (2. * gas_gamma) + +# Characteristic function and its derivative, following Toro (2009) +def compute_f(P_3, P, c): + u = P_3 / P + if u > 1: + term1 = gas_gamma*((gas_gamma+1.)*u + gas_gamma-1.) + term2 = sqrt(2./term1) + fp = (u - 1.)*c*term2 + dfdp = c*term2/P + (u - 1.)*c/term2*(-1./term1**2)*gas_gamma*(gas_gamma+1.)/P + else: + fp = (u**beta - 1.)*(2.*c/(gas_gamma-1.)) + dfdp = 2.*c/(gas_gamma-1.)*beta*u**(beta-1.)/P + return (fp, dfdp) + +# Solution of the Riemann problem following Toro (2009) +def RiemannProblem(rho_L, P_L, v_L, rho_R, P_R, v_R): + P_new = ((c_L + c_R + (v_L - v_R)*0.5*(gas_gamma-1.))/(c_L / P_L**beta + c_R / P_R**beta))**(1./beta) + P_3 = 0.5*(P_R + P_L) + f_L = 1. + while fabs(P_3 - P_new) > 1e-6: + P_3 = P_new + (f_L, dfdp_L) = compute_f(P_3, P_L, c_L) + (f_R, dfdp_R) = compute_f(P_3, P_R, c_R) + f = f_L + f_R + (v_R - v_L) + df = dfdp_L + dfdp_R + dp = -f/df + prnew = P_3 + dp + v_3 = v_L - f_L + return (P_new, v_3) + + +# Solve Riemann problem for post-shock region +(P_3, v_3) = RiemannProblem(rho_L, P_L, v_L, rho_R, P_R, v_R) + +# Check direction of shocks and wave +shock_R = (P_3 > P_R) +shock_L = (P_3 > P_L) + +# Velocity of shock front and and rarefaction wave +if shock_R: + v_right = v_R + c_R**2*(P_3/P_R - 1.)/(gas_gamma*(v_3-v_R)) +else: + v_right = c_R + 0.5*(gas_gamma+1.)*v_3 - 0.5*(gas_gamma-1.)*v_R + +if shock_L: + v_left = v_L + c_L**2*(P_3/p_L - 1.)/(gas_gamma*(v_3-v_L)) +else: + v_left = c_L - 0.5*(gas_gamma+1.)*v_3 + 0.5*(gas_gamma-1.)*v_L + +# Compute position of the transitions +x_23 = -fabs(v_left) * time +if shock_L : + x_12 = -fabs(v_left) * time +else: + x_12 = -(c_L - v_L) * time + +x_34 = v_3 * time + +x_45 = fabs(v_right) * time +if shock_R: + x_56 = fabs(v_right) * time +else: + x_56 = (c_R + v_R) * time + + +# Prepare arrays +delta_x = (x_max - x_min) / N +x_s = arange(x_min, x_max, delta_x) +rho_s = zeros(N) +P_s = zeros(N) +v_s = zeros(N) + +# Compute solution in the different regions +for i in range(N): + if x_s[i] <= x_12: + rho_s[i] = rho_L + P_s[i] = P_L + v_s[i] = v_L + if x_s[i] >= x_12 and x_s[i] < x_23: + if shock_L: + rho_s[i] = rho_L*(Gama + P_3/P_L)/(1. + Gama * P_3/P_L) + P_s[i] = P_3 + v_s[i] = v_3 + else: + rho_s[i] = rho_L*(Gama * (0. - x_s[i])/(c_L * time) + Gama * v_L/c_L + (1.-Gama))**(2./(gas_gamma-1.)) + P_s[i] = P_L*(rho_s[i] / rho_L)**gas_gamma + v_s[i] = (1.-Gama)*(c_L -(0. - x_s[i]) / time) + Gama*v_L + if x_s[i] >= x_23 and x_s[i] < x_34: + if shock_L: + rho_s[i] = rho_L*(Gama + P_3/P_L)/(1+Gama * P_3/p_L) + else: + rho_s[i] = rho_L*(P_3 / P_L)**(1./gas_gamma) + P_s[i] = P_3 + v_s[i] = v_3 + if x_s[i] >= x_34 and x_s[i] < x_45: + if shock_R: + rho_s[i] = rho_R*(Gama + P_3/P_R)/(1. + Gama * P_3/P_R) + else: + rho_s[i] = rho_R*(P_3 / P_R)**(1./gas_gamma) + P_s[i] = P_3 + v_s[i] = v_3 + if x_s[i] >= x_45 and x_s[i] < x_56: + if shock_R: + rho_s[i] = rho_R + P_s[i] = P_R + v_s[i] = v_R + else: + rho_s[i] = rho_R*(Gama*(x_s[i])/(c_R*time) - Gama*v_R/c_R + (1.-Gama))**(2./(gas_gamma-1.)) + P_s[i] = p_R*(rho_s[i]/rho_R)**gas_gamma + v_s[i] = (1.-Gama)*(-c_R - (-x_s[i])/time) + Gama*v_R + if x_s[i] >= x_56: + rho_s[i] = rho_R + P_s[i] = P_R + v_s[i] = v_R + + +# Additional arrays +u_s = P_s / (rho_s * (gas_gamma - 1.)) #internal energy +s_s = P_s / rho_s**gas_gamma # entropic function + +# Plot the interesting quantities +figure() + +# Velocity profile -------------------------------- +subplot(231) +plot(x, v, '.', color='r', ms=0.5, alpha=0.2) +plot(x_s, v_s, '--', color='k', alpha=0.8, lw=1.2) +errorbar(x_bin, v_bin, yerr=v_sigma_bin, fmt='.', ms=8.0, color='b', lw=1.2) +xlabel("${\\rm{Position}}~x$", labelpad=0) +ylabel("${\\rm{Velocity}}~v_x$", labelpad=0) +xlim(-0.5, 0.5) +ylim(-0.1, 0.95) + +# Density profile -------------------------------- +subplot(232) +plot(x, rho, '.', color='r', ms=0.5, alpha=0.2) +plot(x_s, rho_s, '--', color='k', alpha=0.8, lw=1.2) +errorbar(x_bin, rho_bin, yerr=rho_sigma_bin, fmt='.', ms=8.0, color='b', lw=1.2) +xlabel("${\\rm{Position}}~x$", labelpad=0) +ylabel("${\\rm{Density}}~\\rho$", labelpad=0) +xlim(-0.5, 0.5) +ylim(0.05, 1.1) + +# Pressure profile -------------------------------- +subplot(233) +plot(x, P, '.', color='r', ms=0.5, alpha=0.2) +plot(x_s, P_s, '--', color='k', alpha=0.8, lw=1.2) +errorbar(x_bin, P_bin, yerr=P_sigma_bin, fmt='.', ms=8.0, color='b', lw=1.2) +xlabel("${\\rm{Position}}~x$", labelpad=0) +ylabel("${\\rm{Pressure}}~P$", labelpad=0) +xlim(-0.5, 0.5) +ylim(0.01, 1.1) + +# Internal energy profile ------------------------- +subplot(234) +plot(x, u, '.', color='r', ms=0.5, alpha=0.2) +plot(x_s, u_s, '--', color='k', alpha=0.8, lw=1.2) +errorbar(x_bin, u_bin, yerr=u_sigma_bin, fmt='.', ms=8.0, color='b', lw=1.2) +xlabel("${\\rm{Position}}~x$", labelpad=0) +ylabel("${\\rm{Internal~Energy}}~u$", labelpad=0) +xlim(-0.5, 0.5) +ylim(0.8, 2.2) + +# Entropy profile --------------------------------- +subplot(235) +plot(x, S, '.', color='r', ms=0.5, alpha=0.2) +plot(x_s, s_s, '--', color='k', alpha=0.8, lw=1.2) +errorbar(x_bin, S_bin, yerr=S_sigma_bin, fmt='.', ms=8.0, color='b', lw=1.2) +xlabel("${\\rm{Position}}~x$", labelpad=0) +ylabel("${\\rm{Entropy}}~S$", labelpad=0) +xlim(-0.5, 0.5) +ylim(0.8, 3.8) + +# Information ------------------------------------- +subplot(236, frameon=False) + +znow = 1. / anow - 1. +text(-0.49, 0.9, "Sod shock with $\\gamma=%.3f$ in 3D at $z=%.2f$"%(gas_gamma,znow), fontsize=10) +text(-0.49, 0.8, "Left:~~ $(P_L, \\rho_L, v_L) = (%.3f, %.3f, %.3f)$"%(P_L, rho_L, v_L), fontsize=10) +text(-0.49, 0.7, "Right: $(P_R, \\rho_R, v_R) = (%.3f, %.3f, %.3f)$"%(P_R, rho_R, v_R), fontsize=10) +z_i = 1. / a_i - 1. +text(-0.49, 0.6, "Initial redshift: $%.2f$"%z_i, fontsize = 10) +plot([-0.49, 0.1], [0.52, 0.52], 'k-', lw=1) +text(-0.49, 0.4, "$\\textsc{Swift}$ %s"%git, fontsize=10) +text(-0.49, 0.3, scheme, fontsize=10) +text(-0.49, 0.2, kernel, fontsize=10) +text(-0.49, 0.1, "$%.2f$ neighbours ($\\eta=%.3f$)"%(neighbours, eta), fontsize=10) +xlim(-0.5, 0.5) +ylim(0, 1) +xticks([]) +yticks([]) + +tight_layout() +savefig("SodShock.png", dpi=200) diff --git a/examples/ComovingSodShock_3D/run.sh b/examples/ComovingSodShock_3D/run.sh new file mode 100755 index 0000000000000000000000000000000000000000..00e4f669fdb1347ab1b34cfa11821ca011b73120 --- /dev/null +++ b/examples/ComovingSodShock_3D/run.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +# Generate the initial conditions if they are not present. +if [ ! -e glassCube_64.hdf5 ] +then + echo "Fetching initial glass file for the Sod shock example..." + ./getGlass.sh +fi +if [ ! -e sodShock.hdf5 ] +then + echo "Generating initial conditions for the Sod shock example..." + python makeIC.py +fi + +# Run SWIFT +../swift --cosmology --hydro --threads=4 sodShock.yml 2>&1 | tee output.log + +python plotSolution.py 1 diff --git a/examples/ComovingSodShock_3D/sodShock.yml b/examples/ComovingSodShock_3D/sodShock.yml new file mode 100644 index 0000000000000000000000000000000000000000..2d7a5727cbbc2cd417527ce05d7a8ea8ea05dd71 --- /dev/null +++ b/examples/ComovingSodShock_3D/sodShock.yml @@ -0,0 +1,43 @@ +# Define the system of units to use internally. +InternalUnitSystem: + UnitMass_in_cgs: 2.94e55 # Grams + UnitLength_in_cgs: 3.086e18 # pc + UnitVelocity_in_cgs: 1. # km per s + UnitCurrent_in_cgs: 1 # Amperes + UnitTemp_in_cgs: 1 # Kelvin + +# Parameters governing the time integration +TimeIntegration: + dt_min: 1e-7 # The minimal time-step size of the simulation (in internal units). + dt_max: 1e-3 # The maximal time-step size of the simulation (in internal units). + +# Parameters governing the snapshots +Snapshots: + basename: sodShock # Common part of the name of output files + time_first: 0. # Time of the first output (in internal units) + delta_time: 1.06638 # Time difference between consecutive outputs (in internal units) + scale_factor_first: 0.001 + compression: 1 + +# Parameters governing the conserved quantities statistics +Statistics: + delta_time: 1.02 # 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: ./sodShock.hdf5 # The file to read + periodic: 1 + +Cosmology: + Omega_m: 1. + Omega_lambda: 0. + Omega_b: 1. + h: 1. + a_begin: 0.001 + a_end: 0.00106638 + diff --git a/examples/CoolingRates/Makefile.am b/examples/CoolingRates/Makefile.am index 058cdaf2efa3df3647af6f6e0263f65a0e515a15..f81188298d733be2be84cd0be02728c5c6c64113 100644 --- a/examples/CoolingRates/Makefile.am +++ b/examples/CoolingRates/Makefile.am @@ -15,12 +15,12 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. # Add the source directory and the non-standard paths to the included library headers to CFLAGS -AM_CFLAGS = -I$(top_srcdir)/src $(HDF5_CPPFLAGS) $(GSL_INCS) $(FFTW_INCS) +AM_CFLAGS = -I$(top_srcdir)/src $(HDF5_CPPFLAGS) $(GSL_INCS) $(FFTW_INCS) $(NUMA_INCS) -AM_LDFLAGS = $(HDF5_LDFLAGS) $(HDF5_LIBS) $(FFTW_LIBS) $(TCMALLOC_LIBS) $(JEMALLOC_LIBS) $(TBBMALLOC_LIBS) $(GRACKLE_LIBS) $(GSL_LIBS) $(PROFILER_LIBS) +AM_LDFLAGS = $(HDF5_LDFLAGS) $(HDF5_LIBS) $(FFTW_LIBS) $(NUMA_LIBS) $(TCMALLOC_LIBS) $(JEMALLOC_LIBS) $(TBBMALLOC_LIBS) $(GRACKLE_LIBS) $(GSL_LIBS) $(PROFILER_LIBS) # Extra libraries. -EXTRA_LIBS = $(HDF5_LIBS) $(FFTW_LIBS) $(PROFILER_LIBS) $(TCMALLOC_LIBS) $(JEMALLOC_LIBS) $(TBBMALLOC_LIBS) $(GRACKLE_LIBS) $(VELOCIRAPTOR_LIBS) $(GSL_LIBS) +EXTRA_LIBS = $(HDF5_LIBS) $(FFTW_LIBS) $(NUMA_LIBS) $(PROFILER_LIBS) $(TCMALLOC_LIBS) $(JEMALLOC_LIBS) $(TBBMALLOC_LIBS) $(GRACKLE_LIBS) $(VELOCIRAPTOR_LIBS) $(GSL_LIBS) # Programs. bin_PROGRAMS = cooling_rates diff --git a/examples/EAGLE_12/eagle_12.yml b/examples/EAGLE_12/eagle_12.yml index 90b546f311be7e617929eb53146aa7b3daf8114c..1d19320491130ce6d98ac8cd0adff8753f2c2e54 100644 --- a/examples/EAGLE_12/eagle_12.yml +++ b/examples/EAGLE_12/eagle_12.yml @@ -72,9 +72,8 @@ EAGLEChemistry: # Solar abundances SulphurOverSilicon: 0.6054160 EagleCooling: - filename: /cosma5/data/Eagle/BG_Tables/CoolingTables/ + filename: ./coolingtables/ reionisation_redshift: 11.5 - he_reion_z_center: 3.5 - he_reion_z_sigma: 0.5 - he_reion_ev_pH: 2.0 - + He_reion_z_centre: 3.5 + He_reion_z_sigma: 0.5 + He_reion_ev_pH: 2.0 diff --git a/examples/EAGLE_25/eagle_25.yml b/examples/EAGLE_25/eagle_25.yml index bd74473d13acd235a703d7391d187495fc33204f..3e1e5907df7bf76e8ad96a1c9d3c667945c090c8 100644 --- a/examples/EAGLE_25/eagle_25.yml +++ b/examples/EAGLE_25/eagle_25.yml @@ -81,9 +81,9 @@ EAGLEChemistry: # Solar abundances SulphurOverSilicon: 0.6054160 EagleCooling: - filename: /cosma5/data/Eagle/BG_Tables/CoolingTables/ + filename: ./coolingtables/ reionisation_redshift: 11.5 - he_reion_z_center: 3.5 - he_reion_z_sigma: 0.5 - he_reion_ev_pH: 2.0 + He_reion_z_centre: 3.5 + He_reion_z_sigma: 0.5 + He_reion_ev_pH: 2.0 diff --git a/examples/EAGLE_50/eagle_50.yml b/examples/EAGLE_50/eagle_50.yml index b86a3d87ddc5561002a5dc3adf2e82d47fb1b02f..87bef197cd357116d4b67015c5f58774c23d36b7 100644 --- a/examples/EAGLE_50/eagle_50.yml +++ b/examples/EAGLE_50/eagle_50.yml @@ -74,8 +74,8 @@ EAGLEChemistry: # Solar abundances SulphurOverSilicon: 0.6054160 EagleCooling: - filename: /cosma5/data/Eagle/BG_Tables/CoolingTables/ + filename: ./coolingtables/ reionisation_redshift: 11.5 - he_reion_z_center: 3.5 - he_reion_z_sigma: 0.5 - he_reion_ev_pH: 2.0 + He_reion_z_centre: 3.5 + He_reion_z_sigma: 0.5 + He_reion_ev_pH: 2.0 \ No newline at end of file diff --git a/examples/EAGLE_6/eagle_6.yml b/examples/EAGLE_6/eagle_6.yml index 494f48b833f124ffcdc816f170b6b077c4c59857..95a5d3398f13d42700963a0abbae118083662440 100644 --- a/examples/EAGLE_6/eagle_6.yml +++ b/examples/EAGLE_6/eagle_6.yml @@ -85,8 +85,8 @@ EAGLEChemistry: # Solar abundances SulphurOverSilicon: 0.6054160 EagleCooling: - filename: /cosma5/data/Eagle/BG_Tables/CoolingTables/ + filename: ./coolingtables/ reionisation_redshift: 11.5 - he_reion_z_center: 3.5 - he_reion_z_sigma: 0.5 - he_reion_ev_pH: 2.0 + He_reion_z_centre: 3.5 + He_reion_z_sigma: 0.5 + He_reion_ev_pH: 2.0 \ No newline at end of file diff --git a/examples/Makefile.am b/examples/Makefile.am index fae4e132cdf1ac24f293060d6e3a293729d109f4..e6f014ca7bc596af803af2d6963b32c02915dd93 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -20,13 +20,13 @@ MYFLAGS = # Add the source directory and the non-standard paths to the included library headers to CFLAGS AM_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/argparse $(HDF5_CPPFLAGS) \ - $(GSL_INCS) $(FFTW_INCS) $(GRACKLE_INCS) + $(GSL_INCS) $(FFTW_INCS) $(NUMA_INCS) $(GRACKLE_INCS) AM_LDFLAGS = $(HDF5_LDFLAGS) # Extra libraries. -EXTRA_LIBS = $(HDF5_LIBS) $(FFTW_LIBS) $(PROFILER_LIBS) $(TCMALLOC_LIBS) \ - $(JEMALLOC_LIBS) $(TBBMALLOC_LIBS) $(GRACKLE_LIBS) \ +EXTRA_LIBS = $(HDF5_LIBS) $(FFTW_LIBS) $(NUMA_LIBS) $(PROFILER_LIBS) \ + $(TCMALLOC_LIBS) $(JEMALLOC_LIBS) $(TBBMALLOC_LIBS) $(GRACKLE_LIBS) \ $(VELOCIRAPTOR_LIBS) $(GSL_LIBS) # MPI libraries. diff --git a/examples/SmallCosmoVolume_cooling/small_cosmo_volume.yml b/examples/SmallCosmoVolume_cooling/small_cosmo_volume.yml index 8ad9ae074f4d6c3f00ad95ec5dfb11255045d01a..969626d97bf98334dd87cb9dc6862b77795b1643 100644 --- a/examples/SmallCosmoVolume_cooling/small_cosmo_volume.yml +++ b/examples/SmallCosmoVolume_cooling/small_cosmo_volume.yml @@ -66,10 +66,9 @@ LambdaCooling: EagleCooling: filename: ./coolingtables/ reionisation_redshift: 8.5 - he_reion: 1 - he_reion_z_center: 3.5 - he_reion_z_sigma: 0.5 - he_reion_ev_pH: 2.0 + He_reion_z_centre: 3.5 + He_reion_z_sigma: 0.5 + He_reion_ev_pH: 2.0 # Impose primoridal metallicity EAGLEChemistry: diff --git a/examples/main.c b/examples/main.c index 93074a637e7427ac7bec53c51d7e6e608b6cdff2..db7df3b4a129b5469758485c7a042af173e63123 100644 --- a/examples/main.c +++ b/examples/main.c @@ -52,7 +52,7 @@ /* Global profiler. */ struct profiler prof; -// Usage string. +/* Usage string. */ static const char *const swift_usage[] = { "swift [options] [[--] param-file]", "swift [options] param-file", @@ -61,7 +61,7 @@ static const char *const swift_usage[] = { NULL, }; -// Function to handle multiple -P arguments. +/* Function to handle multiple -P arguments. */ struct cmdparams { const char *param[PARSER_MAX_NO_OF_PARAMS]; int nparam; @@ -97,7 +97,6 @@ int main(int argc, char *argv[]) { struct stars_props stars_properties; struct part *parts = NULL; struct phys_const prog_const; - struct sourceterms sourceterms; struct space s; struct spart *sparts = NULL; struct unit_system us; @@ -147,11 +146,11 @@ int main(int argc, char *argv[]) { int restart = 0; int with_cosmology = 0; int with_external_gravity = 0; - int with_sourceterms = 0; int with_cooling = 0; int with_self_gravity = 0; int with_hydro = 0; int with_stars = 0; + int with_star_formation = 0; int with_feedback = 0; int with_fp_exceptions = 0; int with_drift_all = 0; @@ -186,7 +185,8 @@ int main(int argc, char *argv[]) { "particles. This emulates Gadget-[23] and GIZMO's default " "behaviours.", NULL, 0, 0), - OPT_BOOLEAN('F', "sourceterms", &with_sourceterms, "", NULL, 0, 0), + OPT_BOOLEAN('F', "star-formation", &with_star_formation, + "Run with star formation", NULL, 0, 0), OPT_BOOLEAN('g', "external-gravity", &with_external_gravity, "Run with an external gravitational potential.", NULL, 0, 0), OPT_BOOLEAN('G', "self-gravity", &with_self_gravity, @@ -449,10 +449,9 @@ int main(int argc, char *argv[]) { #ifdef WITH_MPI if (with_mpole_reconstruction && nr_nodes > 1) error("Cannot reconstruct m-poles every step over MPI (yet)."); -#endif - -#ifdef WITH_MPI if (with_feedback) error("Can't run with feedback over MPI (yet)."); + if (with_star_formation) + error("Can't run with star formation over MPI (yet)"); #endif #if defined(WITH_MPI) && defined(HAVE_VELOCIRAPTOR) @@ -779,7 +778,7 @@ int main(int argc, char *argv[]) { if (myrank == 0) clocks_gettime(&tic); space_init(&s, params, &cosmo, dim, parts, gparts, sparts, Ngas, Ngpart, Nspart, periodic, replicate, generate_gas_in_ics, with_hydro, - with_self_gravity, talking, dry_run); + with_self_gravity, with_star_formation, talking, dry_run); if (myrank == 0) { clocks_gettime(&toc); @@ -860,10 +859,6 @@ int main(int argc, char *argv[]) { chemistry_init(params, &us, &prog_const, &chemistry); if (myrank == 0) chemistry_print(&chemistry); - /* Initialise the feedback properties */ - if (with_sourceterms) sourceterms_init(params, &us, &sourceterms); - if (with_sourceterms && myrank == 0) sourceterms_print(&sourceterms); - /* Construct the engine policy */ int engine_policies = ENGINE_POLICY | engine_policy_steal; if (with_drift_all) engine_policies |= engine_policy_drift_all; @@ -875,21 +870,18 @@ int main(int argc, char *argv[]) { engine_policies |= engine_policy_external_gravity; if (with_cosmology) engine_policies |= engine_policy_cosmology; if (with_cooling) engine_policies |= engine_policy_cooling; - if (with_sourceterms) engine_policies |= engine_policy_sourceterms; if (with_stars) engine_policies |= engine_policy_stars; + if (with_star_formation) engine_policies |= engine_policy_star_formation; if (with_feedback) engine_policies |= engine_policy_feedback; if (with_structure_finding) engine_policies |= engine_policy_structure_finding; - // MATTHIEU: Temporary star formation law - // engine_policies |= engine_policy_star_formation; - /* 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], N_total[2], engine_policies, talking, &reparttype, &us, &prog_const, &cosmo, &hydro_properties, &gravity_properties, &stars_properties, - &mesh, &potential, &cooling_func, &chemistry, &sourceterms); + &mesh, &potential, &cooling_func, &chemistry); engine_config(0, &e, params, nr_nodes, myrank, nr_threads, with_aff, talking, restart_file); diff --git a/examples/parameter_example.yml b/examples/parameter_example.yml index 6adccf2963dbeff67755bdac946e7bfb10d4a897..6258782ab802ae85d783543bdeedf34f538333cf 100644 --- a/examples/parameter_example.yml +++ b/examples/parameter_example.yml @@ -63,6 +63,9 @@ Scheduler: cell_sub_size_self_stars: 32000 # (Optional) Maximal number of interactions per sub-self stars task (this is the default value). cell_split_size: 400 # (Optional) Maximal number of particles per cell (this is the default value). cell_subdepth_diff_grav: 4 # (Optional) Maximal depth difference between leaves and a cell that gravity tasks can be pushed down to (this is the default value). + cell_extra_parts: 0 # (Optional) Number of spare parts per top-level allocated at rebuild time for on-the-fly creation. + cell_extra_gparts: 0 # (Optional) Number of spare gparts per top-level allocated at rebuild time for on-the-fly creation. + cell_extra_sparts: 400 # (Optional) Number of spare sparts per top-level allocated at rebuild time for on-the-fly creation. max_top_level_cells: 12 # (Optional) Maximal number of top-level cells in any dimension. The number of top-level cells will be the cube of this (this is the default value). tasks_per_cell: 0 # (Optional) The average number of tasks per cell. If not large enough the simulation will fail (means guess...). mpi_message_limit: 4096 # (Optional) Maximum MPI task message size to send non-buffered, KB. @@ -245,6 +248,13 @@ LambdaCooling: lambda_nH2_cgs: 1e-22 # Cooling rate divided by square Hydrogen number density (in cgs units [erg * s^-1 * cm^3]) cooling_tstep_mult: 1.0 # (Optional) Dimensionless pre-factor for the time-step condition. +EagleCooling: + filename: ./coolingtables/ # Location of the Wiersma+08 cooling tables + reionisation_redshift: 11.5 # Redshift of Hydrogen re-ionization + He_reion_z_centre: 3.5 # Redshift of the centre of the Helium re-ionization Gaussian + He_reion_z_sigma: 0.5 # Spread in redshift of the Helium re-ionization Gaussian + He_reion_ev_pH: 2.0 # Energy inject by Helium re-ionization in electron-volt per Hydrogen atom + # Cooling with Grackle 3.0 GrackleCooling: CloudyTable: CloudyData_UVB=HM2012.h5 # Name of the Cloudy Table (available on the grackle bitbucket repository) diff --git a/src/Makefile.am b/src/Makefile.am index 78531f1f03205374231b78df4de4bc697fed3178..9bf6c9bc3a51880e12ed18f59ea68305b5d124da 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -16,7 +16,7 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. # Add the non-standard paths to the included library headers -AM_CFLAGS = $(HDF5_CPPFLAGS) $(GSL_INCS) $(FFTW_INCS) $(GRACKLE_INCS) +AM_CFLAGS = $(HDF5_CPPFLAGS) $(GSL_INCS) $(FFTW_INCS) $(NUMA_INCS) $(GRACKLE_INCS) # Assign a "safe" version number AM_LDFLAGS = $(HDF5_LDFLAGS) $(FFTW_LIBS) -version-info 0:0:0 @@ -25,7 +25,7 @@ AM_LDFLAGS = $(HDF5_LDFLAGS) $(FFTW_LIBS) -version-info 0:0:0 GIT_CMD = @GIT_CMD@ # Additional dependencies for shared libraries. -EXTRA_LIBS = $(HDF5_LIBS) $(FFTW_LIBS) $(PROFILER_LIBS) $(TCMALLOC_LIBS) $(JEMALLOC_LIBS) $(TBBMALLOC_LIBS) $(GRACKLE_LIBS) $(GSL_LIBS) +EXTRA_LIBS = $(HDF5_LIBS) $(FFTW_LIBS) $(NUMA_LIBS) $(PROFILER_LIBS) $(TCMALLOC_LIBS) $(JEMALLOC_LIBS) $(TBBMALLOC_LIBS) $(GRACKLE_LIBS) $(GSL_LIBS) # MPI libraries. MPI_LIBS = $(PARMETIS_LIBS) $(METIS_LIBS) $(MPI_THREAD_LIBS) @@ -44,11 +44,11 @@ include_HEADERS = space.h runner.h queue.h task.h lock.h cell.h part.h const.h \ common_io.h single_io.h multipole.h map.h tools.h partition.h clocks.h parser.h \ physical_constants.h physical_constants_cgs.h potential.h version.h \ hydro_properties.h riemann.h threadpool.h cooling_io.h cooling.h cooling_struct.h \ - sourceterms.h sourceterms_struct.h statistics.h memswap.h cache.h runner_doiact_vec.h profiler.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 cosmology.h restart.h space_getsid.h utilities.h \ - mesh_gravity.h cbrt.h velociraptor_interface.h swift_velociraptor_part.h outputlist.h \ + mesh_gravity.h cbrt.h exp10.h velociraptor_interface.h swift_velociraptor_part.h outputlist.h \ logger_io.h # source files for EAGLE cooling @@ -63,7 +63,7 @@ AM_SOURCES = space.c runner.c queue.c task.c cell.c engine.c engine_maketasks.c proxy.c parallel_io.c units.c common_io.c single_io.c multipole.c version.c map.c \ kernel_hydro.c tools.c part.c partition.c clocks.c parser.c \ physical_constants.c potential.c hydro_properties.c \ - threadpool.c cooling.c sourceterms.c \ + threadpool.c cooling.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 \ @@ -81,7 +81,6 @@ nobase_noinst_HEADERS = align.h approx_math.h atomic.h barrier.h cycle.h error.h gravity/Default/gravity_debug.h gravity/Default/gravity_part.h \ gravity/Potential/gravity.h gravity/Potential/gravity_iact.h gravity/Potential/gravity_io.h \ gravity/Potential/gravity_debug.h gravity/Potential/gravity_part.h \ - sourceterms.h \ equation_of_state.h \ equation_of_state/ideal_gas/equation_of_state.h equation_of_state/isothermal/equation_of_state.h \ hydro.h hydro_io.h \ diff --git a/src/cell.c b/src/cell.c index 3fe5e21e7c888f2358395a27e13710db460fd74c..ed54163a008f7fad8294f50458ef8d2004be832d 100644 --- a/src/cell.c +++ b/src/cell.c @@ -972,6 +972,7 @@ void cell_split(struct cell *c, ptrdiff_t parts_offset, ptrdiff_t sparts_offset, /* Store the counts and offsets. */ for (int k = 0; k < 8; k++) { c->progeny[k]->hydro.count = bucket_count[k]; + c->progeny[k]->hydro.count_total = c->progeny[k]->hydro.count; c->progeny[k]->hydro.parts = &c->hydro.parts[bucket_offset[k]]; c->progeny[k]->hydro.xparts = &c->hydro.xparts[bucket_offset[k]]; } @@ -1089,6 +1090,7 @@ void cell_split(struct cell *c, ptrdiff_t parts_offset, ptrdiff_t sparts_offset, /* Store the counts and offsets. */ for (int k = 0; k < 8; k++) { c->progeny[k]->stars.count = bucket_count[k]; + c->progeny[k]->stars.count_total = c->progeny[k]->stars.count; c->progeny[k]->stars.parts = &c->stars.parts[bucket_offset[k]]; } @@ -1151,6 +1153,7 @@ void cell_split(struct cell *c, ptrdiff_t parts_offset, ptrdiff_t sparts_offset, /* Store the counts and offsets. */ for (int k = 0; k < 8; k++) { c->progeny[k]->grav.count = bucket_count[k]; + c->progeny[k]->grav.count_total = c->progeny[k]->grav.count; c->progeny[k]->grav.parts = &c->grav.parts[bucket_offset[k]]; } } @@ -3813,6 +3816,190 @@ void cell_check_timesteps(struct cell *c) { #endif } +void cell_check_spart_pos(const struct cell *c, + const struct spart *global_sparts) { + +#ifdef SWIFT_DEBUG_CHECKS + + /* Recurse */ + if (c->split) { + for (int k = 0; k < 8; ++k) + if (c->progeny[k] != NULL) + cell_check_spart_pos(c->progeny[k], global_sparts); + } + + struct spart *sparts = c->stars.parts; + const int count = c->stars.count; + for (int i = 0; i < count; ++i) { + + const struct spart *sp = &sparts[i]; + if ((sp->x[0] < c->loc[0] / space_stretch) || + (sp->x[1] < c->loc[1] / space_stretch) || + (sp->x[2] < c->loc[2] / space_stretch) || + (sp->x[0] >= (c->loc[0] + c->width[0]) * space_stretch) || + (sp->x[1] >= (c->loc[1] + c->width[1]) * space_stretch) || + (sp->x[2] >= (c->loc[2] + c->width[2]) * space_stretch)) + error("spart not in its cell!"); + + if (sp->time_bin != time_bin_not_created && + sp->time_bin != time_bin_inhibited) { + + const struct gpart *gp = sp->gpart; + if (gp == NULL && sp->time_bin != time_bin_not_created) + error("Unlinked spart!"); + + if (&global_sparts[-gp->id_or_neg_offset] != sp) + error("Incorrectly linked spart!"); + } + } + +#else + error("Calling a degugging function outside debugging mode."); +#endif +} + +/** + * @brief Recursively update the pointer and counter for #spart after the + * addition of a new particle. + * + * @param c The cell we are working on. + * @param progeny_list The list of the progeny index at each level for the + * leaf-cell where the particle was added. + * @param main_branch Are we in a cell directly above the leaf where the new + * particle was added? + */ +void cell_recursively_shift_sparts(struct cell *c, + const int progeny_list[space_cell_maxdepth], + const int main_branch) { + if (c->split) { + + /* No need to recurse in progenies located before the insestion point */ + const int first_progeny = main_branch ? progeny_list[(int)c->depth] : 0; + + for (int k = first_progeny; k < 8; ++k) { + + if (c->progeny[k] != NULL) + cell_recursively_shift_sparts(c->progeny[k], progeny_list, + main_branch && (k == first_progeny)); + } + } + + /* When directly above the leaf with the new particle: increase the particle + * count */ + /* When after the leaf with the new particle: shift by one position */ + if (main_branch) + c->stars.count++; + else + c->stars.parts++; +} + +/** + * @brief "Add" a #spart in a given #cell. + * + * This function will a a #spart at the start of the current cell's array by + * shifting all the #spart in the top-level cell by one position. All the + * pointers and cell counts are updated accordingly. + * + * @param e The #engine. + * @param c The leaf-cell in which to add the #spart. + * + * @return A pointer to the newly added #spart. The spart has a been zeroed and + * given a position within the cell as well as set to the minimal active time + * bin. + */ +struct spart *cell_add_spart(struct engine *e, struct cell *const c) { + + /* Perform some basic consitency checks */ + if (c->nodeID != engine_rank) error("Adding spart on a foreign node"); + if (c->grav.ti_old_part != e->ti_current) error("Undrifted cell!"); + if (c->split) error("Addition of spart performed above the leaf level"); + + /* Progeny number at each level */ + int progeny[space_cell_maxdepth]; +#ifdef SWIFT_DEBUG_CHECKS + for (int i = 0; i < space_cell_maxdepth; ++i) progeny[i] = -1; +#endif + + /* Get the top-level this leaf cell is in and compute the progeny indices at + each level */ + struct cell *top = c; + while (top->parent != NULL) { + for (int k = 0; k < 8; ++k) { + if (top->parent->progeny[k] == top) { + progeny[(int)top->parent->depth] = k; + } + } + top = top->parent; + } + + /* Are there any extra particles left? */ + if (top->stars.count == top->stars.count_total - 1) { + message("We ran out of star particles!"); + atomic_inc(&e->forcerebuild); + return NULL; + } + + /* Number of particles to shift in order to get a free space. */ + const size_t n_copy = &top->stars.parts[top->stars.count] - c->stars.parts; + +#ifdef SWIFT_DEBUG_CHECKS + if (c->stars.parts + n_copy > top->stars.parts + top->stars.count) + error("Copying beyond the allowed range"); +#endif + + if (n_copy > 0) { + + // MATTHIEU: This can be improved. We don't need to copy everything, just + // need to swap a few particles. + memmove(&c->stars.parts[1], &c->stars.parts[0], + n_copy * sizeof(struct spart)); + + /* Update the gpart->spart links (shift by 1) */ + for (size_t i = 0; i < n_copy; ++i) { +#ifdef SWIFT_DEBUG_CHECKS + if (c->stars.parts[i + 1].gpart == NULL) { + error("Incorrectly linked spart!"); + } +#endif + c->stars.parts[i + 1].gpart->id_or_neg_offset--; + } + } + + /* Recursively shift all the stars to get a free spot at the start of the + * current cell*/ + cell_recursively_shift_sparts(top, progeny, /* main_branch=*/1); + + /* We now have an empty spart as the first particle in that cell */ + struct spart *sp = &c->stars.parts[0]; + bzero(sp, sizeof(struct spart)); + + /* Give it a decent position */ + sp->x[0] = c->loc[0] + 0.5 * c->width[0]; + sp->x[1] = c->loc[1] + 0.5 * c->width[1]; + sp->x[2] = c->loc[2] + 0.5 * c->width[2]; + + /* Set it to the current time-bin */ + sp->time_bin = e->min_active_bin; + + top = c; + while (top->parent != NULL) { + top->grav.ti_end_min = e->ti_current; + top = top->parent; + } + top->grav.ti_end_min = e->ti_current; + +#ifdef SWIFT_DEBUG_CHECKS + /* Specify it was drifted to this point */ + sp->ti_drift = e->ti_current; +#endif + + /* Register that we used one of the free slots. */ + const size_t one = 1; + atomic_sub(&e->s->nr_extra_sparts, one); + + return sp; +} + /** * @brief "Remove" a gas particle from the calculation. * @@ -3899,15 +4086,21 @@ void cell_remove_spart(const struct engine *e, struct cell *c, * @brief "Remove" a gas particle from the calculation and convert its gpart * friend to a dark matter particle. * + * Note that the #part is not destroyed. The pointer is still valid + * after this call and the properties of the #part are not altered + * apart from the time-bin and #gpart pointer. * The particle is inhibited and will officially be removed at the next rebuild. * * @param e The #engine running on this node. * @param c The #cell from which to remove the particle. * @param p The #part to remove. * @param xp The extended data of the particle to remove. + * + * @return Pointer to the #gpart the #part has become. It carries the + * ID of the #part and has a dark matter type. */ -void cell_convert_part_to_gpart(const struct engine *e, struct cell *c, - struct part *p, struct xpart *xp) { +struct gpart *cell_convert_part_to_gpart(const struct engine *e, struct cell *c, + struct part *p, struct xpart *xp) { /* Quick cross-checks */ if (c->nodeID != e->nodeID) @@ -3932,20 +4125,28 @@ void cell_convert_part_to_gpart(const struct engine *e, struct cell *c, #ifdef SWIFT_DEBUG_CHECKS gp->ti_kick = p->ti_kick; #endif + + return gp; } /** * @brief "Remove" a spart particle from the calculation and convert its gpart * friend to a dark matter particle. * + * Note that the #spart is not destroyed. The pointer is still valid + * after this call and the properties of the #spart are not altered + * apart from the time-bin and #gpart pointer. * The particle is inhibited and will officially be removed at the next rebuild. * * @param e The #engine running on this node. * @param c The #cell from which to remove the particle. * @param sp The #spart to remove. + * + * @return Pointer to the #gpart the #spart has become. It carries the + * ID of the #spart and has a dark matter type. */ -void cell_convert_spart_to_gpart(const struct engine *e, struct cell *c, - struct spart *sp) { +struct gpart *cell_convert_spart_to_gpart(const struct engine *e, + struct cell *c, struct spart *sp) { /* Quick cross-check */ if (c->nodeID != e->nodeID) @@ -3970,6 +4171,210 @@ void cell_convert_spart_to_gpart(const struct engine *e, struct cell *c, #ifdef SWIFT_DEBUG_CHECKS gp->ti_kick = sp->ti_kick; #endif + + return gp; +} + +/** + * @brief "Remove" a #part from a #cell and replace it with a #spart + * connected to the same #gpart. + * + * Note that the #part is not destroyed. The pointer is still valid + * after this call and the properties of the #part are not altered + * apart from the time-bin and #gpart pointer. + * The particle is inhibited and will officially be removed at the next rebuild. + * + * @param e The #engine. + * @param c The #cell from which to remove the #part. + * @param p The #part to remove (must be inside c). + * @param xp The extended data of the #part. + * + * @return A fresh #spart with the same ID, position, velocity and + * time-bin as the original #part. + */ +struct spart *cell_convert_part_to_spart(struct engine *e, struct cell *c, + struct part *p, struct xpart *xp) { + + /* Quick cross-check */ + if (c->nodeID != e->nodeID) + error("Can't remove a particle in a foreign cell."); + + if (p->gpart == NULL) + error("Trying to convert part without gpart friend to star!"); + + /* Create a fresh (empty) spart */ + struct spart *sp = cell_add_spart(e, c); + + /* Did we run out of free spart slots? */ + if (sp == NULL) return NULL; + + /* Destroy the gas particle and get it's gpart friend */ + struct gpart *gp = cell_convert_part_to_gpart(e, c, p, xp); + + /* Assign the ID back */ + sp->id = gp->id_or_neg_offset; + gp->type = swift_type_stars; + + /* Re-link things */ + sp->gpart = gp; + gp->id_or_neg_offset = -(sp - e->s->sparts); + + /* Synchronize clocks */ + gp->time_bin = sp->time_bin; + + /* Synchronize masses, positions and velocities */ + sp->mass = gp->mass; + sp->x[0] = gp->x[0]; + sp->x[1] = gp->x[1]; + sp->x[2] = gp->x[2]; + sp->v[0] = gp->v_full[0]; + sp->v[1] = gp->v_full[1]; + sp->v[2] = gp->v_full[2]; + +#ifdef SWIFT_DEBUG_CHECKS + sp->ti_kick = gp->ti_kick; + gp->ti_drift = sp->ti_drift; +#endif + + /* Set a smoothing length */ + sp->h = max(c->stars.h_max, c->hydro.h_max); + + /* Here comes the Sun! */ + return sp; +} + +/** + * @brief Re-arrange the #part in a top-level cell such that all the extra ones + * for on-the-fly creation are located at the end of the array. + * + * @param c The #cell to sort. + * @param parts_offset The offset between the first #part in the array and the + * first #part in the global array in the space structure (for re-linking). + */ +void cell_reorder_extra_parts(struct cell *c, const ptrdiff_t parts_offset) { + + struct part *parts = c->hydro.parts; + struct xpart *xparts = c->hydro.xparts; + const int count_real = c->hydro.count; + + if (c->depth != 0 || c->nodeID != engine_rank) + error("This function should only be called on local top-level cells!"); + + int first_not_extra = count_real; + + /* Find extra particles */ + for (int i = 0; i < count_real; ++i) { + if (parts[i].time_bin == time_bin_not_created) { + + /* Find the first non-extra particle after the end of the + real particles */ + while (parts[first_not_extra].time_bin == time_bin_not_created) { + ++first_not_extra; + } + +#ifdef SWIFT_DEBUG_CHECKS + if (first_not_extra >= count_real + space_extra_parts) + error("Looking for extra particles beyond this cell's range!"); +#endif + + /* Swap everything, including g-part pointer */ + memswap(&parts[i], &parts[first_not_extra], sizeof(struct part)); + memswap(&xparts[i], &xparts[first_not_extra], sizeof(struct xpart)); + if (parts[i].gpart) + parts[i].gpart->id_or_neg_offset = -(i + parts_offset); + } + } +} + +/** + * @brief Re-arrange the #spart in a top-level cell such that all the extra ones + * for on-the-fly creation are located at the end of the array. + * + * @param c The #cell to sort. + * @param sparts_offset The offset between the first #spart in the array and the + * first #spart in the global array in the space structure (for re-linking). + */ +void cell_reorder_extra_sparts(struct cell *c, const ptrdiff_t sparts_offset) { + + struct spart *sparts = c->stars.parts; + const int count_real = c->stars.count; + + if (c->depth != 0 || c->nodeID != engine_rank) + error("This function should only be called on local top-level cells!"); + + int first_not_extra = count_real; + + /* Find extra particles */ + for (int i = 0; i < count_real; ++i) { + if (sparts[i].time_bin == time_bin_not_created) { + + /* Find the first non-extra particle after the end of the + real particles */ + while (sparts[first_not_extra].time_bin == time_bin_not_created) { + ++first_not_extra; + } + +#ifdef SWIFT_DEBUG_CHECKS + if (first_not_extra >= count_real + space_extra_sparts) + error("Looking for extra particles beyond this cell's range!"); +#endif + + /* Swap everything, including g-part pointer */ + memswap(&sparts[i], &sparts[first_not_extra], sizeof(struct spart)); + if (sparts[i].gpart) + sparts[i].gpart->id_or_neg_offset = -(i + sparts_offset); + sparts[first_not_extra].gpart = NULL; +#ifdef SWIFT_DEBUG_CHECKS + if (sparts[first_not_extra].time_bin != time_bin_not_created) + error("Incorrect swap occured!"); +#endif + } + } +} + +/** + * @brief Re-arrange the #gpart in a top-level cell such that all the extra ones + * for on-the-fly creation are located at the end of the array. + * + * @param c The #cell to sort. + * @param parts The global array of #part (for re-linking). + * @param sparts The global array of #spart (for re-linking). + */ +void cell_reorder_extra_gparts(struct cell *c, struct part *parts, + struct spart *sparts) { + + struct gpart *gparts = c->grav.parts; + const int count_real = c->grav.count; + + if (c->depth != 0 || c->nodeID != engine_rank) + error("This function should only be called on local top-level cells!"); + + int first_not_extra = count_real; + + /* Find extra particles */ + for (int i = 0; i < count_real; ++i) { + if (gparts[i].time_bin == time_bin_not_created) { + + /* Find the first non-extra particle after the end of the + real particles */ + while (gparts[first_not_extra].time_bin == time_bin_not_created) { + ++first_not_extra; + } + +#ifdef SWIFT_DEBUG_CHECKS + if (first_not_extra >= count_real + space_extra_gparts) + error("Looking for extra particles beyond this cell's range!"); +#endif + + /* Swap everything (including pointers) */ + memswap(&gparts[i], &gparts[first_not_extra], sizeof(struct gpart)); + if (gparts[i].type == swift_type_gas) { + parts[-gparts[i].id_or_neg_offset].gpart = &gparts[i]; + } else if (gparts[i].type == swift_type_stars) { + sparts[-gparts[i].id_or_neg_offset].gpart = &gparts[i]; + } + } + } } /** diff --git a/src/cell.h b/src/cell.h index 97ca22e584c67de20ca0826425f60523b8158ffa..7178698c425c3791223789930c82761d13fc0116 100644 --- a/src/cell.h +++ b/src/cell.h @@ -220,12 +220,12 @@ struct cell { /*! The cell dimensions. */ double width[3]; - /*! Linking pointer for "memory management". */ - struct cell *next; - /*! Pointers to the next level of cells. */ struct cell *progeny[8]; + /*! Linking pointer for "memory management". */ + struct cell *next; + /*! Parent cell. */ struct cell *parent; @@ -248,18 +248,45 @@ struct cell { * pair/self tasks */ struct cell *super; - /*! Last (integer) time the cell's part were drifted forward in time. */ - integertime_t ti_old_part; + /*! The task computing this cell's sorts. */ + struct task *sorts; - /*! Maximum part movement in this cell since last construction. */ - float dx_max_part; + /*! The drift task for parts */ + struct task *drift; - /*! Maximum particle movement in this cell since the last sort. */ - float dx_max_sort; + /*! Linked list of the tasks computing this cell's hydro density. */ + struct link *density; + + /* Linked list of the tasks computing this cell's hydro gradients. */ + struct link *gradient; + + /*! Linked list of the tasks computing this cell's hydro forces. */ + struct link *force; + + /*! Dependency implicit task for the ghost (in->ghost->out)*/ + struct task *ghost_in; + + /*! Dependency implicit task for the ghost (in->ghost->out)*/ + struct task *ghost_out; + + /*! The ghost task itself */ + struct task *ghost; + + /*! The extra ghost task for complex hydro schemes */ + struct task *extra_ghost; + + /*! Task for cooling */ + struct task *cooling; + + /*! Task for star formation */ + struct task *star_formation; /*! Max smoothing length in this cell. */ double h_max; + /*! Last (integer) time the cell's part were drifted forward in time. */ + integertime_t ti_old_part; + /*! Minimum end of (integer) time step in this cell for hydro tasks. */ integertime_t ti_end_min; @@ -270,20 +297,14 @@ struct cell { */ integertime_t ti_beg_max; - /*! Nr of #part in this cell. */ - int count; - /*! Spin lock for various uses (#part case). */ swift_lock_type lock; - /*! Number of #part updated in this cell. */ - int updated; - - /*! Number of #part inhibited in this cell. */ - int inhibited; + /*! Maximum part movement in this cell since last construction. */ + float dx_max_part; - /*! Is the #part data of this cell being used in a sub-cell? */ - int hold; + /*! Maximum particle movement in this cell since the last sort. */ + float dx_max_sort; /*! Values of h_max before the drifts, used for sub-cell tasks. */ float h_max_old; @@ -294,12 +315,30 @@ struct cell { /*! Values of dx_max_sort before the drifts, used for sub-cell tasks. */ float dx_max_sort_old; + /*! Nr of #part in this cell. */ + int count; + + /*! Nr of #part this cell can hold after addition of new #part. */ + int count_total; + + /*! Number of #part updated in this cell. */ + int updated; + + /*! Number of #part inhibited in this cell. */ + int inhibited; + + /*! Is the #part data of this cell being used in a sub-cell? */ + int hold; + /*! Bit mask of sort directions that will be needed in the next timestep. */ unsigned int requires_sorts; /*! Bit mask of sorts that need to be computed for this cell. */ unsigned int do_sort; + /*! Bit-mask indicating the sorted directions */ + unsigned int sorted; + /*! Does this cell need to be drifted (hydro)? */ char do_drift; @@ -309,42 +348,6 @@ struct cell { /*! Do any of this cell's sub-cells need to be sorted? */ char do_sub_sort; - /*! Bit-mask indicating the sorted directions */ - unsigned int sorted; - - /*! The task computing this cell's sorts. */ - struct task *sorts; - - /*! The drift task for parts */ - struct task *drift; - - /*! Linked list of the tasks computing this cell's hydro density. */ - struct link *density; - - /* Linked list of the tasks computing this cell's hydro gradients. */ - struct link *gradient; - - /*! Linked list of the tasks computing this cell's hydro forces. */ - struct link *force; - - /*! Dependency implicit task for the ghost (in->ghost->out)*/ - struct task *ghost_in; - - /*! Dependency implicit task for the ghost (in->ghost->out)*/ - struct task *ghost_out; - - /*! The ghost task itself */ - struct task *ghost; - - /*! The extra ghost task for complex hydro schemes */ - struct task *extra_ghost; - - /*! Task for cooling */ - struct task *cooling; - - /*! Task for star formation */ - struct task *star_formation; - #ifdef SWIFT_DEBUG_CHECKS /*! Last (integer) time the cell's sort arrays were updated. */ @@ -367,6 +370,36 @@ struct cell { * tasks */ struct cell *super; + /*! The drift task for gparts */ + struct task *drift; + + /*! Implicit task (going up- and down the tree) for the #gpart drifts */ + struct task *drift_out; + + /*! Linked list of the tasks computing this cell's gravity forces. */ + struct link *grav; + + /*! Linked list of the tasks computing this cell's gravity M-M forces. */ + struct link *mm; + + /*! The multipole initialistation task */ + struct task *init; + + /*! Implicit task for the gravity initialisation */ + struct task *init_out; + + /*! Task computing long range non-periodic gravity interactions */ + struct task *long_range; + + /*! Implicit task for the down propagation */ + struct task *down_in; + + /*! Task propagating the mesh forces to the particles */ + struct task *mesh; + + /*! Task propagating the multipole to the particles */ + struct task *down; + /*! Minimum end of (integer) time step in this cell for gravity tasks. */ integertime_t ti_end_min; @@ -383,15 +416,18 @@ struct cell { /*! Last (integer) time the cell's multipole was drifted forward in time. */ integertime_t ti_old_multipole; - /*! Nr of #gpart in this cell. */ - int count; - /*! Spin lock for various uses (#gpart case). */ swift_lock_type plock; /*! Spin lock for various uses (#multipole case). */ swift_lock_type mlock; + /*! Nr of #gpart in this cell. */ + int count; + + /*! Nr of #gpart this cell can hold after addition of new #gpart. */ + int count_total; + /*! Number of #gpart updated in this cell. */ int updated; @@ -404,58 +440,49 @@ struct cell { /*! Is the #multipole data of this cell being used in a sub-cell? */ int mhold; + /*! Number of M-M tasks that are associated with this cell. */ + short int nr_mm_tasks; + /*! Does this cell need to be drifted (gravity)? */ char do_drift; /*! Do any of this cell's sub-cells need to be drifted (gravity)? */ char do_sub_drift; - /*! The drift task for gparts */ - struct task *drift; - - /*! Implicit task (going up- and down the tree) for the #gpart drifts */ - struct task *drift_out; - - /*! Linked list of the tasks computing this cell's gravity forces. */ - struct link *grav; - - /*! Linked list of the tasks computing this cell's gravity M-M forces. */ - struct link *mm; - - /*! The multipole initialistation task */ - struct task *init; + } grav; - /*! Implicit task for the gravity initialisation */ - struct task *init_out; + /*! Stars variables */ + struct { - /*! Task computing long range non-periodic gravity interactions */ - struct task *long_range; + /*! Pointer to the #spart data. */ + struct spart *parts; - /*! Implicit task for the down propagation */ - struct task *down_in; + /*! Dependency implicit task for the star ghost (in->ghost->out)*/ + struct task *ghost_in; - /*! Task propagating the mesh forces to the particles */ - struct task *mesh; + /*! Dependency implicit task for the star ghost (in->ghost->out)*/ + struct task *ghost_out; - /*! Task propagating the multipole to the particles */ - struct task *down; + /*! The star ghost task itself */ + struct task *ghost; - /*! Number of M-M tasks that are associated with this cell. */ - short int nr_mm_tasks; + /*! Linked list of the tasks computing this cell's star density. */ + struct link *density; - } grav; + /*! The task computing this cell's sorts. */ + struct task *sorts; - /*! Stars variables */ - struct { + /*! Max smoothing length in this cell. */ + double h_max; - /*! Pointer to the #spart data. */ - struct spart *parts; + /*! Spin lock for various uses (#spart case). */ + swift_lock_type lock; /*! Nr of #spart in this cell. */ int count; - /*! Max smoothing length in this cell. */ - double h_max; + /*! Nr of #spart this cell can hold after addition of new #spart. */ + int count_total; /*! Values of h_max before the drifts, used for sub-cell tasks. */ float h_max_old; @@ -490,21 +517,6 @@ struct cell { /*! Maximum end of (integer) time step in this cell for gravity tasks. */ integertime_t ti_end_min; - /*! Dependency implicit task for the star ghost (in->ghost->out)*/ - struct task *ghost_in; - - /*! Dependency implicit task for the star ghost (in->ghost->out)*/ - struct task *ghost_out; - - /*! The star ghost task itself */ - struct task *ghost; - - /*! The task computing this cell's sorts. */ - struct task *sorts; - - /*! Linked list of the tasks computing this cell's star density. */ - struct link *density; - /*! Number of #spart updated in this cell. */ int updated; @@ -514,9 +526,6 @@ struct cell { /*! Is the #spart data of this cell being used in a sub-cell? */ int hold; - /*! Spin lock for various uses (#spart case). */ - swift_lock_type lock; - #ifdef SWIFT_DEBUG_CHECKS /*! Last (integer) time the cell's sort arrays were updated. */ integertime_t ti_sort; @@ -695,6 +704,8 @@ void cell_activate_hydro_sorts(struct cell *c, int sid, struct scheduler *s); void cell_activate_stars_sorts(struct cell *c, int sid, struct scheduler *s); void cell_clear_drift_flags(struct cell *c, void *data); void cell_set_super_mapper(void *map_data, int num_elements, void *extra_data); +void cell_check_spart_pos(const struct cell *c, + const struct spart *global_sparts); int cell_has_tasks(struct cell *c); void cell_remove_part(const struct engine *e, struct cell *c, struct part *p, struct xpart *xp); @@ -702,10 +713,17 @@ void cell_remove_gpart(const struct engine *e, struct cell *c, struct gpart *gp); void cell_remove_spart(const struct engine *e, struct cell *c, struct spart *sp); -void cell_convert_part_to_gpart(const struct engine *e, struct cell *c, - struct part *p, struct xpart *xp); -void cell_convert_spart_to_gpart(const struct engine *e, struct cell *c, - struct spart *sp); +struct spart *cell_add_spart(struct engine *e, struct cell *c); +struct gpart *cell_convert_part_to_gpart(const struct engine *e, struct cell *c, + struct part *p, struct xpart *xp); +struct gpart *cell_convert_spart_to_gpart(const struct engine *e, + struct cell *c, struct spart *sp); +struct spart *cell_convert_part_to_spart(struct engine *e, struct cell *c, + struct part *p, struct xpart *xp); +void cell_reorder_extra_parts(struct cell *c, const ptrdiff_t parts_offset); +void cell_reorder_extra_gparts(struct cell *c, struct part *parts, + struct spart *sparts); +void cell_reorder_extra_sparts(struct cell *c, const ptrdiff_t sparts_offset); int cell_can_use_pair_mm(const struct cell *ci, const struct cell *cj, const struct engine *e, const struct space *s); int cell_can_use_pair_mm_rebuild(const struct cell *ci, const struct cell *cj, diff --git a/src/common_io.c b/src/common_io.c index 087697b489269d97a268966d341093dd666dd9c9..24e74014fd52936023b5c7a41378faf3268bfdb3 100644 --- a/src/common_io.c +++ b/src/common_io.c @@ -875,7 +875,8 @@ void io_collect_parts_to_write(const struct part* restrict parts, for (size_t i = 0; i < Nparts; ++i) { /* And collect the ones that have not been removed */ - if (parts[i].time_bin != time_bin_inhibited) { + if (parts[i].time_bin != time_bin_inhibited && + parts[i].time_bin != time_bin_not_created) { parts_written[count] = parts[i]; xparts_written[count] = xparts[i]; @@ -909,7 +910,8 @@ void io_collect_sparts_to_write(const struct spart* restrict sparts, for (size_t i = 0; i < Nsparts; ++i) { /* And collect the ones that have not been removed */ - if (sparts[i].time_bin != time_bin_inhibited) { + if (sparts[i].time_bin != time_bin_inhibited && + sparts[i].time_bin != time_bin_not_created) { sparts_written[count] = sparts[i]; count++; @@ -943,6 +945,7 @@ void io_collect_gparts_to_write(const struct gpart* restrict gparts, /* And collect the ones that have not been removed */ if ((gparts[i].time_bin != time_bin_inhibited) && + (gparts[i].time_bin != time_bin_not_created) && (gparts[i].type == swift_type_dark_matter)) { gparts_written[count] = gparts[i]; diff --git a/src/cooling/Compton/cooling.h b/src/cooling/Compton/cooling.h index f440cd03455c07d2eeb64c37189aed36efe78e09..77252140d21ca910c0b98c68fbb0e89eea37f6ee 100644 --- a/src/cooling/Compton/cooling.h +++ b/src/cooling/Compton/cooling.h @@ -49,61 +49,11 @@ INLINE static void cooling_update(const struct cosmology* cosmo, // Add content if required. } -/** - * @brief Compute the mean molecular weight as a function of temperature for - * primordial gas. - * - * @param T The temperature of the gas [K]. - * @param H_mass_fraction The hydrogen mass fraction of the gas. - * @param T_transition The temperature of the transition from HII to HI [K]. - */ -__attribute__((always_inline, const)) INLINE static double -mean_molecular_weight(const double T, const double H_mass_fraction, - const double T_transition) { - - if (T > T_transition) - return 4. / (8. - 5. * (1. - H_mass_fraction)); - else - return 4. / (1. + 3. * H_mass_fraction); -} - -/** - * @brief Compute the temperature for a given internal energy per unit mass - * assuming primordial gas. - * - * @param u_cgs The internal energy per unit mass of the gas [erg * g^-1]. - * @param H_mass_fraction The hydrogen mass fraction of the gas. - * @param T_transition The temperature of the transition from HII to HI [K]. - * @param m_H_cgs The mass of the Hydorgen atom [g]. - * @param k_B_cgs The Boltzmann constant in cgs units [erg * K^-1] - * @return The temperature of the gas [K] - */ -__attribute__((always_inline, const)) INLINE static double -temperature_from_internal_energy(const double u_cgs, - const double H_mass_fraction, - const double T_transition, - const double m_H_cgs, const double k_B_cgs) { - - const double T_over_mu = hydro_gamma_minus_one * u_cgs * m_H_cgs / k_B_cgs; - - const double mu_high = - mean_molecular_weight(T_transition + 1., H_mass_fraction, T_transition); - const double mu_low = - mean_molecular_weight(T_transition - 1., H_mass_fraction, T_transition); - - if (T_over_mu > (T_transition + 1.) / mu_high) - return T_over_mu * mu_high; - else if (T_over_mu < (T_transition - 1.) / mu_low) - return T_over_mu * mu_low; - else - return T_transition; -} - /** * @brief Calculates du/dt in CGS units for a particle. * - * * @param cosmo The current cosmological model. + * @param phys_const The physical constants in internal units. * @param hydro_props The properties of the hydro scheme. * @param cooling The #cooling_function_data used in the run. * @param z The current redshift. @@ -113,7 +63,8 @@ temperature_from_internal_energy(const double u_cgs, * in cgs units [erg * g^-1 * s^-1]. */ __attribute__((always_inline)) INLINE static double Compton_cooling_rate_cgs( - const struct cosmology* cosmo, const struct hydro_props* hydro_props, + const struct cosmology* cosmo, const struct phys_const* restrict phys_const, + const struct hydro_props* hydro_props, const struct cooling_function_data* cooling, const double z, const double u, const struct part* p) { @@ -129,15 +80,27 @@ __attribute__((always_inline)) INLINE static double Compton_cooling_rate_cgs( /* CMB temperature at this redshift */ const double T_CMB = cooling->const_T_CMB_0 * zp1; + /* Physical constants */ + const double m_H = phys_const->const_proton_mass; + const double k_B = phys_const->const_boltzmann_k; + /* Gas properties */ - const double H_mass_fraction = hydro_props->hydrogen_mass_fraction; const double T_transition = hydro_props->hydrogen_ionization_temperature; + const double mu_neutral = hydro_props->mu_neutral; + const double mu_ionised = hydro_props->mu_ionised; - /* Particle temperature */ - const double u_cgs = u * cooling->conv_factor_energy_to_cgs; - const double T = temperature_from_internal_energy(u_cgs, H_mass_fraction, - T_transition, 1., 1.); - // MATTHIEU: to do: get H mass in cgs and k_B in cgs. + /* Temperature over mean molecular weight */ + const double T_over_mu = hydro_gamma_minus_one * u * m_H / k_B; + + double T; + + /* Are we above or below the HII -> HI transition? */ + if (T_over_mu > (T_transition + 1.) / mu_ionised) + T = T_over_mu * mu_ionised; + else if (T_over_mu < (T_transition - 1.) / mu_neutral) + T = T_over_mu * mu_neutral; + else + T = T_transition; /* Electron abundance */ double electron_abundance = 0.; // MATTHIEU: To do: compute X_e @@ -189,8 +152,8 @@ __attribute__((always_inline)) INLINE static void cooling_cool_part( const float hydro_du_dt = hydro_get_physical_internal_energy_dt(p, cosmo); /* Calculate cooling du_dt (in cgs units) */ - const double cooling_du_dt_cgs = - Compton_cooling_rate_cgs(cosmo, hydro_props, cooling, cosmo->z, u_old, p); + const double cooling_du_dt_cgs = Compton_cooling_rate_cgs( + cosmo, phys_const, hydro_props, cooling, cosmo->z, u_old, p); /* Convert to internal units */ float cooling_du_dt = @@ -273,6 +236,49 @@ __attribute__((always_inline)) INLINE static void cooling_first_init_part( xp->cooling_data.radiated_energy = 0.f; } +/** + * @brief Compute the temperature of a #part based on the cooling function. + * + * @param phys_const #phys_const data structure. + * @param hydro_props The properties of the hydro scheme. + * @param us The internal system of units. + * @param cosmo #cosmology data structure. + * @param cooling #cooling_function_data struct. + * @param p #part data. + * @param xp Pointer to the #xpart data. + */ +INLINE static float cooling_get_temperature( + const struct phys_const* restrict phys_const, + const struct hydro_props* restrict hydro_props, + const struct unit_system* restrict us, + const struct cosmology* restrict cosmo, + const struct cooling_function_data* restrict cooling, + const struct part* restrict p, const struct xpart* restrict xp) { + + /* Physical constants */ + const double m_H = phys_const->const_proton_mass; + const double k_B = phys_const->const_boltzmann_k; + + /* Gas properties */ + const double T_transition = hydro_props->hydrogen_ionization_temperature; + const double mu_neutral = hydro_props->mu_neutral; + const double mu_ionised = hydro_props->mu_ionised; + + /* Particle temperature */ + const double u = hydro_get_physical_internal_energy(p, xp, cosmo); + + /* Temperature over mean molecular weight */ + const double T_over_mu = hydro_gamma_minus_one * u * m_H / k_B; + + /* Are we above or below the HII -> HI transition? */ + if (T_over_mu > (T_transition + 1.) / mu_ionised) + return T_over_mu * mu_ionised; + else if (T_over_mu < (T_transition - 1.) / mu_neutral) + return T_over_mu * mu_neutral; + else + return T_transition; +} + /** * @brief Returns the total radiated energy by this particle. * diff --git a/src/cooling/Compton/cooling_io.h b/src/cooling/Compton/cooling_io.h index d020587c920f781450a5183954bc6c429e461512..8fa3944ff78e7592da3978ee9465451c96e1d533 100644 --- a/src/cooling/Compton/cooling_io.h +++ b/src/cooling/Compton/cooling_io.h @@ -23,6 +23,7 @@ #include "../config.h" /* Local includes */ +#include "cooling.h" #include "io_properties.h" #ifdef HAVE_HDF5 @@ -41,11 +42,18 @@ __attribute__((always_inline)) INLINE static void cooling_write_flavour( } #endif +INLINE static void convert_part_T(const struct engine* e, const struct part* p, + const struct xpart* xp, float* ret) { + + ret[0] = cooling_get_temperature(e->physical_constants, e->hydro_properties, + e->internal_units, e->cosmology, + e->cooling_func, p, xp); +} + /** * @brief Specifies which particle fields to write to a dataset * - * Nothing to write for this scheme. - * + * @param parts The particle array. * @param xparts The extended particle array. * @param list The list of i/o properties to write. * @param cooling The #cooling_function_data @@ -53,10 +61,14 @@ __attribute__((always_inline)) INLINE static void cooling_write_flavour( * @return Returns the number of fields to write. */ __attribute__((always_inline)) INLINE static int cooling_write_particles( - const struct xpart* xparts, struct io_props* list, + const struct part* parts, const struct xpart* xparts, struct io_props* list, const struct cooling_function_data* cooling) { - return 0; + list[0] = io_make_output_field_convert_part("Temperature", FLOAT, 1, + UNIT_CONV_TEMPERATURE, parts, + xparts, convert_part_T); + + return 1; } #endif /* SWIFT_COOLING_IO_COMPTON_H */ diff --git a/src/cooling/EAGLE/cooling.c b/src/cooling/EAGLE/cooling.c index 8dcef4035f633954906a8539f0e92e1ea4e89ca0..f85b4f43a1d689c6216f3a6703453c49cd72ce8b 100644 --- a/src/cooling/EAGLE/cooling.c +++ b/src/cooling/EAGLE/cooling.c @@ -37,6 +37,7 @@ #include "cooling_struct.h" #include "cooling_tables.h" #include "error.h" +#include "exp10.h" #include "hydro.h" #include "interpolate.h" #include "io_properties.h" @@ -151,9 +152,9 @@ void cooling_update(const struct cosmology *cosmo, * * @param logu_init Initial guess for log(internal energy) * @param u_ini Internal energy at beginning of hydro step - * @param n_h_i Particle hydrogen number density index - * @param d_n_h Particle hydrogen number density offset - * @param He_i Particle helium fraction index + * @param n_H_index Particle hydrogen number density index + * @param d_n_H Particle hydrogen number density offset + * @param He_index Particle helium fraction index * @param d_He Particle helium fraction offset * @param He_reion_heat Heating due to helium reionization * (only depends on redshift, so passed as parameter) @@ -166,8 +167,8 @@ void cooling_update(const struct cosmology *cosmo, * @param bisection_flag Flag to identify if scheme failed to converge */ INLINE static float newton_iter( - float logu_init, double u_ini, int n_h_i, float d_n_h, int He_i, float d_He, - float He_reion_heat, struct part *restrict p, + float logu_init, double u_ini, int n_H_index, float d_n_H, int He_index, + float d_He, float He_reion_heat, struct part *restrict p, const struct cosmology *restrict cosmo, const struct cooling_function_data *restrict cooling, const struct phys_const *restrict phys_const, @@ -202,10 +203,10 @@ INLINE static float newton_iter( { logu_old = logu; LambdaNet_old = LambdaNet; - LambdaNet = - (He_reion_heat / (dt * ratefact_cgs)) + - eagle_cooling_rate(logu_old, cosmo->z, n_H_cgs, abundance_ratio, n_h_i, - d_n_h, He_i, d_He, cooling, &dLambdaNet_du); + LambdaNet = (He_reion_heat / (dt * ratefact_cgs)) + + eagle_cooling_rate(logu_old, cosmo->z, n_H_cgs, abundance_ratio, + n_H_index, d_n_H, He_index, d_He, cooling, + &dLambdaNet_du); /* Newton iteration. For details on how the cooling equation is integrated * see documentation in theory/Cooling/ */ @@ -243,9 +244,9 @@ INLINE static float newton_iter( * @param u_ini_cgs Internal energy at beginning of hydro step in CGS. * @param n_H_cgs Hydrogen number density in CGS. * @param redshift Current redshift. - * @param n_h_i Particle hydrogen number density index. - * @param d_n_h Particle hydrogen number density offset. - * @param He_i Particle helium fraction index. + * @param n_H_index Particle hydrogen number density index. + * @param d_n_H Particle hydrogen number density offset. + * @param He_index Particle helium fraction index. * @param d_He Particle helium fraction offset. * @param Lambda_He_reion_cgs Cooling rate coming from He reionization. * @param ratefact_cgs Multiplication factor to get a cooling rate. @@ -256,8 +257,9 @@ INLINE static float newton_iter( */ INLINE static double bisection_iter( const double u_ini_cgs, const double n_H_cgs, const double redshift, - int n_h_i, float d_n_h, int He_i, float d_He, double Lambda_He_reion_cgs, - double ratefact_cgs, const struct cooling_function_data *restrict cooling, + int n_H_index, float d_n_H, int He_index, float d_He, + double Lambda_He_reion_cgs, double ratefact_cgs, + const struct cooling_function_data *restrict cooling, const float abundance_ratio[chemistry_element_count + 2], double dt_cgs, long long ID) { @@ -270,10 +272,10 @@ INLINE static double bisection_iter( /*************************************/ double LambdaNet_cgs = - Lambda_He_reion_cgs + eagle_cooling_rate(log(u_ini_cgs), redshift, - n_H_cgs, abundance_ratio, n_h_i, - d_n_h, He_i, d_He, cooling, - /*dLambdaNet_du=*/NULL); + Lambda_He_reion_cgs + + eagle_cooling_rate(log(u_ini_cgs), redshift, n_H_cgs, abundance_ratio, + n_H_index, d_n_H, He_index, d_He, cooling, + /*dLambdaNet_du=*/NULL); /*************************************/ /* Let's try to bracket the solution */ @@ -289,7 +291,7 @@ INLINE static double bisection_iter( LambdaNet_cgs = Lambda_He_reion_cgs + eagle_cooling_rate(log(u_lower_cgs), redshift, n_H_cgs, abundance_ratio, - n_h_i, d_n_h, He_i, d_He, cooling, + n_H_index, d_n_H, He_index, d_He, cooling, /*dLambdaNet_du=*/NULL); int i = 0; @@ -301,11 +303,11 @@ INLINE static double bisection_iter( u_upper_cgs /= bracket_factor; /* Compute a new rate */ - LambdaNet_cgs = - Lambda_He_reion_cgs + - eagle_cooling_rate(log(u_lower_cgs), redshift, n_H_cgs, - abundance_ratio, n_h_i, d_n_h, He_i, d_He, cooling, - /*dLambdaNet_du=*/NULL); + LambdaNet_cgs = Lambda_He_reion_cgs + + eagle_cooling_rate(log(u_lower_cgs), redshift, n_H_cgs, + abundance_ratio, n_H_index, d_n_H, + He_index, d_He, cooling, + /*dLambdaNet_du=*/NULL); i++; } @@ -325,7 +327,7 @@ INLINE static double bisection_iter( LambdaNet_cgs = Lambda_He_reion_cgs + eagle_cooling_rate(log(u_upper_cgs), redshift, n_H_cgs, abundance_ratio, - n_h_i, d_n_h, He_i, d_He, cooling, + n_H_index, d_n_H, He_index, d_He, cooling, /*dLambdaNet_du=*/NULL); int i = 0; @@ -337,11 +339,11 @@ INLINE static double bisection_iter( u_upper_cgs *= bracket_factor; /* Compute a new rate */ - LambdaNet_cgs = - Lambda_He_reion_cgs + - eagle_cooling_rate(log(u_upper_cgs), redshift, n_H_cgs, - abundance_ratio, n_h_i, d_n_h, He_i, d_He, cooling, - /*dLambdaNet_du=*/NULL); + LambdaNet_cgs = Lambda_He_reion_cgs + + eagle_cooling_rate(log(u_upper_cgs), redshift, n_H_cgs, + abundance_ratio, n_H_index, d_n_H, + He_index, d_He, cooling, + /*dLambdaNet_du=*/NULL); i++; } @@ -371,7 +373,7 @@ INLINE static double bisection_iter( LambdaNet_cgs = Lambda_He_reion_cgs + eagle_cooling_rate(log(u_next_cgs), redshift, n_H_cgs, abundance_ratio, - n_h_i, d_n_h, He_i, d_He, cooling, + n_H_index, d_n_H, He_index, d_He, cooling, /*dLambdaNet_du=*/NULL); /* Where do we go next? */ @@ -453,12 +455,19 @@ void cooling_cool_part(const struct phys_const *restrict phys_const, const double u_0_cgs = u_0 * cooling->internal_energy_to_cgs; const double dt_cgs = dt * units_cgs_conversion_factor(us, UNIT_CONV_TIME); + /* Change in redshift over the course of this time-step + (See cosmology theory document for the derivation) */ + const double delta_redshift = -dt * cosmo->H * cosmo->a_inv; + /* Get this particle's abundance ratios */ float abundance_ratio[chemistry_element_count + 2]; abundance_ratio_to_solar(p, cooling, abundance_ratio); - /* Get the H and He mass fractions */ + /* Get the Hydrogen mass fraction */ const float XH = p->chemistry_data.metal_mass_fraction[chemistry_element_H]; + + /* Get the Helium mass fraction. Note that this is He / (H + He), i.e. a + * metal-free Helium mass fraction as per the Wiersma+08 definition */ const float HeFrac = p->chemistry_data.metal_mass_fraction[chemistry_element_He] / (XH + p->chemistry_data.metal_mass_fraction[chemistry_element_He]); @@ -472,30 +481,35 @@ void cooling_cool_part(const struct phys_const *restrict phys_const, * equivalent expression below */ const double ratefact_cgs = n_H_cgs * (XH * cooling->inv_proton_mass_cgs); + /* compute hydrogen number density and helium fraction table indices and + * offsets (These are fixed for any value of u, so no need to recompute them) + */ + int He_index, n_H_index; + float d_He, d_n_H; + get_index_1d(cooling->HeFrac, eagle_cooling_N_He_frac, HeFrac, &He_index, + &d_He); + get_index_1d(cooling->nH, eagle_cooling_N_density, log10(n_H_cgs), &n_H_index, + &d_n_H); + + /* Start by computing the cooling (heating actually) rate from Helium + re-ionization as this needs to be added on no matter what */ + /* Get helium and hydrogen reheating term */ const double Helium_reion_heat_cgs = eagle_helium_reionization_extraheat( - cooling->z_index, -dt * cosmo->H * cosmo->a_inv, cooling); + cooling->z_index, delta_redshift, cooling); /* Convert this into a rate */ const double Lambda_He_reion_cgs = Helium_reion_heat_cgs / (dt_cgs * ratefact_cgs); - /* compute hydrogen number density and helium fraction table indices and - * offsets (These are fixed for of u, so no need to recompute them) */ - int He_i, n_h_i; - float d_He, d_n_h; - get_index_1d(cooling->HeFrac, eagle_cooling_N_He_frac, HeFrac, &He_i, &d_He); - get_index_1d(cooling->nH, eagle_cooling_N_density, log10(n_H_cgs), &n_h_i, - &d_n_h); - /* Let's compute the internal energy at the end of the step */ double u_final_cgs; /* First try an explicit integration (note we ignore the derivative) */ const double LambdaNet_cgs = Lambda_He_reion_cgs + eagle_cooling_rate(log(u_0_cgs), cosmo->z, n_H_cgs, - abundance_ratio, n_h_i, d_n_h, - He_i, d_He, cooling, + abundance_ratio, n_H_index, + d_n_H, He_index, d_He, cooling, /*dLambdaNet_du=*/NULL); /* if cooling rate is small, take the explicit solution */ @@ -508,33 +522,34 @@ void cooling_cool_part(const struct phys_const *restrict phys_const, int bisection_flag = 1; -#ifdef TO_BE_DONE - if (cooling->newton_flag) { + // MATTHIEU: TO DO restore the Newton-Raphson scheme + if (0 && cooling->newton_flag) { + /* Ok, try a Newton-Raphson scheme instead */ - log_u_final_cgs = newton_iter( - log(u_0_cgs), u_0_cgs, n_h_i, d_n_h, He_i, d_He, LambdaTune, p, cosmo, - cooling, phys_const, abundance_ratio, dt_cgs, &bisection_flag); + double log_u_final_cgs = + newton_iter(log(u_0_cgs), u_0_cgs, n_H_index, d_n_H, He_index, d_He, + Lambda_He_reion_cgs, p, cosmo, cooling, phys_const, + abundance_ratio, dt_cgs, &bisection_flag); /* Check if newton scheme sent us to a higher energy despite being in - a - * cooling regime If it did try newton scheme with a better guess. - (Guess - * internal energy near equilibrium solution). */ - if (LambdaNet < 0 && log_u_final_cgs > log(u_0_cgs)) { + a cooling regime If it did try newton scheme with a better guess. + (Guess internal energy near equilibrium solution). */ + if (LambdaNet_cgs < 0 && log_u_final_cgs > log(u_0_cgs)) { bisection_flag = 0; log_u_final_cgs = - newton_iter(newton_log_u_guess_cgs, u_0_cgs, n_h_i, d_n_h, He_i, - d_He, LambdaTune, p, cosmo, cooling, phys_const, - abundance_ratio, dt_cgs, &bisection_flag); + newton_iter(newton_log_u_guess_cgs, u_0_cgs, n_H_index, d_n_H, + He_index, d_He, Lambda_He_reion_cgs, p, cosmo, cooling, + phys_const, abundance_ratio, dt_cgs, &bisection_flag); } + + u_final_cgs = exp(log_u_final_cgs); } -#endif /* Alright, all else failed, let's bisect */ if (bisection_flag || !(cooling->newton_flag)) { u_final_cgs = - bisection_iter(u_0_cgs, n_H_cgs, cosmo->z, n_h_i, d_n_h, He_i, d_He, - Lambda_He_reion_cgs, ratefact_cgs, cooling, + bisection_iter(u_0_cgs, n_H_cgs, cosmo->z, n_H_index, d_n_H, He_index, + d_He, Lambda_He_reion_cgs, ratefact_cgs, cooling, abundance_ratio, dt_cgs, p->id); } } @@ -620,6 +635,67 @@ __attribute__((always_inline)) INLINE void cooling_first_init_part( xp->cooling_data.radiated_energy = 0.f; } +/** + * @brief Compute the temperature of a #part based on the cooling function. + * + * We use the Temperature table of the Wiersma+08 set. This computes the + * equilibirum temperature of a gas for a given redshift, Hydrogen density, + * internal energy per unit mass and Helium fraction. + * + * The temperature returned is consistent with the cooling rates. + * + * @param phys_const #phys_const data structure. + * @param hydro_props The properties of the hydro scheme. + * @param us The internal system of units. + * @param cosmo #cosmology data structure. + * @param cooling #cooling_function_data struct. + * @param p #part data. + * @param xp Pointer to the #xpart data. + */ +float cooling_get_temperature( + const struct phys_const *restrict phys_const, + const struct hydro_props *restrict hydro_props, + const struct unit_system *restrict us, + const struct cosmology *restrict cosmo, + const struct cooling_function_data *restrict cooling, + const struct part *restrict p, const struct xpart *restrict xp) { + + /* Get physical internal energy */ + const float u = hydro_get_physical_internal_energy(p, xp, cosmo); + const double u_cgs = u * cooling->internal_energy_to_cgs; + + /* Get the Hydrogen mass fraction */ + const float XH = p->chemistry_data.metal_mass_fraction[chemistry_element_H]; + + /* Get the Helium mass fraction. Note that this is He / (H + He), i.e. a + * metal-free Helium mass fraction as per the Wiersma+08 definition */ + const float HeFrac = + p->chemistry_data.metal_mass_fraction[chemistry_element_He] / + (XH + p->chemistry_data.metal_mass_fraction[chemistry_element_He]); + + /* Convert Hydrogen mass fraction into Hydrogen number density */ + const float rho = hydro_get_physical_density(p, cosmo); + const double n_H = rho * XH / phys_const->const_proton_mass; + const double n_H_cgs = n_H * cooling->number_density_to_cgs; + + /* compute hydrogen number density and helium fraction table indices and + * offsets */ + int He_index, n_H_index; + float d_He, d_n_H; + get_index_1d(cooling->HeFrac, eagle_cooling_N_He_frac, HeFrac, &He_index, + &d_He); + get_index_1d(cooling->nH, eagle_cooling_N_density, log10(n_H_cgs), &n_H_index, + &d_n_H); + + /* Compute the log10 of the temperature by interpolating the table */ + const double log_10_T = eagle_convert_u_to_temp( + log10(u_cgs), cosmo->z, /*compute_dT_du=*/0, /*dT_du=*/NULL, n_H_index, + He_index, d_n_H, d_He, cooling); + + /* Undo the log! */ + return exp10(log_10_T); +} + /** * @brief Returns the total radiated energy by this particle. * diff --git a/src/cooling/EAGLE/cooling.h b/src/cooling/EAGLE/cooling.h index 5685692c379c508bc8d6a4ab8d22bb89ba1f4a17..02ee37a416db322c2813cf4da7fe4105d5d8e84f 100644 --- a/src/cooling/EAGLE/cooling.h +++ b/src/cooling/EAGLE/cooling.h @@ -59,6 +59,14 @@ void cooling_first_init_part( const struct cooling_function_data *restrict cooling, const struct part *restrict p, struct xpart *restrict xp); +float cooling_get_temperature( + const struct phys_const *restrict phys_const, + const struct hydro_props *restrict hydro_props, + const struct unit_system *restrict us, + const struct cosmology *restrict cosmo, + const struct cooling_function_data *restrict cooling, + const struct part *restrict p, const struct xpart *restrict xp); + float cooling_get_radiated_energy(const struct xpart *restrict xp); void cooling_init_backend(struct swift_params *parameter_file, diff --git a/src/cooling/EAGLE/cooling_io.h b/src/cooling/EAGLE/cooling_io.h index 48c845c254b41f02d8b4ea39ae43a990b0436ac8..5508153afc094d84383893f55ac0362a6d427b24 100644 --- a/src/cooling/EAGLE/cooling_io.h +++ b/src/cooling/EAGLE/cooling_io.h @@ -23,6 +23,7 @@ #include "../config.h" /* Local includes */ +#include "cooling.h" #include "io_properties.h" #ifdef HAVE_HDF5 @@ -40,9 +41,18 @@ __attribute__((always_inline)) INLINE static void cooling_write_flavour( } #endif +INLINE static void convert_part_T(const struct engine* e, const struct part* p, + const struct xpart* xp, float* ret) { + + ret[0] = cooling_get_temperature(e->physical_constants, e->hydro_properties, + e->internal_units, e->cosmology, + e->cooling_func, p, xp); +} + /** * @brief Specifies which particle fields to write to a dataset * + * @param parts The particle array. * @param xparts The extended data particle array. * @param list The list of i/o properties to write. * @param cooling The #cooling_function_data @@ -50,9 +60,13 @@ __attribute__((always_inline)) INLINE static void cooling_write_flavour( * @return Returns the number of fields to write. */ __attribute__((always_inline)) INLINE static int cooling_write_particles( - const struct xpart* xparts, struct io_props* list, + const struct part* parts, const struct xpart* xparts, struct io_props* list, const struct cooling_function_data* cooling) { - return 0; + + list[0] = io_make_output_field_convert_part("Temperature", FLOAT, 1, + UNIT_CONV_TEMPERATURE, parts, + xparts, convert_part_T); + return 1; } #endif /* SWIFT_COOLING_EAGLE_IO_H */ diff --git a/src/cooling/EAGLE/cooling_rates.h b/src/cooling/EAGLE/cooling_rates.h index 621f7c7b0781ba9806b4b5922843947079941fee..c78be6a30849a7b8a79e56d7fbdefe2eede866f3 100644 --- a/src/cooling/EAGLE/cooling_rates.h +++ b/src/cooling/EAGLE/cooling_rates.h @@ -25,6 +25,7 @@ /* Local includes. */ #include "cooling_tables.h" +#include "exp10.h" #include "interpolate.h" /** @@ -332,7 +333,7 @@ __attribute__((always_inline)) INLINE double eagle_Compton_cooling_rate( * to solar metal abundances * * @param n_H_index Particle hydrogen number density index - * @param d_n_h Particle hydrogen number density offset + * @param d_n_H Particle hydrogen number density offset * @param He_index Particle helium fraction index * @param d_He Particle helium fraction offset * @param cooling Cooling data structure @@ -345,7 +346,7 @@ __attribute__((always_inline)) INLINE double eagle_Compton_cooling_rate( INLINE static double eagle_metal_cooling_rate( double log10_u_cgs, double redshift, double n_H_cgs, const float solar_ratio[chemistry_element_count + 2], int n_H_index, - float d_n_h, int He_index, float d_He, + float d_n_H, int He_index, float d_He, const struct cooling_function_data *restrict cooling, double *dlambda_du, double *element_lambda) { @@ -364,14 +365,15 @@ INLINE static double eagle_metal_cooling_rate( /* Temperature */ float dT_du = -1.f; - const double T = + const double log_10_T = eagle_convert_u_to_temp(log10_u_cgs, redshift, compute_dT_du, &dT_du, - n_H_index, He_index, d_n_h, d_He, cooling); + n_H_index, He_index, d_n_H, d_He, cooling); /* Get index along temperature dimension of the tables */ int T_index; float d_T; - get_index_1d(cooling->Temp, eagle_cooling_N_temperature, T, &T_index, &d_T); + get_index_1d(cooling->Temp, eagle_cooling_N_temperature, log_10_T, &T_index, + &d_T); #ifdef TO_BE_DONE /* Difference between entries on the temperature table around u */ @@ -391,7 +393,7 @@ INLINE static double eagle_metal_cooling_rate( * in redshift */ Lambda_free = interpolation_3d(cooling->table.H_plus_He_heating, /* */ n_H_index, He_index, T_index, /* */ - d_n_h, d_He, d_T, /* */ + d_n_H, d_He, d_T, /* */ eagle_cooling_N_density, /* */ eagle_cooling_N_He_frac, /* */ eagle_cooling_N_temperature); /* */ @@ -416,7 +418,7 @@ INLINE static double eagle_metal_cooling_rate( Lambda_free = interpolation_4d(cooling->table.H_plus_He_heating, /* */ /*z_index=*/0, n_H_index, He_index, T_index, /* */ - cooling->dz, d_n_h, d_He, d_T, /* */ + cooling->dz, d_n_H, d_He, d_T, /* */ eagle_cooling_N_loaded_redshifts, /* */ eagle_cooling_N_density, /* */ eagle_cooling_N_He_frac, /* */ @@ -460,7 +462,7 @@ INLINE static double eagle_metal_cooling_rate( H_plus_He_electron_abundance = interpolation_3d(cooling->table.H_plus_He_electron_abundance, /* */ n_H_index, He_index, T_index, /* */ - d_n_h, d_He, d_T, /* */ + d_n_H, d_He, d_T, /* */ eagle_cooling_N_density, /* */ eagle_cooling_N_He_frac, /* */ eagle_cooling_N_temperature); /* */ @@ -485,7 +487,7 @@ INLINE static double eagle_metal_cooling_rate( H_plus_He_electron_abundance = interpolation_4d(cooling->table.H_plus_He_electron_abundance, /* */ /*z_index=*/0, n_H_index, He_index, T_index, /* */ - cooling->dz, d_n_h, d_He, d_T, /* */ + cooling->dz, d_n_H, d_He, d_T, /* */ eagle_cooling_N_loaded_redshifts, /* */ eagle_cooling_N_density, /* */ eagle_cooling_N_He_frac, /* */ @@ -516,6 +518,8 @@ INLINE static double eagle_metal_cooling_rate( if ((redshift > cooling->Redshifts[eagle_cooling_N_redshifts - 1]) || (redshift > cooling->H_reion_z)) { + const double T = exp10(log_10_T); + /* Note the minus sign */ Lambda_Compton -= eagle_Compton_cooling_rate(cooling, redshift, n_H_cgs, T, H_plus_He_electron_abundance); @@ -539,7 +543,7 @@ INLINE static double eagle_metal_cooling_rate( solar_electron_abundance = interpolation_2d(cooling->table.electron_abundance, /* */ n_H_index, T_index, /* */ - d_n_h, d_T, /* */ + d_n_H, d_T, /* */ eagle_cooling_N_density, /* */ eagle_cooling_N_temperature); /* */ @@ -562,7 +566,7 @@ INLINE static double eagle_metal_cooling_rate( solar_electron_abundance = interpolation_3d(cooling->table.electron_abundance, /* */ /*z_index=*/0, n_H_index, T_index, /* */ - cooling->dz, d_n_h, d_T, /* */ + cooling->dz, d_n_H, d_T, /* */ eagle_cooling_N_loaded_redshifts, /* */ eagle_cooling_N_density, /* */ eagle_cooling_N_temperature); /* */ @@ -601,7 +605,7 @@ INLINE static double eagle_metal_cooling_rate( lambda_metal[elem] = interpolation_3d_no_x(cooling->table.metal_heating, /* */ elem, n_H_index, T_index, /* */ - /*delta_elem=*/0.f, d_n_h, d_T, /* */ + /*delta_elem=*/0.f, d_n_H, d_T, /* */ eagle_cooling_N_metal, /* */ eagle_cooling_N_density, /* */ eagle_cooling_N_temperature); /* */ @@ -637,7 +641,7 @@ INLINE static double eagle_metal_cooling_rate( lambda_metal[elem] = interpolation_4d_no_x( cooling->table.metal_heating, /* */ elem, /*z_index=*/0, n_H_index, T_index, /* */ - /*delta_elem=*/0.f, cooling->dz, d_n_h, d_T, /* */ + /*delta_elem=*/0.f, cooling->dz, d_n_H, d_T, /* */ eagle_cooling_N_metal, /* */ eagle_cooling_N_loaded_redshifts, /* */ eagle_cooling_N_density, /* */ @@ -696,7 +700,7 @@ INLINE static double eagle_metal_cooling_rate( * @param abundance_ratio Ratio of element abundance to solar. * * @param n_H_index Particle hydrogen number density index - * @param d_n_h Particle hydrogen number density offset + * @param d_n_H Particle hydrogen number density offset * @param He_index Particle helium fraction index * @param d_He Particle helium fraction offset * @param cooling #cooling_function_data structure @@ -709,12 +713,12 @@ INLINE static double eagle_metal_cooling_rate( INLINE static double eagle_cooling_rate( double log_u_cgs, double redshift, double n_H_cgs, const float abundance_ratio[chemistry_element_count + 2], int n_H_index, - float d_n_h, int He_index, float d_He, + float d_n_H, int He_index, float d_He, const struct cooling_function_data *restrict cooling, double *dLambdaNet_du) { return eagle_metal_cooling_rate(log_u_cgs / M_LN10, redshift, n_H_cgs, - abundance_ratio, n_H_index, d_n_h, He_index, + abundance_ratio, n_H_index, d_n_H, He_index, d_He, cooling, dLambdaNet_du, /*element_lambda=*/NULL); } diff --git a/src/cooling/const_du/cooling.h b/src/cooling/const_du/cooling.h index dac92f09837cbb40cc49f1e8dc5d4c627ce7023a..8dc545f5b18cc784274921a226a7d679c367a7e4 100644 --- a/src/cooling/const_du/cooling.h +++ b/src/cooling/const_du/cooling.h @@ -164,6 +164,49 @@ __attribute__((always_inline)) INLINE static void cooling_first_init_part( xp->cooling_data.radiated_energy = 0.f; } +/** + * @brief Compute the temperature of a #part based on the cooling function. + * + * @param phys_const #phys_const data structure. + * @param hydro_props The properties of the hydro scheme. + * @param us The internal system of units. + * @param cosmo #cosmology data structure. + * @param cooling #cooling_function_data struct. + * @param p #part data. + * @param xp Pointer to the #xpart data. + */ +INLINE static float cooling_get_temperature( + const struct phys_const* restrict phys_const, + const struct hydro_props* restrict hydro_props, + const struct unit_system* restrict us, + const struct cosmology* restrict cosmo, + const struct cooling_function_data* restrict cooling, + const struct part* restrict p, const struct xpart* restrict xp) { + + /* Physical constants */ + const double m_H = phys_const->const_proton_mass; + const double k_B = phys_const->const_boltzmann_k; + + /* Gas properties */ + const double T_transition = hydro_props->hydrogen_ionization_temperature; + const double mu_neutral = hydro_props->mu_neutral; + const double mu_ionised = hydro_props->mu_ionised; + + /* Particle temperature */ + const double u = hydro_get_physical_internal_energy(p, xp, cosmo); + + /* Temperature over mean molecular weight */ + const double T_over_mu = hydro_gamma_minus_one * u * m_H / k_B; + + /* Are we above or below the HII -> HI transition? */ + if (T_over_mu > (T_transition + 1.) / mu_ionised) + return T_over_mu * mu_ionised; + else if (T_over_mu < (T_transition - 1.) / mu_neutral) + return T_over_mu * mu_neutral; + else + return T_transition; +} + /** * @brief Returns the total radiated energy by this particle. * diff --git a/src/cooling/const_du/cooling_io.h b/src/cooling/const_du/cooling_io.h index f4a327f14ec071bc62c4cf57bb118df71bab2b3e..a60aa5d282d0a244f206f74827f0c1979d3bcb75 100644 --- a/src/cooling/const_du/cooling_io.h +++ b/src/cooling/const_du/cooling_io.h @@ -34,6 +34,7 @@ #include "../config.h" /* Local includes */ +#include "cooling.h" #include "io_properties.h" #ifdef HAVE_HDF5 @@ -50,9 +51,18 @@ __attribute__((always_inline)) INLINE static void cooling_write_flavour( } #endif +INLINE static void convert_part_T(const struct engine* e, const struct part* p, + const struct xpart* xp, float* ret) { + + ret[0] = cooling_get_temperature(e->physical_constants, e->hydro_properties, + e->internal_units, e->cosmology, + e->cooling_func, p, xp); +} + /** * @brief Specifies which particle fields to write to a dataset * + * @param parts The particle array. * @param xparts The exended particle data array. * @param list The list of i/o properties to write. * @param cooling The #cooling_function_data @@ -60,9 +70,14 @@ __attribute__((always_inline)) INLINE static void cooling_write_flavour( * @return Returns the number of fields to write. */ __attribute__((always_inline)) INLINE static int cooling_write_particles( - const struct xpart* xparts, struct io_props* list, + const struct part* parts, const struct xpart* xparts, struct io_props* list, const struct cooling_function_data* cooling) { - return 0; + + list[0] = io_make_output_field_convert_part("Temperature", FLOAT, 1, + UNIT_CONV_TEMPERATURE, parts, + xparts, convert_part_T); + + return 1; } #endif /* SWIFT_COOLING_CONST_DU_IO_H */ diff --git a/src/cooling/const_lambda/cooling.h b/src/cooling/const_lambda/cooling.h index 3c336060bdadae9b0cd0034bc0ccb1e9e9266aff..09c96413ce0d061c01bc267af46e65ee23d2834f 100644 --- a/src/cooling/const_lambda/cooling.h +++ b/src/cooling/const_lambda/cooling.h @@ -230,6 +230,49 @@ __attribute__((always_inline)) INLINE static void cooling_first_init_part( xp->cooling_data.radiated_energy = 0.f; } +/** + * @brief Compute the temperature of a #part based on the cooling function. + * + * @param phys_const #phys_const data structure. + * @param hydro_props The properties of the hydro scheme. + * @param us The internal system of units. + * @param cosmo #cosmology data structure. + * @param cooling #cooling_function_data struct. + * @param p #part data. + * @param xp Pointer to the #xpart data. + */ +INLINE static float cooling_get_temperature( + const struct phys_const* restrict phys_const, + const struct hydro_props* restrict hydro_props, + const struct unit_system* restrict us, + const struct cosmology* restrict cosmo, + const struct cooling_function_data* restrict cooling, + const struct part* restrict p, const struct xpart* restrict xp) { + + /* Physical constants */ + const double m_H = phys_const->const_proton_mass; + const double k_B = phys_const->const_boltzmann_k; + + /* Gas properties */ + const double T_transition = hydro_props->hydrogen_ionization_temperature; + const double mu_neutral = hydro_props->mu_neutral; + const double mu_ionised = hydro_props->mu_ionised; + + /* Particle temperature */ + const double u = hydro_get_physical_internal_energy(p, xp, cosmo); + + /* Temperature over mean molecular weight */ + const double T_over_mu = hydro_gamma_minus_one * u * m_H / k_B; + + /* Are we above or below the HII -> HI transition? */ + if (T_over_mu > (T_transition + 1.) / mu_ionised) + return T_over_mu * mu_ionised; + else if (T_over_mu < (T_transition - 1.) / mu_neutral) + return T_over_mu * mu_neutral; + else + return T_transition; +} + /** * @brief Returns the total radiated energy by this particle. * diff --git a/src/cooling/const_lambda/cooling_io.h b/src/cooling/const_lambda/cooling_io.h index 0dca5011ebe5bc6c2a4866387e9cf1ac0ba3447a..9437f0f94db41725d6715cf349843bf079137305 100644 --- a/src/cooling/const_lambda/cooling_io.h +++ b/src/cooling/const_lambda/cooling_io.h @@ -32,6 +32,7 @@ #include "../config.h" /* Local includes */ +#include "cooling.h" #include "io_properties.h" #ifdef HAVE_HDF5 @@ -49,11 +50,18 @@ __attribute__((always_inline)) INLINE static void cooling_write_flavour( } #endif +INLINE static void convert_part_T(const struct engine* e, const struct part* p, + const struct xpart* xp, float* ret) { + + ret[0] = cooling_get_temperature(e->physical_constants, e->hydro_properties, + e->internal_units, e->cosmology, + e->cooling_func, p, xp); +} + /** * @brief Specifies which particle fields to write to a dataset * - * Nothing to write for this scheme. - * + * @param parts The particle array. * @param xparts The extended particle array. * @param list The list of i/o properties to write. * @param cooling The #cooling_function_data @@ -61,10 +69,14 @@ __attribute__((always_inline)) INLINE static void cooling_write_flavour( * @return Returns the number of fields to write. */ __attribute__((always_inline)) INLINE static int cooling_write_particles( - const struct xpart* xparts, struct io_props* list, + const struct part* parts, const struct xpart* xparts, struct io_props* list, const struct cooling_function_data* cooling) { - return 0; + list[0] = io_make_output_field_convert_part("Temperature", FLOAT, 1, + UNIT_CONV_TEMPERATURE, parts, + xparts, convert_part_T); + + return 1; } #endif /* SWIFT_COOLING_CONST_LAMBDA_IO_H */ diff --git a/src/cooling/none/cooling.h b/src/cooling/none/cooling.h index 868bfad7fc12c2f89d54949642bd5e9d902b42b6..579cf2ae9c2db290300f8367111f91aab9bd27d0 100644 --- a/src/cooling/none/cooling.h +++ b/src/cooling/none/cooling.h @@ -119,6 +119,49 @@ __attribute__((always_inline)) INLINE static void cooling_first_init_part( const struct cooling_function_data* data, const struct part* restrict p, struct xpart* restrict xp) {} +/** + * @brief Compute the temperature of a #part based on the cooling function. + * + * @param phys_const #phys_const data structure. + * @param hydro_props The properties of the hydro scheme. + * @param us The internal system of units. + * @param cosmo #cosmology data structure. + * @param cooling #cooling_function_data struct. + * @param p #part data. + * @param xp Pointer to the #xpart data. + */ +INLINE static float cooling_get_temperature( + const struct phys_const* restrict phys_const, + const struct hydro_props* restrict hydro_props, + const struct unit_system* restrict us, + const struct cosmology* restrict cosmo, + const struct cooling_function_data* restrict cooling, + const struct part* restrict p, const struct xpart* restrict xp) { + + /* Physical constants */ + const double m_H = phys_const->const_proton_mass; + const double k_B = phys_const->const_boltzmann_k; + + /* Gas properties */ + const double T_transition = hydro_props->hydrogen_ionization_temperature; + const double mu_neutral = hydro_props->mu_neutral; + const double mu_ionised = hydro_props->mu_ionised; + + /* Particle temperature */ + const double u = hydro_get_physical_internal_energy(p, xp, cosmo); + + /* Temperature over mean molecular weight */ + const double T_over_mu = hydro_gamma_minus_one * u * m_H / k_B; + + /* Are we above or below the HII -> HI transition? */ + if (T_over_mu > (T_transition + 1.) / mu_ionised) + return T_over_mu * mu_ionised; + else if (T_over_mu < (T_transition - 1.) / mu_neutral) + return T_over_mu * mu_neutral; + else + return T_transition; +} + /** * @brief Returns the total radiated energy by this particle. * diff --git a/src/cooling/none/cooling_io.h b/src/cooling/none/cooling_io.h index 518c166480a0b81f6856c8a39e2a64d34369dc84..16b4b4ca29f8ebd325decc25420d7db617e1e4ef 100644 --- a/src/cooling/none/cooling_io.h +++ b/src/cooling/none/cooling_io.h @@ -23,6 +23,7 @@ #include "../config.h" /* Local includes */ +#include "cooling.h" #include "io_properties.h" #ifdef HAVE_HDF5 @@ -39,9 +40,18 @@ __attribute__((always_inline)) INLINE static void cooling_write_flavour( } #endif +INLINE static void convert_part_T(const struct engine* e, const struct part* p, + const struct xpart* xp, float* ret) { + + ret[0] = cooling_get_temperature(e->physical_constants, e->hydro_properties, + e->internal_units, e->cosmology, + e->cooling_func, p, xp); +} + /** * @brief Specifies which particle fields to write to a dataset * + * @param parts The particle array. * @param xparts The extended particle array. * @param list The list of i/o properties to write. * @param cooling The #cooling_function_data @@ -49,9 +59,13 @@ __attribute__((always_inline)) INLINE static void cooling_write_flavour( * @return Returns the number of fields to write. */ __attribute__((always_inline)) INLINE static int cooling_write_particles( - const struct xpart* xparts, struct io_props* list, + const struct part* parts, const struct xpart* xparts, struct io_props* list, const struct cooling_function_data* cooling) { - return 0; + + list[0] = io_make_output_field_convert_part("Temperature", FLOAT, 1, + UNIT_CONV_TEMPERATURE, parts, + xparts, convert_part_T); + return 1; } #endif /* SWIFT_COOLING_NONE_IO_H */ diff --git a/src/engine.c b/src/engine.c index 73b7d9b64e744e08e19145a574a3a2b896ab3995..841a92638b34dba3dce54576ea22a44bb346b935 100644 --- a/src/engine.c +++ b/src/engine.c @@ -83,7 +83,6 @@ #include "serial_io.h" #include "single_io.h" #include "sort_part.h" -#include "sourceterms.h" #include "stars_io.h" #include "statistics.h" #include "timers.h" @@ -110,7 +109,6 @@ const char *engine_policy_names[] = {"none", "drift everything", "reconstruct multi-poles", "cooling", - "sourceterms", "stars", "structure finding", "star formation", @@ -1925,8 +1923,8 @@ int engine_estimate_nr_tasks(struct engine *e) { /* Cooling task + extra space */ n1 += 2; } - if (e->policy & engine_policy_sourceterms) { - n1 += 2; + if (e->policy & engine_policy_star_formation) { + n1 += 1; } if (e->policy & engine_policy_stars) { /* 2 self (density, feedback), 1 sort, 26/2 density pairs @@ -2016,9 +2014,10 @@ void engine_rebuild(struct engine *e, int repartitioned, const ticks tic2 = getticks(); /* Update the global counters of particles */ - long long num_particles[3] = {(long long)e->s->nr_parts, - (long long)e->s->nr_gparts, - (long long)e->s->nr_sparts}; + long long num_particles[3] = { + (long long)(e->s->nr_parts - e->s->nr_extra_parts), + (long long)(e->s->nr_gparts - e->s->nr_extra_gparts), + (long long)(e->s->nr_sparts - e->s->nr_extra_sparts)}; #ifdef WITH_MPI MPI_Allreduce(MPI_IN_PLACE, num_particles, 3, MPI_LONG_LONG, MPI_SUM, MPI_COMM_WORLD); @@ -2588,8 +2587,7 @@ void engine_skip_force_and_kick(struct engine *e) { t->type == task_type_timestep || t->subtype == task_subtype_force || t->subtype == task_subtype_grav || t->type == task_type_end_force || t->type == task_type_grav_long_range || t->type == task_type_grav_mm || - t->type == task_type_grav_down || t->type == task_type_cooling || - t->type == task_type_sourceterms) + t->type == task_type_grav_down || t->type == task_type_cooling) t->skip = 1; } @@ -2815,6 +2813,10 @@ void engine_init_particles(struct engine *e, int flag_entropy_ICs, double *prev_x = s->parts[0].x; long long *prev_id = &s->parts[0].id; for (size_t k = 1; k < s->nr_parts; k++) { + + /* Ignore fake buffer particles for on-the-fly creation */ + if (s->parts[k].time_bin == time_bin_not_created) continue; + if (prev_x[0] == s->parts[k].x[0] && prev_x[1] == s->parts[k].x[1] && prev_x[2] == s->parts[k].x[2]) { if (e->verbose) @@ -2837,6 +2839,10 @@ void engine_init_particles(struct engine *e, int flag_entropy_ICs, int failed = 0; double *prev_x = s->gparts[0].x; for (size_t k = 1; k < s->nr_gparts; k++) { + + /* Ignore fake buffer particles for on-the-fly creation */ + if (s->gparts[k].time_bin == time_bin_not_created) continue; + if (prev_x[0] == s->gparts[k].x[0] && prev_x[1] == s->gparts[k].x[1] && prev_x[2] == s->gparts[k].x[2]) { if (e->verbose) @@ -3776,8 +3782,8 @@ void engine_split(struct engine *e, struct partition *initial_partition) { /* Re-allocate the local parts. */ if (e->verbose) message("Re-allocating parts array from %zu to %zu.", s->size_parts, - (size_t)(s->nr_parts * 1.2)); - s->size_parts = s->nr_parts * 1.2; + (size_t)(s->nr_parts * engine_redistribute_alloc_margin)); + s->size_parts = s->nr_parts * engine_redistribute_alloc_margin; struct part *parts_new = NULL; struct xpart *xparts_new = NULL; if (posix_memalign((void **)&parts_new, part_align, @@ -3801,8 +3807,8 @@ void engine_split(struct engine *e, struct partition *initial_partition) { /* Re-allocate the local sparts. */ if (e->verbose) message("Re-allocating sparts array from %zu to %zu.", s->size_sparts, - (size_t)(s->nr_sparts * 1.2)); - s->size_sparts = s->nr_sparts * 1.2; + (size_t)(s->nr_sparts * engine_redistribute_alloc_margin)); + s->size_sparts = s->nr_sparts * engine_redistribute_alloc_margin; struct spart *sparts_new = NULL; if (posix_memalign((void **)&sparts_new, spart_align, sizeof(struct spart) * s->size_sparts) != 0) @@ -3819,8 +3825,8 @@ void engine_split(struct engine *e, struct partition *initial_partition) { /* Re-allocate the local gparts. */ if (e->verbose) message("Re-allocating gparts array from %zu to %zu.", s->size_gparts, - (size_t)(s->nr_gparts * 1.2)); - s->size_gparts = s->nr_gparts * 1.2; + (size_t)(s->nr_gparts * engine_redistribute_alloc_margin)); + s->size_gparts = s->nr_gparts * engine_redistribute_alloc_margin; struct gpart *gparts_new = NULL; if (posix_memalign((void **)&gparts_new, gpart_align, sizeof(struct gpart) * s->size_gparts) != 0) @@ -4034,7 +4040,6 @@ void engine_unpin(void) { * @param potential The properties of the external potential. * @param cooling_func The properties of the cooling function. * @param chemistry The chemistry information. - * @param sourceterms The properties of the source terms function. */ void engine_init(struct engine *e, struct space *s, struct swift_params *params, long long Ngas, long long Ngparts, long long Nstars, @@ -4046,8 +4051,7 @@ void engine_init(struct engine *e, struct space *s, struct swift_params *params, struct pm_mesh *mesh, const struct external_potential *potential, struct cooling_function_data *cooling_func, - const struct chemistry_global_data *chemistry, - struct sourceterms *sourceterms) { + const struct chemistry_global_data *chemistry) { /* Clean-up everything */ bzero(e, sizeof(struct engine)); @@ -4110,7 +4114,6 @@ void engine_init(struct engine *e, struct space *s, struct swift_params *params, e->external_potential = potential; e->cooling_func = cooling_func; e->chemistry = chemistry; - e->sourceterms = sourceterms; e->parameter_file = params; e->cell_loc = NULL; #ifdef WITH_MPI @@ -4780,6 +4783,7 @@ void engine_print_policy(struct engine *e) { * @param e The #engine. */ void engine_compute_next_snapshot_time(struct engine *e) { + /* Do outputlist file case */ if (e->output_list_snapshots) { output_list_read_next_time(e->output_list_snapshots, e, "snapshots", @@ -4800,6 +4804,8 @@ void engine_compute_next_snapshot_time(struct engine *e) { time = e->a_first_snapshot; else time = e->time_first_snapshot; + + int found_snapshot_time = 0; while (time < time_end) { /* Output time on the integer timeline */ @@ -4809,7 +4815,10 @@ void engine_compute_next_snapshot_time(struct engine *e) { e->ti_next_snapshot = (time - e->time_begin) / e->time_base; /* Found it? */ - if (e->ti_next_snapshot > e->ti_current) break; + if (e->ti_next_snapshot > e->ti_current) { + found_snapshot_time = 1; + break; + } if (e->policy & engine_policy_cosmology) time *= e->delta_time_snapshot; @@ -4818,7 +4827,7 @@ void engine_compute_next_snapshot_time(struct engine *e) { } /* Deal with last snapshot */ - if (e->ti_next_snapshot >= max_nr_timesteps) { + if (!found_snapshot_time) { e->ti_next_snapshot = -1; if (e->verbose) message("No further output time."); } else { @@ -4864,6 +4873,8 @@ void engine_compute_next_statistics_time(struct engine *e) { time = e->a_first_statistics; else time = e->time_first_statistics; + + int found_stats_time = 0; while (time < time_end) { /* Output time on the integer timeline */ @@ -4873,7 +4884,10 @@ void engine_compute_next_statistics_time(struct engine *e) { e->ti_next_stats = (time - e->time_begin) / e->time_base; /* Found it? */ - if (e->ti_next_stats > e->ti_current) break; + if (e->ti_next_stats > e->ti_current) { + found_stats_time = 1; + break; + } if (e->policy & engine_policy_cosmology) time *= e->delta_time_statistics; @@ -4882,7 +4896,7 @@ void engine_compute_next_statistics_time(struct engine *e) { } /* Deal with last statistics */ - if (e->ti_next_stats >= max_nr_timesteps) { + if (!found_stats_time) { e->ti_next_stats = -1; if (e->verbose) message("No further output time."); } else { @@ -4929,6 +4943,8 @@ void engine_compute_next_stf_time(struct engine *e) { time = e->a_first_stf_output; else time = e->time_first_stf_output; + + int found_stf_time = 0; while (time < time_end) { /* Output time on the integer timeline */ @@ -4938,7 +4954,10 @@ void engine_compute_next_stf_time(struct engine *e) { e->ti_next_stf = (time - e->time_begin) / e->time_base; /* Found it? */ - if (e->ti_next_stf > e->ti_current) break; + if (e->ti_next_stf > e->ti_current) { + found_stf_time = 1; + break; + } if (e->policy & engine_policy_cosmology) time *= e->delta_time_stf; @@ -4947,7 +4966,7 @@ void engine_compute_next_stf_time(struct engine *e) { } /* Deal with last snapshot */ - if (e->ti_next_stf >= max_nr_timesteps) { + if (!found_stf_time) { e->ti_next_stf = -1; if (e->verbose) message("No further output time."); } else { @@ -5042,9 +5061,11 @@ void engine_recompute_displacement_constraint(struct engine *e) { #ifdef SWIFT_DEBUG_CHECKS /* Check that the minimal mass collection worked */ float min_part_mass_check = FLT_MAX; - for (size_t i = 0; i < e->s->nr_parts; ++i) + for (size_t i = 0; i < e->s->nr_parts; ++i) { + if (e->s->parts[i].time_bin >= num_time_bins) continue; min_part_mass_check = min(min_part_mass_check, hydro_get_mass(&e->s->parts[i])); + } if (min_part_mass_check != min_mass[swift_type_gas]) error("Error collecting minimal mass of gas particles."); #endif @@ -5204,7 +5225,6 @@ void engine_struct_dump(struct engine *e, FILE *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); if (e->output_list_snapshots) output_list_struct_dump(e->output_list_snapshots, stream); @@ -5301,11 +5321,6 @@ void engine_struct_restore(struct engine *e, FILE *stream) { chemistry_struct_restore(chemistry, stream); e->chemistry = chemistry; - struct sourceterms *sourceterms = - (struct sourceterms *)malloc(sizeof(struct sourceterms)); - sourceterms_struct_restore(sourceterms, stream); - e->sourceterms = sourceterms; - struct swift_params *parameter_file = (struct swift_params *)malloc(sizeof(struct swift_params)); parser_struct_restore(parameter_file, stream); diff --git a/src/engine.h b/src/engine.h index 9c39ea15a85d19cf26dfd94a9c42897251c6b42a..d7d916c1bc25fc0d2cbac26c95de406accec5a67 100644 --- a/src/engine.h +++ b/src/engine.h @@ -46,7 +46,6 @@ #include "potential.h" #include "runner.h" #include "scheduler.h" -#include "sourceterms_struct.h" #include "space.h" #include "task.h" #include "units.h" @@ -71,13 +70,12 @@ enum engine_policy { engine_policy_drift_all = (1 << 11), engine_policy_reconstruct_mpoles = (1 << 12), engine_policy_cooling = (1 << 13), - engine_policy_sourceterms = (1 << 14), - engine_policy_stars = (1 << 15), - engine_policy_structure_finding = (1 << 16), - engine_policy_star_formation = (1 << 17), - engine_policy_feedback = (1 << 18) + engine_policy_stars = (1 << 14), + engine_policy_structure_finding = (1 << 15), + engine_policy_star_formation = (1 << 16), + engine_policy_feedback = (1 << 17) }; -#define engine_maxpolicy 19 +#define engine_maxpolicy 18 extern const char *engine_policy_names[engine_maxpolicy + 1]; /** @@ -360,9 +358,6 @@ struct engine { /* Properties of the chemistry model */ const struct chemistry_global_data *chemistry; - /* Properties of source terms */ - struct sourceterms *sourceterms; - /* The (parsed) parameter file */ struct swift_params *parameter_file; @@ -417,8 +412,7 @@ void engine_init(struct engine *e, struct space *s, struct swift_params *params, struct pm_mesh *mesh, const struct external_potential *potential, struct cooling_function_data *cooling_func, - const struct chemistry_global_data *chemistry, - struct sourceterms *sourceterms); + const struct chemistry_global_data *chemistry); void engine_config(int restart, struct engine *e, struct swift_params *params, int nr_nodes, int nodeID, int nr_threads, int with_aff, int verbose, const char *restart_file); diff --git a/src/engine_maketasks.c b/src/engine_maketasks.c index 68841aa5999441e6a2621f867038a44e9f52794c..2c9fe3cb70cfcf118cdb9d1f6fc36a6f854fd7b5 100644 --- a/src/engine_maketasks.c +++ b/src/engine_maketasks.c @@ -666,7 +666,6 @@ void engine_add_ghosts(struct engine *e, struct cell *c, struct task *ghost_in, void engine_make_hierarchical_tasks_hydro(struct engine *e, struct cell *c) { struct scheduler *s = &e->sched; - const int is_with_sourceterms = (e->policy & engine_policy_sourceterms); /* Are we in a super-cell ? */ if (c->hydro.super == c) { @@ -696,12 +695,6 @@ void engine_make_hierarchical_tasks_hydro(struct engine *e, struct cell *c) { c->hydro.extra_ghost = scheduler_addtask( s, task_type_extra_ghost, task_subtype_none, 0, 0, c, NULL); #endif - - /* add source terms */ - if (is_with_sourceterms) { - c->sourceterms = scheduler_addtask(s, task_type_sourceterms, - task_subtype_none, 0, 0, c, NULL); - } } } else { /* We are above the super-cell so need to go deeper */ diff --git a/src/exp10.h b/src/exp10.h new file mode 100644 index 0000000000000000000000000000000000000000..48a950574693f81a9556b084d66278f348189a73 --- /dev/null +++ b/src/exp10.h @@ -0,0 +1,63 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2018 Matthieu Schaller (matthieu.schaller@durham.ac.uk) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ +#ifndef SWIFT_EXP10_H +#define SWIFT_EXP10_H + +/* Config parameters. */ +#include "../config.h" + +/* Some standard headers. */ +#include <math.h> + +/* Local headers. */ +#include "inline.h" + +#ifndef __GNUC__ + +/** + * @brief Raises 10 to the power of the argument. + * + * This function is only used as a replacement for compilers that do + * not implement GNU extensions to the C language. + * + * @param x The input value. + */ +__attribute__((always_inline, const)) INLINE static double exp10( + const double x) { + + return exp(x * M_LN10); +} + +/** + * @brief Raises 10 to the power of the argument. + * + * This function is only used as a replacement for compilers that do + * not implement GNU extensions to the C language. + * + * @param x The input value. + */ +__attribute__((always_inline, const)) INLINE static float exp10f( + const float x) { + + return expf(x * (float)M_LN10); +} + +#endif /* __GNUC__ */ + +#endif /* SWIFT_EXP10_H */ diff --git a/src/hydro/Gadget2/hydro_iact.h b/src/hydro/Gadget2/hydro_iact.h index c87a4f91d45167b76ee88a9a46329f3785165884..a3c5e21dbdf8df60b25b01c0326c33c3a10d1bce 100644 --- a/src/hydro/Gadget2/hydro_iact.h +++ b/src/hydro/Gadget2/hydro_iact.h @@ -56,9 +56,9 @@ __attribute__((always_inline)) INLINE static void runner_iact_density( float dv[3], curlvr[3]; #ifdef SWIFT_DEBUG_CHECKS - if (pi->time_bin == time_bin_inhibited) + if (pi->time_bin >= time_bin_inhibited) error("Inhibited pi in interaction function!"); - if (pj->time_bin == time_bin_inhibited) + if (pj->time_bin >= time_bin_inhibited) error("Inhibited pj in interaction function!"); #endif @@ -153,9 +153,9 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_density( float dv[3], curlvr[3]; #ifdef SWIFT_DEBUG_CHECKS - if (pi->time_bin == time_bin_inhibited) + if (pi->time_bin >= time_bin_inhibited) error("Inhibited pi in interaction function!"); - if (pj->time_bin == time_bin_inhibited) + if (pj->time_bin >= time_bin_inhibited) error("Inhibited pj in interaction function!"); #endif @@ -451,9 +451,9 @@ __attribute__((always_inline)) INLINE static void runner_iact_force( float wi, wj, wi_dx, wj_dx; #ifdef SWIFT_DEBUG_CHECKS - if (pi->time_bin == time_bin_inhibited) + if (pi->time_bin >= time_bin_inhibited) error("Inhibited pi in interaction function!"); - if (pj->time_bin == time_bin_inhibited) + if (pj->time_bin >= time_bin_inhibited) error("Inhibited pj in interaction function!"); #endif @@ -580,9 +580,9 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force( float wi, wj, wi_dx, wj_dx; #ifdef SWIFT_DEBUG_CHECKS - if (pi->time_bin == time_bin_inhibited) + if (pi->time_bin >= time_bin_inhibited) error("Inhibited pi in interaction function!"); - if (pj->time_bin == time_bin_inhibited) + if (pj->time_bin >= time_bin_inhibited) error("Inhibited pj in interaction function!"); #endif diff --git a/src/hydro/GizmoMFM/hydro.h b/src/hydro/GizmoMFM/hydro.h index 8e466daabb59482a1c2ebbaf80af30c64c4abdfe..1ce17d76f1814ec9b8d02ccbb73006748545e1e7 100644 --- a/src/hydro/GizmoMFM/hydro.h +++ b/src/hydro/GizmoMFM/hydro.h @@ -722,10 +722,12 @@ hydro_get_comoving_internal_energy(const struct part* restrict p) { * @brief Returns the physical internal energy of a particle * * @param p The particle of interest. + * @param xp The extended data of 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 xpart* restrict xp, const struct cosmology* cosmo) { return cosmo->a_factor_internal_energy * @@ -778,10 +780,12 @@ __attribute__((always_inline)) INLINE static float hydro_get_comoving_entropy( * @brief Returns the physical internal energy of a particle * * @param p The particle of interest. + * @param xp The extended data of 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) { + const struct part* restrict p, const struct xpart* restrict xp, + const struct cosmology* cosmo) { /* Note: no cosmological conversion required here with our choice of * coordinates. */ diff --git a/src/hydro/GizmoMFV/hydro.h b/src/hydro/GizmoMFV/hydro.h index 98a70aefed098243bbf2dfe08e752ee48a838d3e..77db9e3a01f1cfe6a4d3211726cfd9fe30e87cf4 100644 --- a/src/hydro/GizmoMFV/hydro.h +++ b/src/hydro/GizmoMFV/hydro.h @@ -808,10 +808,12 @@ hydro_get_comoving_internal_energy(const struct part* restrict p) { * @brief Returns the physical internal energy of a particle * * @param p The particle of interest. + * @param xp The extended data of 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 xpart* restrict xp, const struct cosmology* cosmo) { return cosmo->a_factor_internal_energy * @@ -828,7 +830,7 @@ __attribute__((always_inline)) INLINE static float hydro_get_drifted_physical_internal_energy(const struct part* restrict p, const struct cosmology* cosmo) { - return hydro_get_physical_internal_energy(p, cosmo); + return hydro_get_physical_internal_energy(p, /*xp=*/NULL, cosmo); } /** @@ -850,10 +852,12 @@ __attribute__((always_inline)) INLINE static float hydro_get_comoving_entropy( * @brief Returns the physical internal energy of a particle * * @param p The particle of interest. + * @param xp The extended data of 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) { + const struct part* restrict p, const struct xpart* restrict xp, + const struct cosmology* cosmo) { /* Note: no cosmological conversion required here with our choice of * coordinates. */ diff --git a/src/hydro/Minimal/hydro_iact.h b/src/hydro/Minimal/hydro_iact.h index e060cb3562f1b319c64d6f6523b18858662312e7..b29f44588c2e13bb5b7c5c9cd5297205557c3fc9 100644 --- a/src/hydro/Minimal/hydro_iact.h +++ b/src/hydro/Minimal/hydro_iact.h @@ -54,9 +54,9 @@ __attribute__((always_inline)) INLINE static void runner_iact_density( float wi, wj, wi_dx, wj_dx; #ifdef SWIFT_DEBUG_CHECKS - if (pi->time_bin == time_bin_inhibited) + if (pi->time_bin >= time_bin_inhibited) error("Inhibited pi in interaction function!"); - if (pj->time_bin == time_bin_inhibited) + if (pj->time_bin >= time_bin_inhibited) error("Inhibited pj in interaction function!"); #endif @@ -135,9 +135,9 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_density( float wi, wi_dx; #ifdef SWIFT_DEBUG_CHECKS - if (pi->time_bin == time_bin_inhibited) + if (pi->time_bin >= time_bin_inhibited) error("Inhibited pi in interaction function!"); - if (pj->time_bin == time_bin_inhibited) + if (pj->time_bin >= time_bin_inhibited) error("Inhibited pj in interaction function!"); #endif @@ -196,9 +196,9 @@ __attribute__((always_inline)) INLINE static void runner_iact_force( struct part *restrict pj, float a, float H) { #ifdef SWIFT_DEBUG_CHECKS - if (pi->time_bin == time_bin_inhibited) + if (pi->time_bin >= time_bin_inhibited) error("Inhibited pi in interaction function!"); - if (pj->time_bin == time_bin_inhibited) + if (pj->time_bin >= time_bin_inhibited) error("Inhibited pj in interaction function!"); #endif @@ -323,9 +323,9 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force( const struct part *restrict pj, float a, float H) { #ifdef SWIFT_DEBUG_CHECKS - if (pi->time_bin == time_bin_inhibited) + if (pi->time_bin >= time_bin_inhibited) error("Inhibited pi in interaction function!"); - if (pj->time_bin == time_bin_inhibited) + if (pj->time_bin >= time_bin_inhibited) error("Inhibited pj in interaction function!"); #endif diff --git a/src/hydro_properties.c b/src/hydro_properties.c index 2b1cd42055c66768e943241c75298e53e0bf75a8..85f88d418bd46354f7a1cd3dd89b0e77b556b7d9 100644 --- a/src/hydro_properties.c +++ b/src/hydro_properties.c @@ -119,6 +119,12 @@ void hydro_props_init(struct hydro_props *p, p->hydrogen_mass_fraction = parser_get_opt_param_double( params, "SPH:H_mass_fraction", default_H_fraction); + /* Mean molecular mass for neutral gas */ + p->mu_neutral = 4. / (1. + 3. * p->hydrogen_mass_fraction); + + /* Mean molecular mass for fully ionised gas */ + p->mu_ionised = 4. / (8. - 5. * (1. - p->hydrogen_mass_fraction)); + /* Read the artificial viscosity parameters from the file, if they exist */ p->viscosity.alpha = parser_get_opt_param_float( params, "SPH:viscosity_alpha", hydro_props_default_viscosity_alpha); diff --git a/src/hydro_properties.h b/src/hydro_properties.h index b45b93192e7db7b1bdca49557f8563322f09aae9..5ee6a22d2cf1c22f99e50a9254ef323d333d2a10 100644 --- a/src/hydro_properties.h +++ b/src/hydro_properties.h @@ -84,6 +84,12 @@ struct hydro_props { /*! Temperature of the neutral to ionized transition of Hydrogen */ float hydrogen_ionization_temperature; + /*! Mean molecular weight below hydrogen ionization temperature */ + float mu_neutral; + + /*! Mean molecular weight above hydrogen ionization temperature */ + float mu_ionised; + /*! Artificial viscosity parameters */ struct { /*! For the fixed, simple case. Also used to set the initial AV diff --git a/src/parallel_io.c b/src/parallel_io.c index febbb4a7db6796fd751cb1eacc174a42936d19a2..1c91b087169420f218b228b8ccdf6deca9925297 100644 --- a/src/parallel_io.c +++ b/src/parallel_io.c @@ -1136,6 +1136,8 @@ void prepare_file(struct engine* e, const char* baseName, long long N_total[6], case swift_type_gas: hydro_write_particles(parts, xparts, list, &num_fields); num_fields += chemistry_write_particles(parts, list + num_fields); + num_fields += cooling_write_particles(parts, xparts, list + num_fields, + e->cooling_func); break; case swift_type_dark_matter: @@ -1219,9 +1221,12 @@ void write_output_parallel(struct engine* e, const char* baseName, // const size_t Ndm = Ntot > 0 ? Ntot - Nbaryons : 0; /* Number of particles that we will write */ - const size_t Ntot_written = e->s->nr_gparts - e->s->nr_inhibited_sparts; - const size_t Ngas_written = e->s->nr_parts - e->s->nr_inhibited_parts; - const size_t Nstars_written = e->s->nr_sparts - e->s->nr_inhibited_gparts; + const size_t Ntot_written = + e->s->nr_gparts - e->s->nr_inhibited_gparts - e->s->nr_extra_gparts; + const size_t Ngas_written = + e->s->nr_parts - e->s->nr_inhibited_parts - e->s->nr_extra_parts; + const size_t Nstars_written = + e->s->nr_sparts - e->s->nr_inhibited_sparts - e->s->nr_extra_sparts; const size_t Nbaryons_written = Ngas_written + Nstars_written; const size_t Ndm_written = Ntot_written > 0 ? Ntot_written - Nbaryons_written : 0; @@ -1394,8 +1399,8 @@ void write_output_parallel(struct engine* e, const char* baseName, Nparticles = Ngas; hydro_write_particles(parts, xparts, list, &num_fields); num_fields += chemistry_write_particles(parts, list + num_fields); - num_fields += cooling_write_particles(xparts, list + num_fields, - e->cooling_func); + num_fields += cooling_write_particles( + parts, xparts, list + num_fields, e->cooling_func); } else { /* Ok, we need to fish out the particles we want */ @@ -1418,8 +1423,9 @@ void write_output_parallel(struct engine* e, const char* baseName, &num_fields); num_fields += chemistry_write_particles(parts_written, list + num_fields); - num_fields += cooling_write_particles( - xparts_written, list + num_fields, e->cooling_func); + num_fields += + cooling_write_particles(parts_written, xparts_written, + list + num_fields, e->cooling_func); } } break; diff --git a/src/part.c b/src/part.c index 3a626e652cf28f0376cadc1d9a40ab85b752e6c1..ec3627d728f69f469cc7d75eb2beb9ae39ed107e 100644 --- a/src/part.c +++ b/src/part.c @@ -139,8 +139,9 @@ void part_verify_links(struct part *parts, struct gpart *gparts, for (size_t k = 0; k < nr_gparts; ++k) { - /* We have a DM particle */ - if (gparts[k].type == swift_type_dark_matter) { + /* We have a real DM particle */ + if (gparts[k].type == swift_type_dark_matter && + gparts[k].time_bin != time_bin_not_created) { /* Check that it's not linked */ if (gparts[k].id_or_neg_offset <= 0) diff --git a/src/runner.c b/src/runner.c index f14f8d8bc2721d0edfaca542b68af645bd5ac1a0..018e35c582efb30d4a0f090b478f8a2adb091d39 100644 --- a/src/runner.c +++ b/src/runner.c @@ -58,7 +58,6 @@ #include "runner_doiact_vec.h" #include "scheduler.h" #include "sort_part.h" -#include "sourceterms.h" #include "space.h" #include "space_getsid.h" #include "stars.h" @@ -107,42 +106,6 @@ #include "runner_doiact_stars.h" #undef FUNCTION -/** - * @brief Perform source terms - * - * @param r runner task - * @param c cell - * @param timer 1 if the time is to be recorded. - */ -void runner_do_sourceterms(struct runner *r, struct cell *c, int timer) { - const int count = c->hydro.count; - const double cell_min[3] = {c->loc[0], c->loc[1], c->loc[2]}; - const double cell_width[3] = {c->width[0], c->width[1], c->width[2]}; - struct sourceterms *sourceterms = r->e->sourceterms; - const int dimen = 3; - - TIMER_TIC; - - /* Recurse? */ - if (c->split) { - for (int k = 0; k < 8; k++) - if (c->progeny[k] != NULL) runner_do_sourceterms(r, c->progeny[k], 0); - } else { - - if (count > 0) { - - /* do sourceterms in this cell? */ - const int incell = - sourceterms_test_cell(cell_min, cell_width, sourceterms, dimen); - if (incell == 1) { - sourceterms_apply(r, sourceterms, c); - } - } - } - - if (timer) TIMER_TOC(timer_dosource); -} - /** * @brief Intermediate task after the density to check that the smoothing * lengths are correct. @@ -499,7 +462,7 @@ void runner_do_cooling(struct runner *r, struct cell *c, int timer) { */ void runner_do_star_formation(struct runner *r, struct cell *c, int timer) { - const struct engine *e = r->e; + struct engine *e = r->e; const struct cosmology *cosmo = e->cosmology; const int count = c->hydro.count; struct part *restrict parts = c->hydro.parts; @@ -529,9 +492,16 @@ void runner_do_star_formation(struct runner *r, struct cell *c, int timer) { // MATTHIEU: Temporary star-formation law // Do not use this at home. - if (rho > 1.5e7 && e->step > 2) { + if (rho > 1.7e7 && e->step > 2) { message("Removing particle id=%lld rho=%e", p->id, rho); - cell_convert_part_to_gpart(e, c, p, xp); + + struct spart *sp = cell_convert_part_to_spart(e, c, p, xp); + + /* Did we run out of fresh particles? */ + if (sp == NULL) continue; + + /* Set everything to a valid state */ + stars_init_spart(sp); } } } @@ -623,9 +593,6 @@ void runner_do_sort_ascending(struct entry *sort, int N) { * @brief Recursively checks that the flags are consistent in a cell hierarchy. * * Debugging function. Exists in two flavours: hydro & stars. - * - * @param c The #cell to check. - * @param flags The sorting flags to check. */ #define RUNNER_CHECK_SORTS(TYPE) \ void runner_check_sorts_##TYPE(struct cell *c, int flags) { \ @@ -2913,9 +2880,6 @@ void *runner_main(void *data) { case task_type_star_formation: runner_do_star_formation(r, t->ci, 1); break; - case task_type_sourceterms: - runner_do_sourceterms(r, t->ci, 1); - break; default: error("Unknown/invalid task type (%d).", t->type); } diff --git a/src/serial_io.c b/src/serial_io.c index 059318df180e0d06e446f9d3f839b16439dd1b34..8c3076461b9463f9cea373e528cd9fb390406981 100644 --- a/src/serial_io.c +++ b/src/serial_io.c @@ -792,9 +792,12 @@ void write_output_serial(struct engine* e, const char* baseName, // const size_t Ndm = Ntot > 0 ? Ntot - Nbaryons : 0; /* Number of particles that we will write */ - const size_t Ntot_written = e->s->nr_gparts - e->s->nr_inhibited_sparts; - const size_t Ngas_written = e->s->nr_parts - e->s->nr_inhibited_parts; - const size_t Nstars_written = e->s->nr_sparts - e->s->nr_inhibited_gparts; + const size_t Ntot_written = + e->s->nr_gparts - e->s->nr_inhibited_gparts - e->s->nr_extra_gparts; + const size_t Ngas_written = + e->s->nr_parts - e->s->nr_inhibited_parts - e->s->nr_extra_parts; + const size_t Nstars_written = + e->s->nr_sparts - e->s->nr_inhibited_sparts - e->s->nr_extra_sparts; const size_t Nbaryons_written = Ngas_written + Nstars_written; const size_t Ndm_written = Ntot_written > 0 ? Ntot_written - Nbaryons_written : 0; @@ -1071,8 +1074,8 @@ void write_output_serial(struct engine* e, const char* baseName, Nparticles = Ngas; hydro_write_particles(parts, xparts, list, &num_fields); num_fields += chemistry_write_particles(parts, list + num_fields); - num_fields += cooling_write_particles(xparts, list + num_fields, - e->cooling_func); + num_fields += cooling_write_particles( + parts, xparts, list + num_fields, e->cooling_func); } else { /* Ok, we need to fish out the particles we want */ @@ -1095,8 +1098,9 @@ void write_output_serial(struct engine* e, const char* baseName, &num_fields); num_fields += chemistry_write_particles(parts_written, list + num_fields); - num_fields += cooling_write_particles( - xparts_written, list + num_fields, e->cooling_func); + num_fields += + cooling_write_particles(parts_written, xparts_written, + list + num_fields, e->cooling_func); } } break; diff --git a/src/single_io.c b/src/single_io.c index 833c4a80cb2f43455d34ad3cd694255b7b19038c..50f60b0a18a14f9d8ffbbbc261d38e80937d5fad 100644 --- a/src/single_io.c +++ b/src/single_io.c @@ -654,9 +654,12 @@ void write_output_single(struct engine* e, const char* baseName, // const size_t Ndm = Ntot > 0 ? Ntot - Nbaryons : 0; /* Number of particles that we will write */ - const size_t Ntot_written = e->s->nr_gparts - e->s->nr_inhibited_sparts; - const size_t Ngas_written = e->s->nr_parts - e->s->nr_inhibited_parts; - const size_t Nstars_written = e->s->nr_sparts - e->s->nr_inhibited_gparts; + const size_t Ntot_written = + e->s->nr_gparts - e->s->nr_inhibited_gparts - e->s->nr_extra_gparts; + const size_t Ngas_written = + e->s->nr_parts - e->s->nr_inhibited_parts - e->s->nr_extra_parts; + const size_t Nstars_written = + e->s->nr_sparts - e->s->nr_inhibited_sparts - e->s->nr_extra_sparts; const size_t Nbaryons_written = Ngas_written + Nstars_written; const size_t Ndm_written = Ntot_written > 0 ? Ntot_written - Nbaryons_written : 0; @@ -890,8 +893,8 @@ void write_output_single(struct engine* e, const char* baseName, N = Ngas; hydro_write_particles(parts, xparts, list, &num_fields); num_fields += chemistry_write_particles(parts, list + num_fields); - num_fields += cooling_write_particles(xparts, list + num_fields, - e->cooling_func); + num_fields += cooling_write_particles( + parts, xparts, list + num_fields, e->cooling_func); } else { /* Ok, we need to fish out the particles we want */ @@ -914,8 +917,9 @@ void write_output_single(struct engine* e, const char* baseName, &num_fields); num_fields += chemistry_write_particles(parts_written, list + num_fields); - num_fields += cooling_write_particles( - xparts_written, list + num_fields, e->cooling_func); + num_fields += + cooling_write_particles(parts_written, xparts_written, + list + num_fields, e->cooling_func); } } break; diff --git a/src/sourceterms.c b/src/sourceterms.c deleted file mode 100644 index 993045e61503e4e78b855816921bc057706b76d1..0000000000000000000000000000000000000000 --- a/src/sourceterms.c +++ /dev/null @@ -1,85 +0,0 @@ -/******************************************************************************* - * This file is part of SWIFT. - * Copyright (c) 2016 Tom Theuns (tom.theuns@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/>. - * - ******************************************************************************/ - -/* Config parameters. */ -#include "../config.h" - -/* Local includes. */ -#include "const.h" -#include "hydro.h" -#include "parser.h" -#include "units.h" - -/* This object's header. */ -#include "sourceterms.h" - -/** - * @brief Initialises the sourceterms - * - * @param parameter_file The parsed parameter file - * @param us The current internal system of units - * @param source the structure that has all the source term properties - */ -void sourceterms_init(struct swift_params *parameter_file, - struct unit_system *us, struct sourceterms *source) { -#ifdef SOURCETERMS_SN_FEEDBACK - supernova_init(parameter_file, us, source); -#endif /* SOURCETERMS_SN_FEEDBACK */ -}; - -/** - * @brief Prints the properties of the source terms to stdout - * @param source the structure that has all the source term properties - */ -void sourceterms_print(struct sourceterms *source) { -#ifdef SOURCETERMS_NONE - error(" no sourceterms defined yet you ran with -F"); -#ifdef SOURCETERMS_SN_FEEDBACK -#error "can't have sourceterms when defined SOURCETERMS_NONE" -#endif -#endif -#ifdef SOURCETERMS_SN_FEEDBACK - supernova_print(source); -#endif /* SOURCETERMS_SN_FEEDBACK */ -}; - -/** - * @brief Write a sourceterms struct to the given FILE as a stream of bytes. - * - * @param sourceterms the struct - * @param stream the file stream - */ -void sourceterms_struct_dump(const struct sourceterms *sourceterms, - FILE *stream) { - restart_write_blocks((void *)sourceterms, sizeof(struct sourceterms), 1, - stream, "sourceterms", "sourceterms"); -} - -/** - * @brief Restore a sourceterms struct from the given FILE as a stream of - * bytes. - * - * @param sourceterms the struct - * @param stream the file stream - */ -void sourceterms_struct_restore(const struct sourceterms *sourceterms, - FILE *stream) { - restart_read_blocks((void *)sourceterms, sizeof(struct sourceterms), 1, - stream, NULL, "sourceterms"); -} diff --git a/src/sourceterms.h b/src/sourceterms.h deleted file mode 100644 index 407d2f19362531a3fd3537889593c484319919b5..0000000000000000000000000000000000000000 --- a/src/sourceterms.h +++ /dev/null @@ -1,78 +0,0 @@ -/******************************************************************************* - * This file is part of SWIFT. - * Coypright (c) 2015 Matthieu Schaller (matthieu.schaller@durham.ac.uk) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - ******************************************************************************/ -#ifndef SWIFT_SOURCETERMS_H -#define SWIFT_SOURCETERMS_H - -/** - * @file src/sourceterms.h - * @brief Branches between the different sourceterms functions. - */ - -#include "./const.h" -#include "runner.h" - -#ifdef SOURCETERMS_SN_FEEDBACK -#include "sourceterms/sn_feedback/sn_feedback_struct.h" -#endif - -/* So far only one model here */ -struct sourceterms { -#ifdef SOURCETERMS_SN_FEEDBACK - struct supernova_struct supernova; -#endif -}; -#ifdef SOURCETERMS_SN_FEEDBACK -#include "sourceterms/sn_feedback/sn_feedback.h" -#endif - -void sourceterms_init(struct swift_params* parameter_file, - struct unit_system* us, struct sourceterms* source); -void sourceterms_print(struct sourceterms* source); - -/* Dump/restore. */ -void sourceterms_struct_dump(const struct sourceterms* source, FILE* stream); -void sourceterms_struct_restore(const struct sourceterms* source, FILE* stream); - -/** - * @brief Routines related to source terms - * @param cell_min: corner of cell to test - * @param cell_width: width of cell to test - * @param sourceterms: properties of source terms to test - * @param dimen: dimensionality of the problem - * - * This routine tests whether a source term should be applied to this cell - * return: 1 if yes, return: 0 if no - */ - -__attribute__((always_inline)) INLINE static int sourceterms_test_cell( - const double cell_min[], const double cell_width[], - struct sourceterms* sourceterms, const int dimen) { -#ifdef SOURCETERMS_SN_FEEDBACK - return supernova_feedback_test_cell(cell_min, cell_width, sourceterms, dimen); -#endif - return 0; -}; - -__attribute__((always_inline)) INLINE static void sourceterms_apply( - struct runner* r, struct sourceterms* sourceterms, struct cell* c) { -#ifdef SOURCETERMS_SN_FEEDBACK - supernova_feedback_apply(r, sourceterms, c); -#endif -}; -#endif /* SWIFT_SOURCETERMS_H */ diff --git a/src/sourceterms/sn_feedback/sn_feedback.h b/src/sourceterms/sn_feedback/sn_feedback.h deleted file mode 100644 index 411673c37e82ff89d906425d1cadaa135c46a38d..0000000000000000000000000000000000000000 --- a/src/sourceterms/sn_feedback/sn_feedback.h +++ /dev/null @@ -1,192 +0,0 @@ -/******************************************************************************* - * This file is part of SWIFT. - * Copyright (c) 2016 Tom Theuns (tom.theuns@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_SN_FEEDBACK_H -#define SWIFT_SN_FEEDBACK_H -#include <float.h> -/* Config parameters. */ -#include "../config.h" - -#include "engine.h" -#include "equation_of_state.h" -#include "hydro.h" -#include "runner.h" -#include "timestep.h" - -/** - * @file src/sourceterms/sn_feedback.h - * - * @brief Routines related to sourceterms (supernova feedback): determine if - * feedback occurs in this cell - * - * @param cell_min: corner of cell to test - * @param cell_width: width of cell to test - * @param sourceterms: properties of source terms to test - * @param dimen: dimensionality of the problem - * - * This routine tests whether a source term should be applied to this cell - * return: 1 if yes, return: 0 if no - */ -__attribute__((always_inline)) INLINE static int supernova_feedback_test_cell( - const double cell_min[], const double cell_width[], - struct sourceterms* sourceterms, const int dimen) { - if (sourceterms->supernova.status == supernova_is_done) return 0; - - const double location[3] = {sourceterms->supernova.x, - sourceterms->supernova.y, - sourceterms->supernova.z}; - for (int i = 0; i < dimen; i++) { - if (cell_min[i] > location[i]) return 0; - if ((cell_min[i] + cell_width[i]) <= location[i]) return 0; - }; - return 1; -}; - -/** - * @file src/sourceterms/sn_feedback.h - * - * @brief Routines related to source terms (supernova feedback): perform - * feedback in this cell - * @param r: the runner - * @param sourceterms the structure describing the source terms properties - * @param c the cell to apply feedback to - * - * This routine heats an individual particle (p), increasing its thermal energy - * per unit mass - * by supernova energy / particle mass. - */ -__attribute__((always_inline)) INLINE static void supernova_feedback_apply( - struct runner* restrict r, struct sourceterms* restrict sourceterms, - struct cell* restrict c) { - - const int count = c->count; - struct part* restrict parts = c->parts; - struct xpart* restrict xparts = c->xparts; - const double timeBase = r->e->timeBase; - const int ti_current = r->e->ti_current; - - /* inject SN energy into the particle with highest id in this cell if it is - * active */ - int imax = 0; - struct part* restrict p_sn = NULL; - struct xpart* restrict xp_sn = NULL; - - for (int i = 0; i < count; i++) { - - /* Get a direct pointer on the part. */ - struct part* restrict p = &parts[i]; - if (p->id > imax) { - imax = p->id; - p_sn = p; - xp_sn = &xparts[i]; - } - } - - /* Is this part within the time step? */ - if (p_sn->ti_begin == ti_current) { - - /* Does this time step straddle the feedback injection time? */ - const float t_begin = p_sn->ti_begin * timeBase; - const float t_end = p_sn->ti_end * timeBase; - if (t_begin <= sourceterms->supernova.time && - t_end > sourceterms->supernova.time) { - - /* store old time step */ - const int dti_old = p_sn->ti_end - p_sn->ti_begin; - - /* add supernova feedback */ - const float u_old = hydro_get_internal_energy(p_sn, 0); - const float ent_old = hydro_get_entropy(p_sn, 0.0); - const float u_new = - u_old + sourceterms->supernova.energy / hydro_get_mass(p_sn); - hydro_set_internal_energy(p_sn, u_new); - const float u_set = hydro_get_internal_energy(p_sn, 0.0); - const float ent_set = hydro_get_entropy(p_sn, 0.0); - message( - " applied super nova, time = %e, location= %e %e %e velocity= %e %e " - "%e", - ti_current * timeBase, p_sn->x[0], p_sn->x[1], p_sn->x[2], p_sn->v[0], - p_sn->v[1], p_sn->v[2]); - message( - " injected SN energy in particle = %lld, increased energy from %e to " - "%e and is notw %e, entropy from %e to %e", - p_sn->id, u_old, u_new, u_set, ent_old, ent_set); - - /* label supernova as done */ - sourceterms->supernova.status = supernova_is_done; - - /* update timestep if new time step shorter than old time step */ - const int dti = get_part_timestep(p_sn, xp_sn, r->e); - if (dti < dti_old) { - p_sn->ti_end = p_sn->ti_begin + dti; - message(" changed timestep from %d to %d", dti_old, dti); - - /* apply simple time-step limiter on all particles in same cell: - */ - int i_limit = 0; - for (int i = 0; i < count; i++) { - struct part* restrict p = &parts[i]; - const int dti_old = p->ti_end - p->ti_begin; - if (dti_old > 2 * dti) { - i_limit++; - const int dti_new = 2 * dti; - p->ti_end = p->ti_begin + dti_new; - message(" old step = %d new step = %d", dti_old, dti_new); - } else - message(" old step = %d", dti_old); - } - message(" count= %d limited timestep of %d particles ", count, i_limit); - } /* end of limiter */ - error("end"); - } - } -}; - -/** - * @file src/sourceterms/sn_feedback.h - * - * @brief Routine to initialise supernova feedback - * @param parameterfile: the parse parmeter file - * @param us: the unit system in use - * @param sourceterms the structure describing the source terms properties - * - * This routine heats an individual particle (p), increasing its thermal energy - * per unit mass - * by supernova energy / particle mass. - */ - -__attribute__((always_inline)) INLINE static void supernova_init( - struct swift_params* parameter_file, struct unit_system* us, - struct sourceterms* source) { - source->supernova.time = parser_get_param_double(parameter_file, "SN:time"); - source->supernova.energy = - parser_get_param_double(parameter_file, "SN:energy"); - source->supernova.x = parser_get_param_double(parameter_file, "SN:x"); - source->supernova.y = parser_get_param_double(parameter_file, "SN:y"); - source->supernova.z = parser_get_param_double(parameter_file, "SN:z"); - source->supernova.status = supernova_is_not_done; -} -__attribute__((always_inline)) INLINE static void supernova_print( - struct sourceterms* source) { - message( - " Single SNe of energy= %e will explode at time= %e at location " - "(%e,%e,%e)", - source->supernova.energy, source->supernova.time, source->supernova.x, - source->supernova.y, source->supernova.z); -} -#endif /* SWIFT_SN_FEEDBACK_H */ diff --git a/src/sourceterms/sn_feedback/sn_feedback_struct.h b/src/sourceterms/sn_feedback/sn_feedback_struct.h deleted file mode 100644 index dd1842a6717c6c5a20352324cbe6b018c73e7b3e..0000000000000000000000000000000000000000 --- a/src/sourceterms/sn_feedback/sn_feedback_struct.h +++ /dev/null @@ -1,45 +0,0 @@ -/******************************************************************************* - * This file is part of SWIFT. - * Copyright (c) 2016 Tom Theuns (tom.theuns@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 src/sourceterms/sn_feedback_struct.h - * @brief Routines related to source terms (feedback) - * - * enumeration type that sets if supernova explosion is done (is_done) or still - * needs doing (is_not_done) - */ -#ifndef SWIFT_SN_FEEDBACK_STRUCT_H -#define SWIFT_SN_FEEDBACK_STRUCT_H -enum supernova_status { supernova_is_done, supernova_is_not_done }; - -/** - * @file src/sourceterms/sn_feedback_struct.h - * @brief Routines related to source terms (feedback) - * - * The structure that describes the source term (supernova feedback) - * It specifies the time, energy and location of the desired supernova - * explosion, and a status (supernova_is_done/supernova_is_not_done) - * that records the status of the supernova - */ -struct supernova_struct { - double time; - double energy; - double x, y, z; - enum supernova_status status; -}; -#endif /* SWIFT_SN_FEEDBACK_STRUCT_H */ diff --git a/src/sourceterms_struct.h b/src/sourceterms_struct.h deleted file mode 100644 index b3c38986db52d72df825fda97b36c985dff922b6..0000000000000000000000000000000000000000 --- a/src/sourceterms_struct.h +++ /dev/null @@ -1,26 +0,0 @@ -/******************************************************************************* - * This file is part of SWIFT. - * Coypright (c) 2015 Matthieu Schaller (matthieu.schaller@durham.ac.uk) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - ******************************************************************************/ -#ifndef SWIFT_SOURCETERMS_STRUCT_H -#define SWIFT_SOURCETERMS_STRUCT_H -#include "./const.h" -#ifdef SOURCETERMS_SN_FEEDBACK -#include "sourceterms/sn_feedback/sn_feedback_struct.h" -#endif - -#endif /* SWIFT_SOURCETERMS_STRUCT_H */ diff --git a/src/space.c b/src/space.c index 82f369a501bc1be13d27d8096acc8a57a004a580..85e1147a909346829b6ff9df7e15619ecc0d15e5 100644 --- a/src/space.c +++ b/src/space.c @@ -70,6 +70,18 @@ int space_subsize_pair_stars = space_subsize_pair_stars_default; int space_subsize_self_stars = space_subsize_self_stars_default; int space_subdepth_diff_grav = space_subdepth_diff_grav_default; int space_maxsize = space_maxsize_default; + +/*! Number of extra #part we allocate memory for per top-level cell */ +int space_extra_parts = space_extra_parts_default; + +/*! Number of extra #spart we allocate memory for per top-level cell */ +int space_extra_sparts = space_extra_sparts_default; + +/*! Number of extra #gpart we allocate memory for per top-level cell */ +int space_extra_gparts = space_extra_gparts_default; + +/*! Expected maximal number of strays received at a rebuild */ +int space_expected_max_nr_strays = space_expected_max_nr_strays_default; #ifdef SWIFT_DEBUG_CHECKS int last_cell_id; #endif @@ -104,9 +116,12 @@ struct index_data { struct space *s; int *ind; int *cell_counts; - int count_inhibited_part; - int count_inhibited_gpart; - int count_inhibited_spart; + size_t count_inhibited_part; + size_t count_inhibited_gpart; + size_t count_inhibited_spart; + size_t count_extra_part; + size_t count_extra_gpart; + size_t count_extra_spart; }; /** @@ -136,13 +151,13 @@ void space_rebuild_recycle_rec(struct space *s, struct cell *c, c->progeny[k]->next = *cell_rec_begin; *cell_rec_begin = c->progeny[k]; - if (s->gravity) { + if (s->with_self_gravity) { c->progeny[k]->grav.multipole->next = *multipole_rec_begin; *multipole_rec_begin = c->progeny[k]->grav.multipole; } if (*cell_rec_end == NULL) *cell_rec_end = *cell_rec_begin; - if (s->gravity && *multipole_rec_end == NULL) + if (s->with_self_gravity && *multipole_rec_end == NULL) *multipole_rec_end = *multipole_rec_begin; c->progeny[k]->grav.multipole = NULL; @@ -182,12 +197,15 @@ void space_rebuild_recycle_mapper(void *map_data, int num_elements, c->hydro.sorted = 0; c->stars.sorted = 0; c->hydro.count = 0; + c->hydro.count_total = 0; c->hydro.updated = 0; c->hydro.inhibited = 0; c->grav.count = 0; + c->grav.count_total = 0; c->grav.updated = 0; c->grav.inhibited = 0; c->stars.count = 0; + c->stars.count_total = 0; c->stars.updated = 0; c->stars.inhibited = 0; c->grav.init = NULL; @@ -232,7 +250,8 @@ void space_rebuild_recycle_mapper(void *map_data, int num_elements, #ifdef SWIFT_DEBUG_CHECKS c->cellID = 0; #endif - if (s->gravity) bzero(c->grav.multipole, sizeof(struct gravity_tensors)); + if (s->with_self_gravity) + bzero(c->grav.multipole, sizeof(struct gravity_tensors)); for (int i = 0; i < 13; i++) { if (c->hydro.sort[i] != NULL) { free(c->hydro.sort[i]); @@ -445,7 +464,7 @@ void space_regrid(struct space *s, int verbose) { bzero(s->cells_top, s->nr_cells * sizeof(struct cell)); /* Allocate the multipoles for the top-level cells. */ - if (s->gravity) { + if (s->with_self_gravity) { if (posix_memalign((void **)&s->multipoles_top, multipole_align, s->nr_cells * sizeof(struct gravity_tensors)) != 0) error("Failed to allocate top-level multipoles."); @@ -525,7 +544,7 @@ void space_regrid(struct space *s, int verbose) { c->mpi.grav.recv = NULL; c->mpi.grav.send = NULL; #endif // WITH_MPI - if (s->gravity) c->grav.multipole = &s->multipoles_top[cid]; + if (s->with_self_gravity) c->grav.multipole = &s->multipoles_top[cid]; #ifdef SWIFT_DEBUG_CHECKS c->cellID = -last_cell_id; last_cell_id++; @@ -602,6 +621,341 @@ void space_regrid(struct space *s, int verbose) { clocks_getunit()); } +/** + * @brief Allocate memory for the extra particles used for on-the-fly creation. + * + * This rarely actually allocates memory. Most of the time, we convert + * pre-allocated memory inot extra particles. + * + * This function also sets the extra particles' location to their top-level + * cells. They can then be sorted into their correct memory position later on. + * + * @param s The current #space. + * @param verbose Are we talkative? + */ +void space_allocate_extras(struct space *s, int verbose) { + + const int local_nodeID = s->e->nodeID; + + /* Anything to do here? (Abort if we don't want extras)*/ + if (space_extra_parts == 0 && space_extra_gparts == 0 && + space_extra_sparts == 0) + return; + + /* The top-level cells */ + const struct cell *cells = s->cells_top; + const double half_cell_width[3] = {0.5 * cells[0].width[0], + 0.5 * cells[0].width[1], + 0.5 * cells[0].width[2]}; + + /* The current number of particles (including spare ones) */ + size_t nr_parts = s->nr_parts; + size_t nr_gparts = s->nr_gparts; + size_t nr_sparts = s->nr_sparts; + + /* The current number of actual particles */ + size_t nr_actual_parts = nr_parts - s->nr_extra_parts; + size_t nr_actual_gparts = nr_gparts - s->nr_extra_gparts; + size_t nr_actual_sparts = nr_sparts - s->nr_extra_sparts; + + /* The number of particles we allocated memory for (MPI overhead) */ + size_t size_parts = s->size_parts; + size_t size_gparts = s->size_gparts; + size_t size_sparts = s->size_sparts; + + int local_cells = 0; + for (int i = 0; i < s->nr_cells; ++i) + if (s->cells_top[i].nodeID == local_nodeID) local_cells++; + + /* Number of extra particles we want for each type */ + const size_t expected_num_extra_parts = local_cells * space_extra_parts; + const size_t expected_num_extra_gparts = local_cells * space_extra_gparts; + const size_t expected_num_extra_sparts = local_cells * space_extra_sparts; + + if (verbose) { + message("Currently have %zd/%zd/%zd real particles.", nr_actual_parts, + nr_actual_gparts, nr_actual_sparts); + message("Currently have %zd/%zd/%zd spaces for extra particles.", + s->nr_extra_parts, s->nr_extra_gparts, s->nr_extra_sparts); + message("Requesting space for future %zd/%zd/%zd part/gpart/sparts.", + expected_num_extra_parts, expected_num_extra_gparts, + expected_num_extra_sparts); + } + + if (expected_num_extra_parts < s->nr_extra_parts) + error("Reduction in top-level cells number not handled."); + if (expected_num_extra_gparts < s->nr_extra_gparts) + error("Reduction in top-level cells number not handled."); + if (expected_num_extra_sparts < s->nr_extra_sparts) + error("Reduction in top-level cells number not handled."); + + /* Do we have enough space for the extra gparts (i.e. we haven't used up any) + * ? */ + if (nr_gparts + expected_num_extra_gparts > size_gparts) { + + /* Ok... need to put some more in the game */ + + /* Do we need to reallocate? */ + if (nr_actual_gparts + expected_num_extra_gparts > size_gparts) { + + size_gparts = (nr_actual_gparts + expected_num_extra_gparts) * + engine_redistribute_alloc_margin; + + if (verbose) + message("Re-allocating gparts array from %zd to %zd", s->size_gparts, + size_gparts); + + /* Create more space for parts */ + struct gpart *gparts_new = NULL; + if (posix_memalign((void **)&gparts_new, gpart_align, + sizeof(struct gpart) * size_gparts) != 0) + error("Failed to allocate new gpart data"); + const ptrdiff_t delta = gparts_new - s->gparts; + memcpy(gparts_new, s->gparts, sizeof(struct gpart) * s->size_gparts); + free(s->gparts); + s->gparts = gparts_new; + + /* Update the counter */ + s->size_gparts = size_gparts; + + /* We now need to reset all the part and spart pointers */ + for (size_t i = 0; i < nr_parts; ++i) { + if (s->parts[i].time_bin != time_bin_not_created) + s->parts[i].gpart += delta; + } + for (size_t i = 0; i < nr_sparts; ++i) { + if (s->sparts[i].time_bin != time_bin_not_created) + s->sparts[i].gpart += delta; + } + } + + /* Turn some of the allocated spares into particles we can use */ + for (size_t i = nr_gparts; i < nr_actual_gparts + expected_num_extra_gparts; + ++i) { + bzero(&s->gparts[i], sizeof(struct gpart)); + s->gparts[i].time_bin = time_bin_not_created; + s->gparts[i].type = swift_type_dark_matter; + s->gparts[i].id_or_neg_offset = -1; + } + + /* Put the spare particles in their correct cell */ +#ifdef WITH_MPI + error("Need to do this correctly over MPI for only the local cells."); +#endif + int count_in_cell = 0, current_cell = 0; + size_t count_extra_gparts = 0; + for (size_t i = 0; i < nr_actual_gparts + expected_num_extra_gparts; ++i) { + +#ifdef SWIFT_DEBUG_CHECKS + if (current_cell == s->nr_cells) + error("Cell counter beyond the maximal nr. cells."); +#endif + + if (s->gparts[i].time_bin == time_bin_not_created) { + + /* We want the extra particles to be at the centre of their cell */ + s->gparts[i].x[0] = cells[current_cell].loc[0] + half_cell_width[0]; + s->gparts[i].x[1] = cells[current_cell].loc[1] + half_cell_width[1]; + s->gparts[i].x[2] = cells[current_cell].loc[2] + half_cell_width[2]; + ++count_in_cell; + count_extra_gparts++; + } + + /* Once we have reached the number of extra gpart per cell, we move to the + * next */ + if (count_in_cell == space_extra_gparts) { + ++current_cell; + count_in_cell = 0; + } + } + +#ifdef SWIFT_DEBUG_CHECKS + if (count_extra_gparts != expected_num_extra_gparts) + error("Constructed the wrong number of extra gparts (%zd vs. %zd)", + count_extra_gparts, expected_num_extra_gparts); +#endif + + /* Update the counters */ + s->nr_gparts = nr_actual_gparts + expected_num_extra_gparts; + s->nr_extra_gparts = expected_num_extra_gparts; + } + + /* Do we have enough space for the extra parts (i.e. we haven't used up any) ? + */ + if (expected_num_extra_parts > s->nr_extra_parts) { + + /* Ok... need to put some more in the game */ + + /* Do we need to reallocate? */ + if (nr_actual_parts + expected_num_extra_parts > size_parts) { + + size_parts = (nr_actual_parts + expected_num_extra_parts) * + engine_redistribute_alloc_margin; + + if (verbose) + message("Re-allocating parts array from %zd to %zd", s->size_parts, + size_parts); + + /* Create more space for parts */ + struct part *parts_new = NULL; + if (posix_memalign((void **)&parts_new, part_align, + sizeof(struct part) * size_parts) != 0) + error("Failed to allocate new part data"); + memcpy(parts_new, s->parts, sizeof(struct part) * s->size_parts); + free(s->parts); + s->parts = parts_new; + + /* Same for xparts */ + struct xpart *xparts_new = NULL; + if (posix_memalign((void **)&xparts_new, xpart_align, + sizeof(struct xpart) * size_parts) != 0) + error("Failed to allocate new xpart data"); + memcpy(xparts_new, s->xparts, sizeof(struct xpart) * s->size_parts); + free(s->xparts); + s->xparts = xparts_new; + + /* Update the counter */ + s->size_parts = size_parts; + } + + /* Turn some of the allocated spares into particles we can use */ + for (size_t i = nr_parts; i < nr_actual_parts + expected_num_extra_parts; + ++i) { + bzero(&s->parts[i], sizeof(struct part)); + bzero(&s->xparts[i], sizeof(struct xpart)); + s->parts[i].time_bin = time_bin_not_created; + s->parts[i].id = -1; + } + + /* Put the spare particles in their correct cell */ +#ifdef WITH_MPI + error("Need to do this correctly over MPI for only the local cells."); +#endif + int count_in_cell = 0, current_cell = 0; + size_t count_extra_parts = 0; + for (size_t i = 0; i < nr_actual_parts + expected_num_extra_parts; ++i) { + +#ifdef SWIFT_DEBUG_CHECKS + if (current_cell == s->nr_cells) + error("Cell counter beyond the maximal nr. cells."); +#endif + + if (s->parts[i].time_bin == time_bin_not_created) { + + /* We want the extra particles to be at the centre of their cell */ + s->parts[i].x[0] = cells[current_cell].loc[0] + half_cell_width[0]; + s->parts[i].x[1] = cells[current_cell].loc[1] + half_cell_width[1]; + s->parts[i].x[2] = cells[current_cell].loc[2] + half_cell_width[2]; + ++count_in_cell; + count_extra_parts++; + } + + /* Once we have reached the number of extra part per cell, we move to the + * next */ + if (count_in_cell == space_extra_parts) { + ++current_cell; + count_in_cell = 0; + } + } + +#ifdef SWIFT_DEBUG_CHECKS + if (count_extra_parts != expected_num_extra_parts) + error("Constructed the wrong number of extra parts (%zd vs. %zd)", + count_extra_parts, expected_num_extra_parts); +#endif + + /* Update the counters */ + s->nr_parts = nr_actual_parts + expected_num_extra_parts; + s->nr_extra_parts = expected_num_extra_parts; + } + + /* Do we have enough space for the extra sparts (i.e. we haven't used up any) + * ? */ + if (nr_actual_sparts + expected_num_extra_sparts > nr_sparts) { + + /* Ok... need to put some more in the game */ + + /* Do we need to reallocate? */ + if (nr_actual_sparts + expected_num_extra_sparts > size_sparts) { + + size_sparts = (nr_actual_sparts + expected_num_extra_sparts) * + engine_redistribute_alloc_margin; + + if (verbose) + message("Re-allocating sparts array from %zd to %zd", s->size_sparts, + size_sparts); + + /* Create more space for parts */ + struct spart *sparts_new = NULL; + if (posix_memalign((void **)&sparts_new, spart_align, + sizeof(struct spart) * size_sparts) != 0) + error("Failed to allocate new spart data"); + memcpy(sparts_new, s->sparts, sizeof(struct spart) * s->size_sparts); + free(s->sparts); + s->sparts = sparts_new; + + /* Update the counter */ + s->size_sparts = size_sparts; + } + + /* Turn some of the allocated spares into particles we can use */ + for (size_t i = nr_sparts; i < nr_actual_sparts + expected_num_extra_sparts; + ++i) { + bzero(&s->sparts[i], sizeof(struct spart)); + s->sparts[i].time_bin = time_bin_not_created; + s->sparts[i].id = -42; + } + + /* Put the spare particles in their correct cell */ +#ifdef WITH_MPI + error("Need to do this correctly over MPI for only the local cells."); +#endif + int count_in_cell = 0, current_cell = 0; + size_t count_extra_sparts = 0; + for (size_t i = 0; i < nr_actual_sparts + expected_num_extra_sparts; ++i) { + +#ifdef SWIFT_DEBUG_CHECKS + if (current_cell == s->nr_cells) + error("Cell counter beyond the maximal nr. cells."); +#endif + + if (s->sparts[i].time_bin == time_bin_not_created) { + + /* We want the extra particles to be at the centre of their cell */ + s->sparts[i].x[0] = cells[current_cell].loc[0] + half_cell_width[0]; + s->sparts[i].x[1] = cells[current_cell].loc[1] + half_cell_width[1]; + s->sparts[i].x[2] = cells[current_cell].loc[2] + half_cell_width[2]; + ++count_in_cell; + count_extra_sparts++; + } + + /* Once we have reached the number of extra spart per cell, we move to the + * next */ + if (count_in_cell == space_extra_sparts) { + ++current_cell; + count_in_cell = 0; + } + } + +#ifdef SWIFT_DEBUG_CHECKS + if (count_extra_sparts != expected_num_extra_sparts) + error("Constructed the wrong number of extra sparts (%zd vs. %zd)", + count_extra_sparts, expected_num_extra_sparts); +#endif + + /* Update the counters */ + s->nr_sparts = nr_actual_sparts + expected_num_extra_sparts; + s->nr_extra_sparts = expected_num_extra_sparts; + } + +#ifdef SWIFT_DEBUG_CHECKS + /* Verify that the links are correct */ + if ((nr_gparts > 0 && nr_parts > 0) || (nr_gparts > 0 && nr_sparts > 0)) + part_verify_links(s->parts, s->gparts, s->sparts, nr_parts, nr_gparts, + nr_sparts, verbose); +#endif +} + /** * @brief Re-build the cells as well as the tasks. * @@ -622,67 +976,105 @@ void space_rebuild(struct space *s, int repartitioned, int verbose) { /* Re-grid if necessary, or just re-set the cell data. */ space_regrid(s, verbose); + /* Allocate extra space for particles that will be created */ + if (s->with_star_formation) space_allocate_extras(s, verbose); + + struct cell *cells_top = s->cells_top; + const integertime_t ti_current = (s->e != NULL) ? s->e->ti_current : 0; + const int local_nodeID = s->e->nodeID; + + /* The current number of particles */ size_t nr_parts = s->nr_parts; size_t nr_gparts = s->nr_gparts; size_t nr_sparts = s->nr_sparts; - int count_inhibited_parts = 0; - int count_inhibited_gparts = 0; - int count_inhibited_sparts = 0; - struct cell *restrict cells_top = s->cells_top; - const integertime_t ti_current = (s->e != NULL) ? s->e->ti_current : 0; - /* Run through the particles and get their cell index. Allocates - an index that is larger than the number of particles to avoid - re-allocating after shuffling. */ - const size_t ind_size = s->size_parts + 100; - int *ind = (int *)malloc(sizeof(int) * ind_size); - if (ind == NULL) error("Failed to allocate temporary particle indices."); - int *cell_part_counts = (int *)calloc(sizeof(int), s->nr_cells); - if (cell_part_counts == NULL) - error("Failed to allocate cell part count buffer."); - if (s->size_parts > 0) - space_parts_get_cell_index(s, ind, cell_part_counts, &count_inhibited_parts, - verbose); + /* The number of particles we allocated memory for */ + size_t size_parts = s->size_parts; + size_t size_gparts = s->size_gparts; + size_t size_sparts = s->size_sparts; + + /* Counter for the number of inhibited particles found on the node */ + size_t count_inhibited_parts = 0; + size_t count_inhibited_gparts = 0; + size_t count_inhibited_sparts = 0; + + /* Counter for the number of extra particles found on the node */ + size_t count_extra_parts = 0; + size_t count_extra_gparts = 0; + size_t count_extra_sparts = 0; + + /* Number of particles we expect to have after strays exchange */ + const size_t h_index_size = size_parts + space_expected_max_nr_strays; + const size_t g_index_size = size_gparts + space_expected_max_nr_strays; + const size_t s_index_size = size_sparts + space_expected_max_nr_strays; + + /* Allocate arrays to store the indices of the cells where particles + belong. We allocate extra space to allow for particles we may + receive from other nodes */ + int *h_index = (int *)malloc(sizeof(int) * h_index_size); + int *g_index = (int *)malloc(sizeof(int) * g_index_size); + int *s_index = (int *)malloc(sizeof(int) * s_index_size); + if (h_index == NULL || g_index == NULL || s_index == NULL) + error("Failed to allocate temporary particle indices."); + + /* Allocate counters of particles that will land in each cell */ + int *cell_part_counts = (int *)malloc(sizeof(int) * s->nr_cells); + int *cell_gpart_counts = (int *)malloc(sizeof(int) * s->nr_cells); + int *cell_spart_counts = (int *)malloc(sizeof(int) * s->nr_cells); + if (cell_part_counts == NULL || cell_gpart_counts == NULL || + cell_spart_counts == NULL) + error("Failed to allocate cell particle count buffer."); + + /* Initialise the counters, including buffer space for future particles */ + for (int i = 0; i < s->nr_cells; ++i) { + cell_part_counts[i] = 0; + cell_gpart_counts[i] = 0; + cell_spart_counts[i] = 0; + } - /* Run through the gravity particles and get their cell index. */ - const size_t gind_size = s->size_gparts + 100; - int *gind = (int *)malloc(sizeof(int) * gind_size); - if (gind == NULL) error("Failed to allocate temporary g-particle indices."); - int *cell_gpart_counts = (int *)calloc(sizeof(int), s->nr_cells); - if (cell_gpart_counts == NULL) - error("Failed to allocate cell gpart count buffer."); - if (s->size_gparts > 0) - space_gparts_get_cell_index(s, gind, cell_gpart_counts, - &count_inhibited_gparts, verbose); - - /* Run through the star particles and get their cell index. */ - const size_t sind_size = s->size_sparts + 100; - int *sind = (int *)malloc(sizeof(int) * sind_size); - if (sind == NULL) error("Failed to allocate temporary s-particle indices."); - int *cell_spart_counts = (int *)calloc(sizeof(int), s->nr_cells); - if (cell_spart_counts == NULL) - error("Failed to allocate cell gpart count buffer."); - if (s->size_sparts > 0) - space_sparts_get_cell_index(s, sind, cell_spart_counts, - &count_inhibited_sparts, verbose); + /* Run through the particles and get their cell index. */ + if (nr_parts > 0) + space_parts_get_cell_index(s, h_index, cell_part_counts, + &count_inhibited_parts, &count_extra_parts, + verbose); + if (nr_gparts > 0) + space_gparts_get_cell_index(s, g_index, cell_gpart_counts, + &count_inhibited_gparts, &count_extra_gparts, + verbose); + if (nr_sparts > 0) + space_sparts_get_cell_index(s, s_index, cell_spart_counts, + &count_inhibited_sparts, &count_extra_sparts, + verbose); #ifdef SWIFT_DEBUG_CHECKS + /* Some safety checks */ if (repartitioned && count_inhibited_parts) error("We just repartitioned but still found inhibited parts."); if (repartitioned && count_inhibited_sparts) error("We just repartitioned but still found inhibited sparts."); if (repartitioned && count_inhibited_gparts) error("We just repartitioned but still found inhibited gparts."); -#endif - const int local_nodeID = s->e->nodeID; + if (count_extra_parts != s->nr_extra_parts) + error( + "Number of extra parts in the part array not matching the space " + "counter."); + if (count_extra_gparts != s->nr_extra_gparts) + error( + "Number of extra gparts in the gpart array not matching the space " + "counter."); + if (count_extra_sparts != s->nr_extra_sparts) + error( + "Number of extra sparts in the spart array not matching the space " + "counter."); +#endif /* Move non-local parts and inhibited parts to the end of the list. */ if (!repartitioned && (s->e->nr_nodes > 1 || count_inhibited_parts > 0)) { for (size_t k = 0; k < nr_parts; /* void */) { /* Inhibited particle or foreign particle */ - if (ind[k] == -1 || cells_top[ind[k]].nodeID != local_nodeID) { + if (h_index[k] == -1 || cells_top[h_index[k]].nodeID != local_nodeID) { /* One fewer particle */ nr_parts -= 1; @@ -701,7 +1093,7 @@ void space_rebuild(struct space *s, int repartitioned, int verbose) { /* Swap the xpart */ memswap(&s->xparts[k], &s->xparts[nr_parts], sizeof(struct xpart)); /* Swap the index */ - memswap(&ind[k], &ind[nr_parts], sizeof(int)); + memswap(&h_index[k], &h_index[nr_parts], sizeof(int)); } else { /* Increment when not exchanging otherwise we need to retest "k".*/ @@ -712,17 +1104,17 @@ void space_rebuild(struct space *s, int repartitioned, int verbose) { #ifdef SWIFT_DEBUG_CHECKS /* Check that all parts are in the correct places. */ - int check_count_inhibited_part = 0; + size_t check_count_inhibited_part = 0; for (size_t k = 0; k < nr_parts; k++) { - if (ind[k] == -1 || cells_top[ind[k]].nodeID != local_nodeID) { + if (h_index[k] == -1 || cells_top[h_index[k]].nodeID != local_nodeID) { error("Failed to move all non-local parts to send list"); } } for (size_t k = nr_parts; k < s->nr_parts; k++) { - if (ind[k] != -1 && cells_top[ind[k]].nodeID == local_nodeID) { + if (h_index[k] != -1 && cells_top[h_index[k]].nodeID == local_nodeID) { error("Failed to remove local parts from send list"); } - if (ind[k] == -1) ++check_count_inhibited_part; + if (h_index[k] == -1) ++check_count_inhibited_part; } if (check_count_inhibited_part != count_inhibited_parts) error("Counts of inhibited particles do not match!"); @@ -733,7 +1125,7 @@ void space_rebuild(struct space *s, int repartitioned, int verbose) { for (size_t k = 0; k < nr_sparts; /* void */) { /* Inhibited particle or foreign particle */ - if (sind[k] == -1 || cells_top[sind[k]].nodeID != local_nodeID) { + if (s_index[k] == -1 || cells_top[s_index[k]].nodeID != local_nodeID) { /* One fewer particle */ nr_sparts -= 1; @@ -750,7 +1142,7 @@ void space_rebuild(struct space *s, int repartitioned, int verbose) { } /* Swap the index */ - memswap(&sind[k], &sind[nr_sparts], sizeof(int)); + memswap(&s_index[k], &s_index[nr_sparts], sizeof(int)); } else { /* Increment when not exchanging otherwise we need to retest "k".*/ @@ -761,17 +1153,17 @@ void space_rebuild(struct space *s, int repartitioned, int verbose) { #ifdef SWIFT_DEBUG_CHECKS /* Check that all sparts are in the correct place. */ - int check_count_inhibited_spart = 0; + size_t check_count_inhibited_spart = 0; for (size_t k = 0; k < nr_sparts; k++) { - if (sind[k] == -1 || cells_top[sind[k]].nodeID != local_nodeID) { + if (s_index[k] == -1 || cells_top[s_index[k]].nodeID != local_nodeID) { error("Failed to move all non-local sparts to send list"); } } for (size_t k = nr_sparts; k < s->nr_sparts; k++) { - if (sind[k] != -1 && cells_top[sind[k]].nodeID == local_nodeID) { + if (s_index[k] != -1 && cells_top[s_index[k]].nodeID == local_nodeID) { error("Failed to remove local sparts from send list"); } - if (sind[k] == -1) ++check_count_inhibited_spart; + if (s_index[k] == -1) ++check_count_inhibited_spart; } if (check_count_inhibited_spart != count_inhibited_sparts) error("Counts of inhibited s-particles do not match!"); @@ -782,7 +1174,7 @@ void space_rebuild(struct space *s, int repartitioned, int verbose) { for (size_t k = 0; k < nr_gparts; /* void */) { /* Inhibited particle or foreign particle */ - if (gind[k] == -1 || cells_top[gind[k]].nodeID != local_nodeID) { + if (g_index[k] == -1 || cells_top[g_index[k]].nodeID != local_nodeID) { /* One fewer particle */ nr_gparts -= 1; @@ -805,7 +1197,7 @@ void space_rebuild(struct space *s, int repartitioned, int verbose) { } /* Swap the index */ - memswap(&gind[k], &gind[nr_gparts], sizeof(int)); + memswap(&g_index[k], &g_index[nr_gparts], sizeof(int)); } else { /* Increment when not exchanging otherwise we need to retest "k".*/ k++; @@ -815,17 +1207,17 @@ void space_rebuild(struct space *s, int repartitioned, int verbose) { #ifdef SWIFT_DEBUG_CHECKS /* Check that all gparts are in the correct place. */ - int check_count_inhibited_gpart = 0; + size_t check_count_inhibited_gpart = 0; for (size_t k = 0; k < nr_gparts; k++) { - if (gind[k] == -1 || cells_top[gind[k]].nodeID != local_nodeID) { + if (g_index[k] == -1 || cells_top[g_index[k]].nodeID != local_nodeID) { error("Failed to move all non-local gparts to send list"); } } for (size_t k = nr_gparts; k < s->nr_gparts; k++) { - if (gind[k] != -1 && cells_top[gind[k]].nodeID == local_nodeID) { + if (g_index[k] != -1 && cells_top[g_index[k]].nodeID == local_nodeID) { error("Failed to remove local gparts from send list"); } - if (gind[k] == -1) ++check_count_inhibited_gpart; + if (g_index[k] == -1) ++check_count_inhibited_gpart; } if (check_count_inhibited_gpart != count_inhibited_gparts) error("Counts of inhibited g-particles do not match!"); @@ -834,21 +1226,23 @@ void space_rebuild(struct space *s, int repartitioned, int verbose) { #ifdef WITH_MPI /* Exchange the strays, note that this potentially re-allocates - the parts arrays. This can be skipped if we just repartitioned aspace - there should be no strays */ + the parts arrays. This can be skipped if we just repartitioned space + as there should be no strays in that case */ if (!repartitioned) { size_t nr_parts_exchanged = s->nr_parts - nr_parts; size_t nr_gparts_exchanged = s->nr_gparts - nr_gparts; size_t nr_sparts_exchanged = s->nr_sparts - nr_sparts; - engine_exchange_strays(s->e, nr_parts, &ind[nr_parts], &nr_parts_exchanged, - nr_gparts, &gind[nr_gparts], &nr_gparts_exchanged, - nr_sparts, &sind[nr_sparts], &nr_sparts_exchanged); + engine_exchange_strays(s->e, nr_parts, &h_index[nr_parts], + &nr_parts_exchanged, nr_gparts, &g_index[nr_gparts], + &nr_gparts_exchanged, nr_sparts, &s_index[nr_sparts], + &nr_sparts_exchanged); /* Set the new particle counts. */ s->nr_parts = nr_parts + nr_parts_exchanged; s->nr_gparts = nr_gparts + nr_gparts_exchanged; s->nr_sparts = nr_sparts + nr_sparts_exchanged; + } else { #ifdef SWIFT_DEBUG_CHECKS if (s->nr_parts != nr_parts) @@ -870,23 +1264,23 @@ void space_rebuild(struct space *s, int repartitioned, int verbose) { } /* Re-allocate the index array for the parts if needed.. */ - if (s->nr_parts + 1 > ind_size) { + if (s->nr_parts + 1 > h_index_size) { int *ind_new; if ((ind_new = (int *)malloc(sizeof(int) * (s->nr_parts + 1))) == NULL) error("Failed to allocate temporary particle indices."); - memcpy(ind_new, ind, sizeof(int) * nr_parts); - free(ind); - ind = ind_new; + memcpy(ind_new, h_index, sizeof(int) * nr_parts); + free(h_index); + h_index = ind_new; } /* Re-allocate the index array for the sparts if needed.. */ - if (s->nr_sparts + 1 > sind_size) { + if (s->nr_sparts + 1 > s_index_size) { int *sind_new; if ((sind_new = (int *)malloc(sizeof(int) * (s->nr_sparts + 1))) == NULL) error("Failed to allocate temporary s-particle indices."); - memcpy(sind_new, sind, sizeof(int) * nr_sparts); - free(sind); - sind = sind_new; + memcpy(sind_new, s_index, sizeof(int) * nr_sparts); + free(s_index); + s_index = sind_new; } const int cdim[3] = {s->cdim[0], s->cdim[1], s->cdim[2]}; @@ -895,13 +1289,13 @@ void space_rebuild(struct space *s, int repartitioned, int verbose) { /* Assign each received part to its cell. */ for (size_t k = nr_parts; k < s->nr_parts; k++) { const struct part *const p = &s->parts[k]; - ind[k] = + h_index[k] = cell_getid(cdim, p->x[0] * ih[0], p->x[1] * ih[1], p->x[2] * ih[2]); - cell_part_counts[ind[k]]++; + cell_part_counts[h_index[k]]++; #ifdef SWIFT_DEBUG_CHECKS - if (cells_top[ind[k]].nodeID != local_nodeID) + if (cells_top[h_index[k]].nodeID != local_nodeID) error("Received part that does not belong to me (nodeID=%i).", - cells_top[ind[k]].nodeID); + cells_top[h_index[k]].nodeID); #endif } nr_parts = s->nr_parts; @@ -909,13 +1303,13 @@ void space_rebuild(struct space *s, int repartitioned, int verbose) { /* Assign each received spart to its cell. */ for (size_t k = nr_sparts; k < s->nr_sparts; k++) { const struct spart *const sp = &s->sparts[k]; - sind[k] = + s_index[k] = cell_getid(cdim, sp->x[0] * ih[0], sp->x[1] * ih[1], sp->x[2] * ih[2]); - cell_spart_counts[sind[k]]++; + cell_spart_counts[s_index[k]]++; #ifdef SWIFT_DEBUG_CHECKS - if (cells_top[sind[k]].nodeID != local_nodeID) + if (cells_top[s_index[k]].nodeID != local_nodeID) error("Received s-part that does not belong to me (nodeID=%i).", - cells_top[sind[k]].nodeID); + cells_top[s_index[k]].nodeID); #endif } nr_sparts = s->nr_sparts; @@ -930,8 +1324,8 @@ void space_rebuild(struct space *s, int repartitioned, int verbose) { /* Sort the parts according to their cells. */ if (nr_parts > 0) - space_parts_sort(s->parts, s->xparts, ind, cell_part_counts, s->nr_cells, - 0); + space_parts_sort(s->parts, s->xparts, h_index, cell_part_counts, + s->nr_cells, 0); #ifdef SWIFT_DEBUG_CHECKS /* Verify that the part have been sorted correctly. */ @@ -949,7 +1343,7 @@ void space_rebuild(struct space *s, int repartitioned, int verbose) { /* New cell of this part */ const struct cell *c = &s->cells_top[new_ind]; - if (ind[k] != new_ind) + if (h_index[k] != new_ind) error("part's new cell index not matching sorted index."); if (p->x[0] < c->loc[0] || p->x[0] > c->loc[0] + c->width[0] || @@ -961,7 +1355,7 @@ void space_rebuild(struct space *s, int repartitioned, int verbose) { /* Sort the sparts according to their cells. */ if (nr_sparts > 0) - space_sparts_sort(s->sparts, sind, cell_spart_counts, s->nr_cells, 0); + space_sparts_sort(s->sparts, s_index, cell_spart_counts, s->nr_cells, 0); #ifdef SWIFT_DEBUG_CHECKS /* Verify that the spart have been sorted correctly. */ @@ -979,7 +1373,7 @@ void space_rebuild(struct space *s, int repartitioned, int verbose) { /* New cell of this spart */ const struct cell *c = &s->cells_top[new_sind]; - if (sind[k] != new_sind) + if (s_index[k] != new_sind) error("spart's new cell index not matching sorted index."); if (sp->x[0] < c->loc[0] || sp->x[0] > c->loc[0] + c->width[0] || @@ -989,54 +1383,58 @@ void space_rebuild(struct space *s, int repartitioned, int verbose) { } #endif /* SWIFT_DEBUG_CHECKS */ - /* Extract the cell counts from the sorted indices. */ + /* Extract the cell counts from the sorted indices. Deduct the extra + * particles. */ size_t last_index = 0; - ind[nr_parts] = s->nr_cells; // sentinel. + h_index[nr_parts] = s->nr_cells; // sentinel. for (size_t k = 0; k < nr_parts; k++) { - if (ind[k] < ind[k + 1]) { - cells_top[ind[k]].hydro.count = k - last_index + 1; + if (h_index[k] < h_index[k + 1]) { + cells_top[h_index[k]].hydro.count = + k - last_index + 1 - space_extra_parts; last_index = k + 1; } } - /* Extract the cell counts from the sorted indices. */ + /* Extract the cell counts from the sorted indices. Deduct the extra + * particles. */ size_t last_sindex = 0; - sind[nr_sparts] = s->nr_cells; // sentinel. + s_index[nr_sparts] = s->nr_cells; // sentinel. for (size_t k = 0; k < nr_sparts; k++) { - if (sind[k] < sind[k + 1]) { - cells_top[sind[k]].stars.count = k - last_sindex + 1; + if (s_index[k] < s_index[k + 1]) { + cells_top[s_index[k]].stars.count = + k - last_sindex + 1 - space_extra_sparts; last_sindex = k + 1; } } /* We no longer need the indices as of here. */ - free(ind); + free(h_index); free(cell_part_counts); - free(sind); + free(s_index); free(cell_spart_counts); #ifdef WITH_MPI /* Re-allocate the index array for the gparts if needed.. */ - if (s->nr_gparts + 1 > gind_size) { + if (s->nr_gparts + 1 > g_index_size) { int *gind_new; if ((gind_new = (int *)malloc(sizeof(int) * (s->nr_gparts + 1))) == NULL) error("Failed to allocate temporary g-particle indices."); - memcpy(gind_new, gind, sizeof(int) * nr_gparts); - free(gind); - gind = gind_new; + memcpy(gind_new, g_index, sizeof(int) * nr_gparts); + free(g_index); + g_index = gind_new; } /* Assign each received gpart to its cell. */ for (size_t k = nr_gparts; k < s->nr_gparts; k++) { const struct gpart *const p = &s->gparts[k]; - gind[k] = + g_index[k] = cell_getid(cdim, p->x[0] * ih[0], p->x[1] * ih[1], p->x[2] * ih[2]); - cell_gpart_counts[gind[k]]++; + cell_gpart_counts[g_index[k]]++; #ifdef SWIFT_DEBUG_CHECKS - if (cells_top[gind[k]].nodeID != s->e->nodeID) + if (cells_top[g_index[k]].nodeID != s->e->nodeID) error("Received g-part that does not belong to me (nodeID=%i).", - cells_top[gind[k]].nodeID); + cells_top[g_index[k]].nodeID); #endif } nr_gparts = s->nr_gparts; @@ -1055,8 +1453,8 @@ void space_rebuild(struct space *s, int repartitioned, int verbose) { /* Sort the gparts according to their cells. */ if (nr_gparts > 0) - space_gparts_sort(s->gparts, s->parts, s->sparts, gind, cell_gpart_counts, - s->nr_cells); + space_gparts_sort(s->gparts, s->parts, s->sparts, g_index, + cell_gpart_counts, s->nr_cells); #ifdef SWIFT_DEBUG_CHECKS /* Verify that the gpart have been sorted correctly. */ @@ -1074,7 +1472,7 @@ void space_rebuild(struct space *s, int repartitioned, int verbose) { /* New cell of this gpart */ const struct cell *c = &s->cells_top[new_gind]; - if (gind[k] != new_gind) + if (g_index[k] != new_gind) error("gpart's new cell index not matching sorted index."); if (gp->x[0] < c->loc[0] || gp->x[0] > c->loc[0] + c->width[0] || @@ -1084,18 +1482,20 @@ void space_rebuild(struct space *s, int repartitioned, int verbose) { } #endif /* SWIFT_DEBUG_CHECKS */ - /* Extract the cell counts from the sorted indices. */ + /* Extract the cell counts from the sorted indices. Deduct the extra + * particles. */ size_t last_gindex = 0; - gind[nr_gparts] = s->nr_cells; + g_index[nr_gparts] = s->nr_cells; for (size_t k = 0; k < nr_gparts; k++) { - if (gind[k] < gind[k + 1]) { - cells_top[gind[k]].grav.count = k - last_gindex + 1; + if (g_index[k] < g_index[k + 1]) { + cells_top[g_index[k]].grav.count = + k - last_gindex + 1 - space_extra_gparts; last_gindex = k + 1; } } /* We no longer need the indices as of here. */ - free(gind); + free(g_index); free(cell_gpart_counts); #ifdef SWIFT_DEBUG_CHECKS @@ -1134,10 +1534,15 @@ void space_rebuild(struct space *s, int repartitioned, int verbose) { c->hydro.xparts = xfinger; c->grav.parts = gfinger; c->stars.parts = sfinger; - finger = &finger[c->hydro.count]; - xfinger = &xfinger[c->hydro.count]; - gfinger = &gfinger[c->grav.count]; - sfinger = &sfinger[c->stars.count]; + + c->hydro.count_total = c->hydro.count + space_extra_parts; + c->grav.count_total = c->grav.count + space_extra_gparts; + c->stars.count_total = c->stars.count + space_extra_sparts; + + finger = &finger[c->hydro.count_total]; + xfinger = &xfinger[c->hydro.count_total]; + gfinger = &gfinger[c->grav.count_total]; + sfinger = &sfinger[c->stars.count_total]; /* Add this cell to the list of local cells */ s->local_cells_top[s->nr_local_cells] = k; @@ -1160,13 +1565,17 @@ void space_rebuild(struct space *s, int repartitioned, int verbose) { clocks_from_ticks(getticks() - tic2), clocks_getunit()); } - /* At this point, we have the upper-level cells, old or new. Now make - sure that the parts in each cell are ok. */ + /* Re-order the extra particles such that they are at the end of their cell's + memory pool. */ + if (s->with_star_formation) space_reorder_extras(s, verbose); + + /* At this point, we have the upper-level cells. Now recursively split each + cell to get the full AMR grid. */ space_split(s, verbose); #ifdef SWIFT_DEBUG_CHECKS /* Check that the multipole construction went OK */ - if (s->gravity) + if (s->with_self_gravity) for (int k = 0; k < s->nr_cells; k++) cell_check_multipole(&s->cells_top[k]); #endif @@ -1201,6 +1610,75 @@ void space_split(struct space *s, int verbose) { clocks_getunit()); } +void space_reorder_extra_parts_mapper(void *map_data, int num_cells, + void *extra_data) { + + struct cell *cells_top = (struct cell *)map_data; + struct space *s = (struct space *)extra_data; + + for (int ind = 0; ind < num_cells; ind++) { + struct cell *c = &cells_top[ind]; + cell_reorder_extra_parts(c, c->hydro.parts - s->parts); + } +} + +void space_reorder_extra_gparts_mapper(void *map_data, int num_cells, + void *extra_data) { + + struct cell *cells_top = (struct cell *)map_data; + struct space *s = (struct space *)extra_data; + + for (int ind = 0; ind < num_cells; ind++) { + struct cell *c = &cells_top[ind]; + cell_reorder_extra_gparts(c, s->parts, s->sparts); + } +} + +void space_reorder_extra_sparts_mapper(void *map_data, int num_cells, + void *extra_data) { + + struct cell *cells_top = (struct cell *)map_data; + struct space *s = (struct space *)extra_data; + + for (int ind = 0; ind < num_cells; ind++) { + struct cell *c = &cells_top[ind]; + cell_reorder_extra_sparts(c, c->stars.parts - s->sparts); + } +} + +/** + * @brief Re-orders the particles in each cell such that the extra particles + * for on-the-fly creation are located at the end of their respective cells. + * + * This assumes that all the particles (real and extra) have already been sorted + * in their correct top-level cell. + * + * @param s The #space to act upon. + * @param verbose Are we talkative? + */ +void space_reorder_extras(struct space *s, int verbose) { + +#ifdef WITH_MPI + if (space_extra_parts || space_extra_gparts || space_extra_sparts) + error("Need an MPI-proof version of this."); +#endif + + /* Re-order the gas particles */ + if (space_extra_parts) + threadpool_map(&s->e->threadpool, space_reorder_extra_parts_mapper, + s->cells_top, s->nr_cells, sizeof(struct cell), 0, s); + + /* Re-order the gravity particles */ + if (space_extra_gparts) + threadpool_map(&s->e->threadpool, space_reorder_extra_gparts_mapper, + s->cells_top, s->nr_cells, sizeof(struct cell), 0, s); + + /* Re-order the star particles */ + if (space_extra_sparts) + threadpool_map(&s->e->threadpool, space_reorder_extra_sparts_mapper, + s->cells_top, s->nr_cells, sizeof(struct cell), 0, s); +} + /** * @brief #threadpool mapper function to sanitize the cells * @@ -1264,7 +1742,8 @@ void space_parts_get_cell_index_mapper(void *map_data, int nr_parts, /* Init the local collectors */ float min_mass = FLT_MAX; float sum_vel_norm = 0.f; - int count_inhibited_part = 0; + size_t count_inhibited_part = 0; + size_t count_extra_part = 0; /* Loop over the parts. */ for (int k = 0; k < nr_parts; k++) { @@ -1296,26 +1775,31 @@ void space_parts_get_cell_index_mapper(void *map_data, int nr_parts, pos_z); #endif - /* Is this particle to be removed? */ if (p->time_bin == time_bin_inhibited) { + /* Is this particle to be removed? */ ind[k] = -1; ++count_inhibited_part; + } else if (p->time_bin == time_bin_not_created) { + /* Is this a place-holder for on-the-fly creation? */ + ind[k] = index; + cell_counts[index]++; + ++count_extra_part; } else { - /* List its top-level cell index */ + /* Normal case: list its top-level cell index */ ind[k] = index; cell_counts[index]++; - } - /* Compute minimal mass */ - min_mass = min(min_mass, hydro_get_mass(p)); + /* Compute minimal mass */ + min_mass = min(min_mass, hydro_get_mass(p)); - /* Compute sum of velocity norm */ - sum_vel_norm += p->v[0] * p->v[0] + p->v[1] * p->v[1] + p->v[2] * p->v[2]; + /* Compute sum of velocity norm */ + sum_vel_norm += p->v[0] * p->v[0] + p->v[1] * p->v[1] + p->v[2] * p->v[2]; - /* Update the position */ - p->x[0] = pos_x; - p->x[1] = pos_y; - p->x[2] = pos_z; + /* Update the position */ + p->x[0] = pos_x; + p->x[1] = pos_y; + p->x[2] = pos_z; + } } /* Write the counts back to the global array. */ @@ -1323,8 +1807,10 @@ void space_parts_get_cell_index_mapper(void *map_data, int nr_parts, if (cell_counts[k]) atomic_add(&data->cell_counts[k], cell_counts[k]); free(cell_counts); - /* Write the count of inhibited parts */ - atomic_add(&data->count_inhibited_part, count_inhibited_part); + /* Write the count of inhibited and extra parts */ + if (count_inhibited_part) + atomic_add(&data->count_inhibited_part, count_inhibited_part); + if (count_extra_part) atomic_add(&data->count_extra_part, count_extra_part); /* Write back the minimal part mass and velocity sum */ atomic_min_f(&s->min_part_mass, min_mass); @@ -1364,7 +1850,8 @@ void space_gparts_get_cell_index_mapper(void *map_data, int nr_gparts, /* Init the local collectors */ float min_mass = FLT_MAX; float sum_vel_norm = 0.f; - int count_inhibited_gpart = 0; + size_t count_inhibited_gpart = 0; + size_t count_extra_gpart = 0; for (int k = 0; k < nr_gparts; k++) { @@ -1395,31 +1882,36 @@ void space_gparts_get_cell_index_mapper(void *map_data, int nr_gparts, pos_z); #endif - /* Is this particle to be removed? */ if (gp->time_bin == time_bin_inhibited) { + /* Is this particle to be removed? */ ind[k] = -1; ++count_inhibited_gpart; + } else if (gp->time_bin == time_bin_not_created) { + /* Is this a place-holder for on-the-fly creation? */ + ind[k] = index; + cell_counts[index]++; + ++count_extra_gpart; } else { /* List its top-level cell index */ ind[k] = index; cell_counts[index]++; - } - if (gp->type == swift_type_dark_matter) { + if (gp->type == swift_type_dark_matter) { - /* Compute minimal mass */ - min_mass = min(min_mass, gp->mass); + /* Compute minimal mass */ + min_mass = min(min_mass, gp->mass); - /* Compute sum of velocity norm */ - sum_vel_norm += gp->v_full[0] * gp->v_full[0] + - gp->v_full[1] * gp->v_full[1] + - gp->v_full[2] * gp->v_full[2]; - } + /* Compute sum of velocity norm */ + sum_vel_norm += gp->v_full[0] * gp->v_full[0] + + gp->v_full[1] * gp->v_full[1] + + gp->v_full[2] * gp->v_full[2]; + } - /* Update the position */ - gp->x[0] = pos_x; - gp->x[1] = pos_y; - gp->x[2] = pos_z; + /* Update the position */ + gp->x[0] = pos_x; + gp->x[1] = pos_y; + gp->x[2] = pos_z; + } } /* Write the counts back to the global array. */ @@ -1427,8 +1919,11 @@ void space_gparts_get_cell_index_mapper(void *map_data, int nr_gparts, if (cell_counts[k]) atomic_add(&data->cell_counts[k], cell_counts[k]); free(cell_counts); - /* Write the count of inhibited gparts */ - atomic_add(&data->count_inhibited_gpart, count_inhibited_gpart); + /* Write the count of inhibited and extra gparts */ + if (count_inhibited_gpart) + atomic_add(&data->count_inhibited_gpart, count_inhibited_gpart); + if (count_extra_gpart) + atomic_add(&data->count_extra_gpart, count_extra_gpart); /* Write back the minimal part mass and velocity sum */ atomic_min_f(&s->min_gpart_mass, min_mass); @@ -1468,7 +1963,8 @@ void space_sparts_get_cell_index_mapper(void *map_data, int nr_sparts, /* Init the local collectors */ float min_mass = FLT_MAX; float sum_vel_norm = 0.f; - int count_inhibited_spart = 0; + size_t count_inhibited_spart = 0; + size_t count_extra_spart = 0; for (int k = 0; k < nr_sparts; k++) { @@ -1503,23 +1999,28 @@ void space_sparts_get_cell_index_mapper(void *map_data, int nr_sparts, if (sp->time_bin == time_bin_inhibited) { ind[k] = -1; ++count_inhibited_spart; + } else if (sp->time_bin == time_bin_not_created) { + /* Is this a place-holder for on-the-fly creation? */ + ind[k] = index; + cell_counts[index]++; + ++count_extra_spart; } else { /* List its top-level cell index */ ind[k] = index; cell_counts[index]++; - } - /* Compute minimal mass */ - min_mass = min(min_mass, sp->mass); + /* Compute minimal mass */ + min_mass = min(min_mass, sp->mass); - /* Compute sum of velocity norm */ - sum_vel_norm += - sp->v[0] * sp->v[0] + sp->v[1] * sp->v[1] + sp->v[2] * sp->v[2]; + /* Compute sum of velocity norm */ + sum_vel_norm += + sp->v[0] * sp->v[0] + sp->v[1] * sp->v[1] + sp->v[2] * sp->v[2]; - /* Update the position */ - sp->x[0] = pos_x; - sp->x[1] = pos_y; - sp->x[2] = pos_z; + /* Update the position */ + sp->x[0] = pos_x; + sp->x[1] = pos_y; + sp->x[2] = pos_z; + } } /* Write the counts back to the global array. */ @@ -1527,8 +2028,11 @@ void space_sparts_get_cell_index_mapper(void *map_data, int nr_sparts, if (cell_counts[k]) atomic_add(&data->cell_counts[k], cell_counts[k]); free(cell_counts); - /* Write the count of inhibited parts */ - atomic_add(&data->count_inhibited_spart, count_inhibited_spart); + /* Write the count of inhibited and extra sparts */ + if (count_inhibited_spart) + atomic_add(&data->count_inhibited_spart, count_inhibited_spart); + if (count_extra_spart) + atomic_add(&data->count_extra_spart, count_extra_spart); /* Write back the minimal part mass and velocity sum */ atomic_min_f(&s->min_spart_mass, min_mass); @@ -1544,10 +2048,13 @@ void space_sparts_get_cell_index_mapper(void *map_data, int nr_sparts, * @param ind The array of indices to fill. * @param cell_counts The cell counters to update. * @param count_inhibited_parts (return) The number of #part to remove. + * @param count_extra_parts (return) The number of #part for on-the-fly + * creation. * @param verbose Are we talkative ? */ void space_parts_get_cell_index(struct space *s, int *ind, int *cell_counts, - int *count_inhibited_parts, int verbose) { + size_t *count_inhibited_parts, + size_t *count_extra_parts, int verbose) { const ticks tic = getticks(); @@ -1563,11 +2070,15 @@ void space_parts_get_cell_index(struct space *s, int *ind, int *cell_counts, data.count_inhibited_part = 0; data.count_inhibited_gpart = 0; data.count_inhibited_spart = 0; + data.count_extra_part = 0; + data.count_extra_gpart = 0; + data.count_extra_spart = 0; threadpool_map(&s->e->threadpool, space_parts_get_cell_index_mapper, s->parts, s->nr_parts, sizeof(struct part), 0, &data); *count_inhibited_parts = data.count_inhibited_part; + *count_extra_parts = data.count_extra_part; if (verbose) message("took %.3f %s.", clocks_from_ticks(getticks() - tic), @@ -1583,10 +2094,13 @@ void space_parts_get_cell_index(struct space *s, int *ind, int *cell_counts, * @param gind The array of indices to fill. * @param cell_counts The cell counters to update. * @param count_inhibited_gparts (return) The number of #gpart to remove. + * @param count_extra_gparts (return) The number of #gpart for on-the-fly + * creation. * @param verbose Are we talkative ? */ void space_gparts_get_cell_index(struct space *s, int *gind, int *cell_counts, - int *count_inhibited_gparts, int verbose) { + size_t *count_inhibited_gparts, + size_t *count_extra_gparts, int verbose) { const ticks tic = getticks(); @@ -1602,11 +2116,15 @@ void space_gparts_get_cell_index(struct space *s, int *gind, int *cell_counts, data.count_inhibited_part = 0; data.count_inhibited_gpart = 0; data.count_inhibited_spart = 0; + data.count_extra_part = 0; + data.count_extra_gpart = 0; + data.count_extra_spart = 0; threadpool_map(&s->e->threadpool, space_gparts_get_cell_index_mapper, s->gparts, s->nr_gparts, sizeof(struct gpart), 0, &data); *count_inhibited_gparts = data.count_inhibited_gpart; + *count_extra_gparts = data.count_extra_gpart; if (verbose) message("took %.3f %s.", clocks_from_ticks(getticks() - tic), @@ -1622,10 +2140,13 @@ void space_gparts_get_cell_index(struct space *s, int *gind, int *cell_counts, * @param sind The array of indices to fill. * @param cell_counts The cell counters to update. * @param count_inhibited_sparts (return) The number of #spart to remove. + * @param count_extra_sparts (return) The number of #spart for on-the-fly + * creation. * @param verbose Are we talkative ? */ void space_sparts_get_cell_index(struct space *s, int *sind, int *cell_counts, - int *count_inhibited_sparts, int verbose) { + size_t *count_inhibited_sparts, + size_t *count_extra_sparts, int verbose) { const ticks tic = getticks(); @@ -1641,11 +2162,15 @@ void space_sparts_get_cell_index(struct space *s, int *sind, int *cell_counts, data.count_inhibited_part = 0; data.count_inhibited_gpart = 0; data.count_inhibited_spart = 0; + data.count_extra_part = 0; + data.count_extra_gpart = 0; + data.count_extra_spart = 0; threadpool_map(&s->e->threadpool, space_sparts_get_cell_index_mapper, s->sparts, s->nr_sparts, sizeof(struct spart), 0, &data); *count_inhibited_sparts = data.count_inhibited_spart; + *count_extra_sparts = data.count_extra_spart; if (verbose) message("took %.3f %s.", clocks_from_ticks(getticks() - tic), @@ -2018,7 +2543,7 @@ void space_split_recursive(struct space *s, struct cell *c, const int count = c->hydro.count; const int gcount = c->grav.count; const int scount = c->stars.count; - const int with_gravity = s->gravity; + const int with_self_gravity = s->with_self_gravity; const int depth = c->depth; int maxdepth = 0; float h_max = 0.0f; @@ -2046,6 +2571,8 @@ void space_split_recursive(struct space *s, struct cell *c, #ifdef SWIFT_DEBUG_CHECKS if (parts[k].time_bin == time_bin_inhibited) error("Inhibited particle present in space_split()"); + if (parts[k].time_bin == time_bin_not_created) + error("Extra particle present in space_split()"); #endif buff[k].x[0] = parts[k].x[0]; buff[k].x[1] = parts[k].x[1]; @@ -2060,6 +2587,8 @@ void space_split_recursive(struct space *s, struct cell *c, #ifdef SWIFT_DEBUG_CHECKS if (gparts[k].time_bin == time_bin_inhibited) error("Inhibited particle present in space_split()"); + if (gparts[k].time_bin == time_bin_not_created) + error("Extra particle present in space_split()"); #endif gbuff[k].x[0] = gparts[k].x[0]; gbuff[k].x[1] = gparts[k].x[1]; @@ -2074,6 +2603,8 @@ void space_split_recursive(struct space *s, struct cell *c, #ifdef SWIFT_DEBUG_CHECKS if (sparts[k].time_bin == time_bin_inhibited) error("Inhibited particle present in space_split()"); + if (sparts[k].time_bin == time_bin_not_created) + error("Extra particle present in space_split()"); #endif sbuff[k].x[0] = sparts[k].x[0]; sbuff[k].x[1] = sparts[k].x[1]; @@ -2094,8 +2625,8 @@ void space_split_recursive(struct space *s, struct cell *c, } /* Split or let it be? */ - if ((with_gravity && gcount > space_splitsize) || - (!with_gravity && + if ((with_self_gravity && gcount > space_splitsize) || + (!with_self_gravity && (count > space_splitsize || scount > space_splitsize))) { /* No longer just a leaf. */ @@ -2108,6 +2639,9 @@ void space_split_recursive(struct space *s, struct cell *c, cp->hydro.count = 0; cp->grav.count = 0; cp->stars.count = 0; + cp->hydro.count_total = 0; + cp->grav.count_total = 0; + cp->stars.count_total = 0; cp->hydro.ti_old_part = c->hydro.ti_old_part; cp->grav.ti_old_part = c->grav.ti_old_part; cp->grav.ti_old_multipole = c->grav.ti_old_multipole; @@ -2193,7 +2727,7 @@ void space_split_recursive(struct space *s, struct cell *c, } /* Deal with the multipole */ - if (s->gravity) { + if (s->with_self_gravity) { /* Reset everything */ gravity_reset(c->grav.multipole); @@ -2317,6 +2851,8 @@ void space_split_recursive(struct space *s, struct cell *c, /* parts: Get dt_min/dt_max and h_max. */ for (int k = 0; k < count; k++) { #ifdef SWIFT_DEBUG_CHECKS + if (parts[k].time_bin == time_bin_not_created) + error("Extra particle present in space_split()"); if (parts[k].time_bin == time_bin_inhibited) error("Inhibited particle present in space_split()"); #endif @@ -2335,6 +2871,8 @@ void space_split_recursive(struct space *s, struct cell *c, /* gparts: Get dt_min/dt_max. */ for (int k = 0; k < gcount; k++) { #ifdef SWIFT_DEBUG_CHECKS + if (gparts[k].time_bin == time_bin_not_created) + error("Extra g-particle present in space_split()"); if (gparts[k].time_bin == time_bin_inhibited) error("Inhibited g-particle present in space_split()"); #endif @@ -2345,6 +2883,8 @@ void space_split_recursive(struct space *s, struct cell *c, /* sparts: Get dt_min/dt_max */ for (int k = 0; k < scount; k++) { #ifdef SWIFT_DEBUG_CHECKS + if (sparts[k].time_bin == time_bin_not_created) + error("Extra s-particle present in space_split()"); if (sparts[k].time_bin == time_bin_inhibited) error("Inhibited s-particle present in space_split()"); #endif @@ -2372,7 +2912,7 @@ void space_split_recursive(struct space *s, struct cell *c, ti_stars_end_min = get_integer_time_end(ti_current, stars_time_bin_min); /* Construct the multipole and the centre of mass*/ - if (s->gravity) { + if (s->with_self_gravity) { if (gcount > 0) { gravity_P2M(c->grav.multipole, c->grav.parts, c->grav.count); @@ -2480,7 +3020,7 @@ void space_recycle(struct space *s, struct cell *c) { lock_lock(&s->lock); /* Hook the multipole back in the buffer */ - if (s->gravity) { + if (s->with_self_gravity) { c->grav.multipole->next = s->multipoles_sub; s->multipoles_sub = c->grav.multipole; } @@ -2538,7 +3078,7 @@ void space_recycle_list(struct space *s, struct cell *cell_list_begin, s->tot_cells -= count; /* Hook the multipoles into the buffer. */ - if (s->gravity) { + if (s->with_self_gravity) { multipole_list_end->next = s->multipoles_sub; s->multipoles_sub = multipole_list_begin; } @@ -2582,7 +3122,7 @@ void space_getcells(struct space *s, int nr_cells, struct cell **cells) { } /* Is the multipole buffer empty? */ - if (s->gravity && s->multipoles_sub == NULL) { + if (s->with_self_gravity && s->multipoles_sub == NULL) { if (posix_memalign( (void **)&s->multipoles_sub, multipole_align, space_cellallocchunk * sizeof(struct gravity_tensors)) != 0) @@ -2600,7 +3140,7 @@ void space_getcells(struct space *s, int nr_cells, struct cell **cells) { s->tot_cells += 1; /* Hook the multipole */ - if (s->gravity) { + if (s->with_self_gravity) { cells[j]->grav.multipole = s->multipoles_sub; s->multipoles_sub = cells[j]->grav.multipole->next; } @@ -2773,6 +3313,13 @@ void space_first_init_parts_mapper(void *restrict map_data, int count, const struct chemistry_global_data *chemistry = e->chemistry; const struct cooling_function_data *cool_func = e->cooling_func; + /* Check that the smoothing lengths are non-zero */ + for (int k = 0; k < count; k++) { + if (p[k].h <= 0.) + error("Invalid value of smoothing length for part %lld h=%e", p[k].id, + p[k].h); + } + /* Convert velocities to internal units */ for (int k = 0; k < count; k++) { p[k].v[0] *= a_factor_vel; @@ -2900,12 +3447,15 @@ void space_first_init_sparts_mapper(void *restrict map_data, int count, struct spart *restrict sp = (struct spart *)map_data; const struct space *restrict s = (struct space *)extra_data; + const struct engine *e = s->e; #ifdef SWIFT_DEBUG_CHECKS const ptrdiff_t delta = sp - s->sparts; #endif - const struct cosmology *cosmo = s->e->cosmology; + const int with_feedback = (e->policy & engine_policy_feedback); + + const struct cosmology *cosmo = e->cosmology; const float a_factor_vel = cosmo->a; /* Convert velocities to internal units */ @@ -2926,6 +3476,13 @@ void space_first_init_sparts_mapper(void *restrict map_data, int count, #endif } + /* Check that the smoothing lengths are non-zero */ + for (int k = 0; k < count; k++) { + if (with_feedback && sp[k].h <= 0.) + error("Invalid value of smoothing length for spart %lld h=%e", sp[k].id, + sp[k].h); + } + /* Initialise the rest */ for (int k = 0; k < count; k++) { @@ -3045,8 +3602,11 @@ void space_convert_quantities_mapper(void *restrict map_data, int count, const ptrdiff_t index = parts - s->parts; struct xpart *restrict xparts = s->xparts + index; + /* Loop over all the particles ignoring the extra buffer ones for on-the-fly + * creation */ for (int k = 0; k < count; k++) - hydro_convert_quantities(&parts[k], &xparts[k], cosmo, hydro_props); + if (parts[k].time_bin <= num_time_bins) + hydro_convert_quantities(&parts[k], &xparts[k], cosmo, hydro_props); } /** @@ -3087,6 +3647,7 @@ void space_convert_quantities(struct space *s, int verbose) { * @param generate_gas_in_ics Are we generating gas particles from the gparts? * @param hydro flag whether we are doing hydro or not? * @param self_gravity flag whether we are doing gravity or not? + * @param star_formation flag whether we are doing star formation or not? * @param verbose Print messages to stdout or not. * @param dry_run If 1, just initialise stuff, don't do anything with the parts. * @@ -3100,7 +3661,8 @@ void space_init(struct space *s, struct swift_params *params, struct part *parts, struct gpart *gparts, struct spart *sparts, size_t Npart, size_t Ngpart, size_t Nspart, int periodic, int replicate, int generate_gas_in_ics, int hydro, - int self_gravity, int verbose, int dry_run) { + int self_gravity, int star_formation, int verbose, + int dry_run) { /* Clean-up everything */ bzero(s, sizeof(struct space)); @@ -3110,16 +3672,23 @@ void space_init(struct space *s, struct swift_params *params, s->dim[1] = dim[1]; s->dim[2] = dim[2]; s->periodic = periodic; - s->gravity = self_gravity; - s->hydro = hydro; + s->with_self_gravity = self_gravity; + s->with_hydro = hydro; + s->with_star_formation = star_formation; s->nr_parts = Npart; - s->size_parts = Npart; - s->parts = parts; s->nr_gparts = Ngpart; - s->size_gparts = Ngpart; - s->gparts = gparts; s->nr_sparts = Nspart; + s->size_parts = Npart; + s->size_gparts = Ngpart; s->size_sparts = Nspart; + s->nr_inhibited_parts = 0; + s->nr_inhibited_gparts = 0; + s->nr_inhibited_sparts = 0; + s->nr_extra_parts = 0; + s->nr_extra_gparts = 0; + s->nr_extra_sparts = 0; + s->parts = parts; + s->gparts = gparts; s->sparts = sparts; s->min_part_mass = FLT_MAX; s->min_gpart_mass = FLT_MAX; @@ -3202,6 +3771,12 @@ void space_init(struct space *s, struct swift_params *params, space_subdepth_diff_grav = parser_get_opt_param_int(params, "Scheduler:cell_subdepth_diff_grav", space_subdepth_diff_grav_default); + space_extra_parts = parser_get_opt_param_int( + params, "Scheduler:cell_extra_parts", space_extra_parts_default); + space_extra_sparts = parser_get_opt_param_int( + params, "Scheduler:cell_extra_sparts", space_extra_sparts_default); + space_extra_gparts = parser_get_opt_param_int( + params, "Scheduler:cell_extra_gparts", space_extra_gparts_default); if (verbose) { message("max_size set to %d split_size set to %d", space_maxsize, @@ -3308,6 +3883,9 @@ void space_init(struct space *s, struct swift_params *params, last_cell_id = 1; #endif + /* Do we want any spare particles for on the fly cration? */ + if (!star_formation) space_extra_sparts = 0; + /* Build the cells recursively. */ if (!dry_run) space_regrid(s, verbose); } @@ -3453,7 +4031,7 @@ void space_generate_gas(struct space *s, const struct cosmology *cosmo, int periodic, const double dim[3], int verbose) { /* Check that this is a sensible ting to do */ - if (!s->hydro) + if (!s->with_hydro) error( "Cannot generate gas from ICs if we are running without " "hydrodynamics. Need to run with -s and the corresponding " diff --git a/src/space.h b/src/space.h index e6d774200be1a31d622419dceafb16b3826ce177..a1280945d2aa232cbb5e5b519266bc7058e5dc57 100644 --- a/src/space.h +++ b/src/space.h @@ -44,6 +44,10 @@ struct cosmology; #define space_cellallocchunk 1000 #define space_splitsize_default 400 #define space_maxsize_default 8000000 +#define space_extra_parts_default 0 +#define space_extra_gparts_default 0 +#define space_extra_sparts_default 100 +#define space_expected_max_nr_strays_default 100 #define space_subsize_pair_hydro_default 256000000 #define space_subsize_self_hydro_default 32000 #define space_subsize_pair_grav_default 256000000 @@ -68,6 +72,9 @@ extern int space_subsize_self_grav; extern int space_subsize_pair_stars; extern int space_subsize_self_stars; extern int space_subdepth_diff_grav; +extern int space_extra_parts; +extern int space_extra_gparts; +extern int space_extra_sparts; /** * @brief The space in which the cells and particles reside. @@ -84,10 +91,13 @@ struct space { struct hydro_space hs; /*! Are we doing hydrodynamics? */ - int hydro; + int with_hydro; /*! Are we doing gravity? */ - int gravity; + int with_self_gravity; + + /*! Are we doing star formation? */ + int with_star_formation; /*! Width of the top-level cells. */ double width[3]; @@ -149,14 +159,23 @@ struct space { /*! The indices of the top-level cells that have >0 particles (of any kind) */ int *local_cells_with_particles_top; - /*! The total number of parts in the space. */ - size_t nr_parts, size_parts; + /*! The total number of #part in the space. */ + size_t nr_parts; + + /*! The total number of #gpart in the space. */ + size_t nr_gparts; + + /*! The total number of #spart in the space. */ + size_t nr_sparts; + + /*! The total number of #part we allocated memory for */ + size_t size_parts; - /*! The total number of g-parts in the space. */ - size_t nr_gparts, size_gparts; + /*! The total number of #gpart we allocated memory for */ + size_t size_gparts; - /*! The total number of g-parts in the space. */ - size_t nr_sparts, size_sparts; + /*! The total number of #spart we allocated memory for */ + size_t size_sparts; /*! Number of inhibted gas particles in the space */ size_t nr_inhibited_parts; @@ -167,6 +186,15 @@ struct space { /*! Number of inhibted star particles in the space */ size_t nr_inhibited_sparts; + /*! Number of extra #part we allocated (for on-the-fly creation) */ + size_t nr_extra_parts; + + /*! Number of extra #gpart we allocated (for on-the-fly creation) */ + size_t nr_extra_gparts; + + /*! Number of extra #spart we allocated (for on-the-fly creation) */ + size_t nr_extra_sparts; + /*! The particle data (cells have pointers to this). */ struct part *parts; @@ -241,7 +269,7 @@ void space_init(struct space *s, struct swift_params *params, struct part *parts, struct gpart *gparts, struct spart *sparts, size_t Npart, size_t Ngpart, size_t Nspart, int periodic, int replicate, int generate_gas_in_ics, int hydro, int gravity, - int verbose, int dry_run); + int star_formation, int verbose, int dry_run); void space_sanitize(struct space *s); void space_map_cells_pre(struct space *s, int full, void (*fun)(struct cell *c, void *data), void *data); @@ -260,14 +288,18 @@ void space_recycle_list(struct space *s, struct cell *cell_list_begin, struct gravity_tensors *multipole_list_begin, struct gravity_tensors *multipole_list_end); void space_split(struct space *s, int verbose); +void space_reorder_extras(struct space *s, int verbose); void space_split_mapper(void *map_data, int num_elements, void *extra_data); void space_list_useful_top_level_cells(struct space *s); void space_parts_get_cell_index(struct space *s, int *ind, int *cell_counts, - int *count_inibibited_parts, int verbose); + size_t *count_inhibited_parts, + size_t *count_extra_parts, int verbose); void space_gparts_get_cell_index(struct space *s, int *gind, int *cell_counts, - int *count_inibibited_gparts, int verbose); + size_t *count_inhibited_gparts, + size_t *count_extra_gparts, int verbose); void space_sparts_get_cell_index(struct space *s, int *sind, int *cell_counts, - int *count_inibibited_sparts, int verbose); + size_t *count_inhibited_sparts, + size_t *count_extra_sparts, int verbose); void space_synchronize_particle_positions(struct space *s); void space_do_parts_sort(void); void space_do_gparts_sort(void); diff --git a/src/swift.h b/src/swift.h index 153c4ae0d4440d083f1b0c9850e1f2649c0df6fb..7279fc58b3b4ac0227c11b8a835c829df2ceb49c 100644 --- a/src/swift.h +++ b/src/swift.h @@ -65,7 +65,6 @@ #include "scheduler.h" #include "serial_io.h" #include "single_io.h" -#include "sourceterms.h" #include "space.h" #include "stars.h" #include "stars_io.h" diff --git a/src/task.c b/src/task.c index 3918dad3b713c6c226e5dacf3e38756910c1dd27..f68d10f7cfbcfd512151e5bd4c21089128a6b804 100644 --- a/src/task.c +++ b/src/task.c @@ -75,7 +75,6 @@ const char *taskID_names[task_type_count] = {"none", "grav_mesh", "cooling", "star_formation", - "sourceterms", "logger", "stars_ghost_in", "stars_ghost", @@ -141,7 +140,6 @@ __attribute__((always_inline)) INLINE static enum task_actions task_acts_on( case task_type_ghost: case task_type_extra_ghost: case task_type_cooling: - case task_type_sourceterms: return task_action_part; break; @@ -391,6 +389,12 @@ void task_unlock(struct task *t) { cell_munlocktree(cj); break; + case task_type_star_formation: + cell_unlocktree(ci); + cell_sunlocktree(ci); + cell_gunlocktree(ci); + break; + default: break; } @@ -545,6 +549,21 @@ int task_lock(struct task *t) { cell_munlocktree(ci); return 0; } + break; + + case task_type_star_formation: + /* Lock the gas, gravity and star particles */ + if (ci->hydro.hold || ci->stars.hold || ci->grav.phold) return 0; + if (cell_locktree(ci) != 0) return 0; + if (cell_slocktree(ci) != 0) { + cell_unlocktree(ci); + return 0; + } + if (cell_glocktree(ci) != 0) { + cell_unlocktree(ci); + cell_sunlocktree(ci); + return 0; + } default: break; diff --git a/src/task.h b/src/task.h index 994b2b14c05965b71e877feac5cb9827a1d1b4bb..5bce55d6a28fae7ad99f966267b14e926b7fd924 100644 --- a/src/task.h +++ b/src/task.h @@ -67,7 +67,6 @@ enum task_types { task_type_grav_mesh, task_type_cooling, task_type_star_formation, - task_type_sourceterms, task_type_logger, task_type_stars_ghost_in, task_type_stars_ghost, diff --git a/src/timeline.h b/src/timeline.h index 38727def50b5a81c073ab23375f0c548ca096b66..09161b3ec68e9f7c19bf812103384257473f5719 100644 --- a/src/timeline.h +++ b/src/timeline.h @@ -40,6 +40,9 @@ typedef char timebin_t; /*! Fictious time-bin to hold inhibited particles */ #define time_bin_inhibited (num_time_bins + 2) +/*! Fictious time-bin to hold particles not yet created */ +#define time_bin_not_created (num_time_bins + 3) + /*! Fictitious time-bin for particles not awaken */ #define time_bin_not_awake (0) diff --git a/src/timers.c b/src/timers.c index d7523edaa42570f8e5f3c01516075267988dfd9c..9ede0320e49c70b2488cd5ceb3e4b6965659aa74 100644 --- a/src/timers.c +++ b/src/timers.c @@ -61,7 +61,6 @@ const char* timers_names[timer_count] = { "dograv_mesh", "dograv_top_level", "dograv_long_range", - "dosource", "dosub_self_density", "dosub_self_gradient", "dosub_self_force", diff --git a/src/timers.h b/src/timers.h index 412f36d7de547040e29efdede9cc6826358929bc..3a2a939339e6d08b43836d4f5ca213af0822c2b2 100644 --- a/src/timers.h +++ b/src/timers.h @@ -62,7 +62,6 @@ enum { timer_dograv_mesh, timer_dograv_top_level, timer_dograv_long_range, - timer_dosource, timer_dosub_self_density, timer_dosub_self_gradient, timer_dosub_self_force, diff --git a/tests/Makefile.am b/tests/Makefile.am index 7a0242437b8496d8c8756b1bccd2abb4d991262f..41bffaef3e1c61d5de2216d5e10c4841a0125929 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -15,9 +15,9 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. # Add the source directory and the non-standard paths to the included library headers to CFLAGS -AM_CFLAGS = -I$(top_srcdir)/src $(HDF5_CPPFLAGS) $(GSL_INCS) $(FFTW_INCS) +AM_CFLAGS = -I$(top_srcdir)/src $(HDF5_CPPFLAGS) $(GSL_INCS) $(FFTW_INCS) $(NUMA_INCS) -AM_LDFLAGS = ../src/.libs/libswiftsim.a $(HDF5_LDFLAGS) $(HDF5_LIBS) $(FFTW_LIBS) $(TCMALLOC_LIBS) $(JEMALLOC_LIBS) $(TBBMALLOC_LIBS) $(GRACKLE_LIBS) $(GSL_LIBS) $(PROFILER_LIBS) +AM_LDFLAGS = ../src/.libs/libswiftsim.a $(HDF5_LDFLAGS) $(HDF5_LIBS) $(FFTW_LIBS) $(NUMA_LIBS) $(TCMALLOC_LIBS) $(JEMALLOC_LIBS) $(TBBMALLOC_LIBS) $(GRACKLE_LIBS) $(GSL_LIBS) $(PROFILER_LIBS) # List of programs and scripts to run in the test suite TESTS = testGreetings testMaths testReading.sh testSingle testKernel \ diff --git a/theory/Cosmology/operators.tex b/theory/Cosmology/operators.tex index 89aa32bae554dceba8f1525cb209728a17154f5b..4ec4ea4b5fa49082295675420f562fa9e45e3e18 100644 --- a/theory/Cosmology/operators.tex +++ b/theory/Cosmology/operators.tex @@ -37,19 +37,21 @@ time using $\Delta t_{\rm kick,A} = \Delta t_{\rm 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} + difference.}. We additionally compute a few other terms +appearing in some viscosity terms and subgrid models. There are the +difference in cosmic time between the start and the end of the step +and the corresponding change in redshift: +\begin{align} + \Delta t_{\rm cosmic} &= \int_{a_n}^{a_{n+1}} dt = \frac{1}{H_0} + \int_{a_n}^{a_{n+1}} \frac{da}{a E(a)},\\ + \Delta z &= \frac{1}{a_n} - \frac{1}{a_{n+1}} \approx -\frac{H}{a} \Delta t_{\rm cosmic}. +\end{align} 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. +(sec. \ref{ssec:flrw}), these 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/timesteps.tex b/theory/Cosmology/timesteps.tex index 4a1c2ef534d32c667f1b5b655e9b93ae618b8c99..a9856d03a2d04cc0c917176a828fc135a83fb745 100644 --- a/theory/Cosmology/timesteps.tex +++ b/theory/Cosmology/timesteps.tex @@ -40,3 +40,7 @@ dominates the overall time-step size calculation. \subsubsection{Conversion from time to integer time-line} +\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} diff --git a/tools/task_plots/analyse_tasks.py b/tools/task_plots/analyse_tasks.py index ca41970c683a1680e9d1054c9d70d6370992a05e..f79a0090b04e013c9e10c53e6a4796e46579e1b9 100755 --- a/tools/task_plots/analyse_tasks.py +++ b/tools/task_plots/analyse_tasks.py @@ -91,7 +91,6 @@ TASKTYPES = [ "grav_mesh", "cooling", "star_formation", - "sourceterms", "logger", "stars_ghost_in", "stars_ghost", diff --git a/tools/task_plots/plot_tasks.py b/tools/task_plots/plot_tasks.py index 1fe7bcbd11f30ff17051bc9a7ae789439df8b9e9..1ff722a6079883a043109e26dea8d6b3fb405000 100755 --- a/tools/task_plots/plot_tasks.py +++ b/tools/task_plots/plot_tasks.py @@ -176,7 +176,6 @@ TASKTYPES = [ "grav_mesh", "cooling", "star_formation", - "sourceterms", "logger", "stars_ghost_in", "stars_ghost",