diff --git a/AUTHORS b/AUTHORS index 7cbdaffcf7813aae0488a4f284c789cf6f3e30d9..3bbcc3c251d52bfcf372e807e9e5c3d02ea30ca5 100644 --- a/AUTHORS +++ b/AUTHORS @@ -12,3 +12,4 @@ Stefan Arridge stefan.arridge@durham.ac.uk Josh Borrow joshua.borrow@durham.ac.uk Loic Hausammann loic.hausammann@epfl.ch Yves Revaz yves.revaz@epfl.ch +Jacob Kegerreis jacob.kegerreis@durham.ac.uk diff --git a/configure.ac b/configure.ac index b30e9c41d7323a84a1838d68bdf60d1fee6f00c7..714be8b97a4c8173d53131e25fe3212b8059b82c 100644 --- a/configure.ac +++ b/configure.ac @@ -54,6 +54,19 @@ AX_COMPILER_VERSION # Restrict support. AC_C_RESTRICT +# logger +AC_ARG_ENABLE([logger], + [AS_HELP_STRING([--enable-logger], + [enable the particle logger] + )], + [with_logger="${enableval}"], + [with_logger="no"] +) + +if test "$with_logger" = "yes"; then + AC_DEFINE([WITH_LOGGER], 1, [logger enabled]) +fi + # Interprocedural optimization support. Needs special handling for linking and # archiving as well as compilation with Intels, needs to be done before # libtool is configured (to use correct LD). @@ -878,6 +891,43 @@ if test "$with_hdf5" = "yes"; then fi AM_CONDITIONAL([HAVEPARALLELHDF5],[test "$have_parallel_hdf5" = "yes"]) +# Check for grackle. +have_grackle="no" +AC_ARG_WITH([grackle], + [AS_HELP_STRING([--with-grackle=PATH], + [root directory where grackle is installed @<:@yes/no@:>@] + )], + [with_grackle="$withval"], + [with_grackle="no"] +) +if test "x$with_grackle" != "xno"; then + AC_PROG_FC + AC_FC_LIBRARY_LDFLAGS + if test "x$with_grackle" != "xyes" -a "x$with_grackle" != "x"; then + GRACKLE_LIBS="-L$with_grackle/lib -lgrackle" + GRACKLE_INCS="-I$with_grackle/include" + else + GRACKLE_LIBS="-lgrackle" + GRACKLE_INCS="" + fi + + have_grackle="yes" + + echo $GRACKLE_LIBS + + AC_CHECK_LIB( + [grackle], + [initialize_chemistry_data], + [AC_DEFINE([HAVE_GRACKLE],1,[The GRACKLE library appears to be present.]) + AC_DEFINE([CONFIG_BFLOAT_8],1,[Use doubles in grackle]) + ], + [AC_MSG_ERROR(Cannot find grackle library!)], + [$GRACKLE_LIBS]) +fi +AC_SUBST([GRACKLE_LIBS]) +AC_SUBST([GRACKLE_INCS]) +AM_CONDITIONAL([HAVEGRACKLE],[test -n "$GRACKLE_LIBS"]) + # Check for VELOCIraptor. have_velociraptor="no" AC_ARG_WITH([velociraptor], @@ -910,6 +960,22 @@ fi AC_SUBST([VELOCIRAPTOR_LIBS]) AM_CONDITIONAL([HAVEVELOCIRAPTOR],[test -n "$VELOCIRAPTOR_LIBS"]) +# Check for dummy VELOCIraptor. +AC_ARG_ENABLE([dummy-velociraptor], + [AS_HELP_STRING([--enable-dummy-velociraptor], + [Enable dummy velociraptor compilation @<:@yes/no@:>@] + )], + [enable_dummy_velociraptor="$enableval"], + [enable_dummy_velociraptor="no"] +) + +if test "$enable_dummy_velociraptor" = "yes"; then + have_velociraptor="yes" + + AC_DEFINE(HAVE_VELOCIRAPTOR,1,[The VELOCIraptor library appears to be present.]) + AC_DEFINE(HAVE_DUMMY_VELOCIRAPTOR,1,[The dummy VELOCIraptor library is present.]) +fi + # Check for floating-point execeptions AC_CHECK_FUNC(feenableexcept, AC_DEFINE([HAVE_FE_ENABLE_EXCEPT],[1], [Defined if the floating-point exception can be enabled using non-standard GNU functions.])) @@ -1305,43 +1371,6 @@ case "$with_riemann" in AC_MSG_ERROR([Unknown Riemann solver: $with_riemann]) ;; esac - -# Check for grackle. -have_grackle="no" -AC_ARG_WITH([grackle], - [AS_HELP_STRING([--with-grackle=PATH], - [root directory where grackle is installed @<:@yes/no@:>@] - )], - [with_grackle="$withval"], - [with_grackle="no"] -) -if test "x$with_grackle" != "xno"; then - AC_PROG_FC - AC_FC_LIBRARY_LDFLAGS - if test "x$with_grackle" != "xyes" -a "x$with_grackle" != "x"; then - GRACKLE_LIBS="-L$with_grackle/lib -lgrackle" - GRACKLE_INCS="-I$with_grackle/include" - else - GRACKLE_LIBS="-lgrackle" - GRACKLE_INCS="" - fi - - have_grackle="yes" - - AC_CHECK_LIB( - [grackle], - [initialize_chemistry_data], - [AC_DEFINE([HAVE_GRACKLE],1,[The GRACKLE library appears to be present.]) - AC_DEFINE([CONFIG_BFLOAT_8],1,[Use doubles in grackle]) - ], - [AC_MSG_ERROR(Cannot find grackle library!)], - [$GRACKLE_LIBS $GRACKLE_INCS $FCLIBS] - ) -fi -AC_SUBST([GRACKLE_LIBS]) -AC_SUBST([GRACKLE_INCS]) -AM_CONDITIONAL([HAVEGRACKLE],[test -n "$GRACKLE_LIBS"]) - # Cooling function AC_ARG_WITH([cooling], [AS_HELP_STRING([--with-cooling=<function>], @@ -1369,6 +1398,9 @@ case "$with_cooling" in const-lambda) AC_DEFINE([COOLING_CONST_LAMBDA], [1], [Const Lambda cooling function]) ;; + compton) + AC_DEFINE([COOLING_COMPTON], [1], [Compton cooling off the CMB]) + ;; grackle) AC_DEFINE([COOLING_GRACKLE], [1], [Cooling via the grackle library]) AC_DEFINE([COOLING_GRACKLE_MODE], [0], [Grackle chemistry network, mode 0]) @@ -1486,7 +1518,7 @@ esac # External potential AC_ARG_WITH([ext-potential], [AS_HELP_STRING([--with-ext-potential=<pot>], - [external potential @<:@none, point-mass, point-mass-ring, point-mass-softened, isothermal, softened-isothermal, disc-patch, sine-wave, default: none@:>@] + [external potential @<:@none, point-mass, point-mass-ring, point-mass-softened, isothermal, softened-isothermal, nfw, hernquist, disc-patch, sine-wave, default: none@:>@] )], [with_potential="$withval"], [with_potential="none"] @@ -1501,6 +1533,12 @@ case "$with_potential" in isothermal) AC_DEFINE([EXTERNAL_POTENTIAL_ISOTHERMAL], [1], [Isothermal external potential]) ;; + hernquist) + AC_DEFINE([EXTERNAL_POTENTIAL_HERNQUIST], [1], [Hernquist external potential]) + ;; + nfw) + AC_DEFINE([EXTERNAL_POTENTIAL_NFW], [1], [Navarro-Frenk-White external potential]) + ;; disc-patch) AC_DEFINE([EXTERNAL_POTENTIAL_DISC_PATCH], [1], [Disc-patch external potential]) ;; @@ -1556,8 +1594,9 @@ AC_CONFIG_FILES([tests/testFormat.sh], [chmod +x tests/testFormat.sh]) # Save the compilation options AC_DEFINE_UNQUOTED([SWIFT_CONFIG_FLAGS],["$swift_config_flags"],[Flags passed to configure]) -# Make sure the latest git revision string gets included -touch src/version.c +# Make sure the latest git revision string gets included, when we are +# working in a checked out repository. +test -d ${srcdir}/.git && touch ${srcdir}/src/version.c # Need to define this, instead of using fifth argument of AC_INIT, until # 2.64. Defer until now as this redefines PACKAGE_URL, which can emit a @@ -1589,6 +1628,7 @@ AC_MSG_RESULT([ CPU profiler : $have_profiler Pthread barriers : $have_pthread_barrier VELOCIraptor enabled : $have_velociraptor + Particle Logger : $with_logger Hydro scheme : $with_hydro Dimensionality : $with_dimension diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index cba52250ccc37f50ed130c70d8a5039d8c786474..d2dd87257ea7da2b78bfe0503870112b830ee22c 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -761,11 +761,15 @@ WARN_LOGFILE = INPUT = @top_srcdir@ @top_srcdir@/src @top_srcdir@/tests @top_srcdir@/examples INPUT += @top_srcdir@/src/hydro/Minimal +INPUT += @top_srcdir@/src/hydro/Gadget2 INPUT += @top_srcdir@/src/gravity/Default INPUT += @top_srcdir@/src/stars/Default INPUT += @top_srcdir@/src/riemann INPUT += @top_srcdir@/src/potential/point_mass INPUT += @top_srcdir@/src/equation_of_state/ideal_gas +INPUT += @top_srcdir@/src/cooling/const_du +INPUT += @top_srcdir@/src/cooling/const_lambda +INPUT += @top_srcdir@/src/cooling/Compton INPUT += @top_srcdir@/src/cooling/EAGLE INPUT += @top_srcdir@/src/chemistry/EAGLE diff --git a/doc/RTD/source/CommandLineOptions/index.rst b/doc/RTD/source/CommandLineOptions/index.rst new file mode 100644 index 0000000000000000000000000000000000000000..a8ce7af082fd7b2bf3ec285b5bb0b2b5bb509401 --- /dev/null +++ b/doc/RTD/source/CommandLineOptions/index.rst @@ -0,0 +1,43 @@ +.. Command line options + Matthieu Schaller, 21st October 2018 + +.. _cmdline-options: + +Command line options +==================== + +SWIFT requires a number of runtime options to run and get any sensible output. +For instance, just running the ``swift`` binary will not use any SPH or gravity; +the particles will just sit still! + +Below is a list of the command line options and when they should be used. The same list +can be found by typing ``./swift -h``. + ++ ``-a``: Pin runners using processor affinity. ++ ``-c``: Run with cosmological time integration. ++ ``-C``: Run with cooling. ++ ``-d``: Dry run. Read the parameter file, allocate memory but does not read + the particles from ICs and exit before the start of time integration. Allows + user to check validity of parameter and IC files as well as memory limits. ++ ``-D``: Always drift all particles even the ones far from active particles. + This emulates Gadget-[23] and GIZMO's default behaviours. ++ ``-e``: Enable floating-point exceptions (debugging mode). ++ ``-f``: {int} Overwrite the CPU frequency (Hz) to be used for time measurements. ++ ``-g``: Run with an external gravitational potential. ++ ``-G``: Run with self-gravity. ++ ``-M``: Reconstruct the multipoles every time-step. ++ ``-n``: {int} Execute a fixed number of time steps. When unset use the + time_end parameter to stop. ++ ``-o``: {str} Generate a default output parameter file. ++ ``-P``: {sec:par:val} Set parameter value and overwrites values read from the + parameters file. Can be used more than once. ++ ``-s``: Run with hydrodynamics. ++ ``-S``: Run with stars. ++ ``-t``: {int} The number of threads to use on each MPI rank. Defaults to 1 if + not specified. ++ ``-T``: Print timers every time-step. ++ ``-v``: [12] Increase the level of verbosity: 1, MPI-rank 0 writes, 2, All + MPI-ranks write. ++ ``-y``: {int} Time-step frequency at which task graphs are dumped. ++ ``-Y``: {int} Time-step frequency at which threadpool tasks are dumped. ++ ``-h``: Print a help message and exit. diff --git a/doc/RTD/source/Cooling/index.rst b/doc/RTD/source/Cooling/index.rst index 46a01b2a054629b7fc13f0ea190c2a5a0fdd6d9c..0ca3f62f3ca6fdff2abb95501681dc7bf4676fd2 100644 --- a/doc/RTD/source/Cooling/index.rst +++ b/doc/RTD/source/Cooling/index.rst @@ -45,6 +45,19 @@ to provide an HDF5 table computed by Cloudy. When starting a simulation without providing the different fractions, the code supposes an equilibrium and computes the fractions automatically. +In order to compile SWIFT with Grackle, you need to provide the options ``with-grackle`` +and ``with-chemistry``. + +You will need a Grackle version later than 3.1. To compile it, run +the following commands from the root directory of Grackle: +``./configure; cd src/clib``. +Update the variables ``LOCAL_HDF5_INSTALL`` and ``MACH_INSTALL_PREFIX`` in +the file ``src/clib/Make.mach.linux-gnu``. +Finish with ``make machine-linux-gnu; make && make install``. +If you encounter any problem, you can look at the `Grackle documentation <https://grackle.readthedocs.io/en/latest/>`_ + +You can now provide the path given for ``MACH_INSTALL_PREFIX`` to ``with-grackle``. + Eagle ~~~~~ diff --git a/doc/RTD/source/ExternalPotentials/index.rst b/doc/RTD/source/ExternalPotentials/index.rst new file mode 100644 index 0000000000000000000000000000000000000000..e3138162465c200ec71d7d31b02c575e3e663416 --- /dev/null +++ b/doc/RTD/source/ExternalPotentials/index.rst @@ -0,0 +1,80 @@ +.. External potentials in SWIFT + Folkert Nobels, 25th October 2018 + +External Potentials +=================== + +SWIFT can be run with an external potential on this page we will summarize the +current potentials which can be run with SWIFT and how to implement your own +potential in SWIFT. + +Implemented External Potentials +------------------------------- + +Currently there are several potentials implemented in SWIFT. On this page we +give a short overview of the potentials that are implemented in the code: + +1. No potential (none) +2. Point mass potential (point-mass): classical point mass, can be placed at + a position with a mass. +3. Plummer potential (point-mass-softened): in the code a softended point mass + corresponds to a Plummer potential, can be placed at a position with a mass. +4. Isothermal potential (isothermal): An isothermal potential which corresponds + to a density profile which is :math:`\propto r^{-2}` and a potential which is + logarithmic. This potential has as free parameters the rotation velocity + and the position. +5. Hernquist potential (hernquist): A potential that is given by the Hernquist + potential: + + :math:`\Phi(r) = - \frac{GM}{r+a}.` + + The free paramters of Hernquist potential are mass, scale length, + and softening. The potential can be set at any position in the box. +6. NFW potential (nfw): The most used potential to describe dark matter halos, the + potential is given by: + + :math:`\Phi(r) = - \frac{4\pi G \rho_0 R_s^3}{r} \ln \left( 1+ + \frac{r}{R_s} \right).` + + This potential has as free paramters the concentration of the DM halo, the + virial mass (:math:`M_{200}`) and the critical density. +7. Sine wave (sine-wave) +8. Point mass ring (point-mass-ring) +9. Disc Patch (disc-patch) + + +How to implement your own potential +----------------------------------- + +The first step in implementing your own potential is making a directory of your +potential in the ``src/potential`` folder and creating a file in the folder +called ``potential.h``. + +Configuring the potential +^^^^^^^^^^^^^^^^^^^^^^^^^ + +To get started you can copy a ``potential.h`` file from an already implemented +potential. In this potential the header guards (e.g. ``#IFDEF <>``) need to be +changed to the specific potential and the ``struct`` and +``potential_init_backend`` need to be changed such that it uses your potential +and reads the correct potential from the parameter file during running the +program. + +Add the potential to the ``potential.h`` file in the ``src`` directory such that +the program knows that it is possible to run with this potential. + +Furthermore during the configuration of the code it also needs to be clear for +the program that the code can be configured to run with the different +potentials. This means that the ``configure.ac`` file needs to be changed. +This can be done to add an other case in the potential:: + + case "$with_potential" in + none) + AC_DEFINE([EXTERNAL_POTENTIAL_NONE], [1], [No external potential]) + ;; + newpotential) + AC_DEFINE([EXTERNAL_POTENTIAL_NEWPOTENTIAL], [1], [New external potential]) + ;; + +After this change it is possible to configure the code to use your new potential. + diff --git a/doc/RTD/source/GettingStarted/index.rst b/doc/RTD/source/GettingStarted/index.rst index 36de8ea740490c16bc9d6b69d871290e80dc2091..2086bcfb4af0ac1b7bbc24c34caa85fa1ebec498 100644 --- a/doc/RTD/source/GettingStarted/index.rst +++ b/doc/RTD/source/GettingStarted/index.rst @@ -20,7 +20,6 @@ and keep on your desk. running_example runtime_options configuration_options - parameter_file what_about_mpi running_on_large_systems special_modes diff --git a/doc/RTD/source/GettingStarted/running_example.rst b/doc/RTD/source/GettingStarted/running_example.rst index 854e74cf830d58e51cf866d59a93ede6dceb57b6..7c9e333ca971ec73f3c2e25b56cc8e1381385567 100644 --- a/doc/RTD/source/GettingStarted/running_example.rst +++ b/doc/RTD/source/GettingStarted/running_example.rst @@ -19,14 +19,14 @@ as ``wget`` for grabbing the glass). This will run the 'SodShock' in 3D and produce a nice plot that shows you -how the density has varied. Try running with GIZMO (this will take +how the density has varied. Try running with GIZMO-MFV (this will take _significantly_ longer than with SPH) to see the difference. For that, you will need to reconfigure with the following options: .. code-block:: bash ./configure \ - --with-hydro=gizmo \ + --with-hydro=gizmo-mfv \ --with-riemann-solver=hllc diff --git a/doc/RTD/source/GettingStarted/runtime_options.rst b/doc/RTD/source/GettingStarted/runtime_options.rst index b2ca10640d8830b9b5ecb8e117bf047af738889c..fdd2c1233cc09cc3a46c8eb2e38efb10729a2950 100644 --- a/doc/RTD/source/GettingStarted/runtime_options.rst +++ b/doc/RTD/source/GettingStarted/runtime_options.rst @@ -8,34 +8,5 @@ SWIFT requires a number of runtime options to run and get any sensible output. For instance, just running the ``swift`` binary will not use any SPH or gravity; the particles will just sit still! -Below is a list of the runtime options and when they should be used. The same list -can be found by typing ``./swift -h``. +A list of available command line options can be found on the :ref:`cmdline-options` page. -+ ``-a``: Pin runners using processor affinity. -+ ``-c``: Run with cosmological time integration. -+ ``-C``: Run with cooling. -+ ``-d``: Dry run. Read the parameter file, allocate memory but does not read - the particles from ICs and exit before the start of time integration. Allows - user to check validity of parameter and IC files as well as memory limits. -+ ``-D``: Always drift all particles even the ones far from active particles. - This emulates Gadget-[23] and GIZMO's default behaviours. -+ ``-e``: Enable floating-point exceptions (debugging mode). -+ ``-f``: {int} Overwrite the CPU frequency (Hz) to be used for time measurements. -+ ``-g``: Run with an external gravitational potential. -+ ``-G``: Run with self-gravity. -+ ``-M``: Reconstruct the multipoles every time-step. -+ ``-n``: {int} Execute a fixed number of time steps. When unset use the - time_end parameter to stop. -+ ``-o``: {str} Generate a default output parameter file. -+ ``-P``: {sec:par:val} Set parameter value and overwrites values read from the - parameters file. Can be used more than once. -+ ``-s``: Run with hydrodynamics. -+ ``-S``: Run with stars. -+ ``-t``: {int} The number of threads to use on each MPI rank. Defaults to 1 if - not specified. -+ ``-T``: Print timers every time-step. -+ ``-v``: [12] Increase the level of verbosity: 1, MPI-rank 0 writes, 2, All - MPI-ranks write. -+ ``-y``: {int} Time-step frequency at which task graphs are dumped. -+ ``-Y``: {int} Time-step frequency at which threadpool tasks are dumped. -+ ``-h``: Print a help message and exit. diff --git a/doc/RTD/source/HydroSchemes/hopkins_sph.rst b/doc/RTD/source/HydroSchemes/hopkins_sph.rst index bcc51e0ad96b18956f1c8e54f7bf2bf3b352c138..e4f1479230df96eabaa1fe16994960059858613b 100644 --- a/doc/RTD/source/HydroSchemes/hopkins_sph.rst +++ b/doc/RTD/source/HydroSchemes/hopkins_sph.rst @@ -28,3 +28,9 @@ scheme it includes a Monaghan AV scheme and a Balsara switch. .. code-block:: bash ./configure --with-hydro="pressure-energy" + +Both of the above schemes use a very simple, fixed artificial viscosity, only +the ``SPH:viscosity_alpha`` parameter has any effect for this scheme. This will +change the strength of the artificial viscosity throughout the simulation, and +has a default of 0.8. + diff --git a/doc/RTD/source/HydroSchemes/minimal_sph.rst b/doc/RTD/source/HydroSchemes/minimal_sph.rst index 1a16a23360aaba8b28920150af0d4f4b05c74c2f..bbcbe026b56381c007f58920f31115f9f9160d05 100644 --- a/doc/RTD/source/HydroSchemes/minimal_sph.rst +++ b/doc/RTD/source/HydroSchemes/minimal_sph.rst @@ -10,11 +10,17 @@ Minimal (Density-Energy) SPH :caption: Contents: This scheme is a textbook implementation of Density-Energy SPH, and can be used -as a pedagogical example. It also implements a Monaghan AV scheme, like the -GADGET-2 scheme. It uses very similar equations, but differs in implementation -details; namely it tracks the internal energy \(u\) as the thermodynamic -variable, rather than entropy \(A\). To use the minimal scheme, use +as a pedagogical example. It also implements a Monaghan AV scheme with a +Balsara switch, like the GADGET-2 scheme. It uses very similar equations, but +differs in implementation details; namely it tracks the internal energy \(u\) +as the thermodynamic variable, rather than entropy \(A\). To use the minimal +scheme, use .. code-block:: bash ./configure --with-hydro="minimal" + +As it uses a very simple, fixed artificial viscosity, only the +``SPH:viscosity_alpha`` parameter has any effect for this scheme. This will +change the strength of the artificial viscosity throughout the simulation, +and has a default of 0.8. diff --git a/doc/RTD/source/HydroSchemes/traditional_sph.rst b/doc/RTD/source/HydroSchemes/traditional_sph.rst index c69ea5f60644119b8590414ffe00a75246de49a6..455e8bebe516bd9be9f6df889f1ead2088ca94d2 100644 --- a/doc/RTD/source/HydroSchemes/traditional_sph.rst +++ b/doc/RTD/source/HydroSchemes/traditional_sph.rst @@ -15,3 +15,8 @@ a Monaghan artificial viscosity scheme and Balsara switch. To use this hydro scheme, you need no extra configuration options -- it is the default! +As it uses a very simple, fixed artificial viscosity, only the +``SPH:viscosity_alpha`` parameter has any effect for this scheme. This will +change the strength of the artificial viscosity throughout the simulation, +and has a default of 0.8. + diff --git a/doc/RTD/source/InitialConditions/index.rst b/doc/RTD/source/InitialConditions/index.rst index 19ead066c4efb799e6587884a952baf488f794bf..00e7b98c5916a29b31d9396c317dfc2851d7389b 100644 --- a/doc/RTD/source/InitialConditions/index.rst +++ b/doc/RTD/source/InitialConditions/index.rst @@ -117,15 +117,6 @@ GADGET-2 based analysis programs: + ``Time``, time of the start of the simulation in internal units or expressed as a scale-factor for cosmological runs. SWIFT ignores this and reads it from the parameter file. - -RuntimePars -~~~~~~~~~~~ - -In the ``/RuntimePars/``, the following attributes are required: - -+ ``PeriodicBoundariesOn``, a flag to tell the code whether or not you - have periodic boundaries switched on. Again, this is historical; it should be - set to 1 (default) if you have the code running in periodic mode, or 0 otherwise. Particle Data @@ -145,7 +136,7 @@ individual particle type (e.g. ``/PartType0/``) that have the following *dataset velocities divided by ``sqrt(a)`` (see below for a fix). + ``ParticleIDs``, an array of length N that are unique identifying numbers for each particle. Note that these have to be unique to a particle, and cannot be - the same even between particle types. The **IDs must be >1**. 0 or negative + the same even between particle types. The **IDs must be >= 0**. Negative IDs will be rejected by the code. + ``Masses``, an array of length N that gives the masses of the particles. @@ -176,7 +167,9 @@ as peculiar velocities divided by ``sqrt(a)``. This can be undone by swicthing on the parameter ``InitialConditions:cleanup_velocity_factors`` in the :ref:`Parameter_File_label`. - + +.. _ICs_units_label: + Optional Components ------------------- @@ -214,8 +207,6 @@ You should have an HDF5 file with the following structure: Flag_Entropy_ICs=0 NumPart_Total=[0, 1, 0, 0, 4, 5] NumPart_Total_HighWord=[0, 0, 0, 0, 0, 0] - RuntimePars/ - PeriodicBoundariesOn=1 Units/ Unit current in cgs (U_I)=1.0 Unit length in cgs (U_L)=1.0 diff --git a/doc/RTD/source/NewOption/index.rst b/doc/RTD/source/NewOption/index.rst index a7445524017fefd99d76c80a4a1ecc646874bd7a..441cd860ed79dabad2005b39ae4549d1496ab98d 100644 --- a/doc/RTD/source/NewOption/index.rst +++ b/doc/RTD/source/NewOption/index.rst @@ -1,4 +1,4 @@ -.. Equation of State +.. Adding new schemes Loic Hausammann, 7th April 2018 .. _new_option: diff --git a/doc/RTD/source/ParameterFiles/index.rst b/doc/RTD/source/ParameterFiles/index.rst new file mode 100644 index 0000000000000000000000000000000000000000..ae5451d71bf3e52e2b8c4bc5c202b930d665ce0a --- /dev/null +++ b/doc/RTD/source/ParameterFiles/index.rst @@ -0,0 +1,378 @@ +.. Parameter Files + Matthieu Schaller, 21st October 2018 + +Parameter Files +=============== + +File format and basic information +--------------------------------- + +The parameter file uses a format similar to the `YAML format +<https://en.wikipedia.org/wiki/YAML>`_ but reduced to only the +elements required for the SWIFT parameters. Options are given by a +name followed by a column and the value of the parameter: + +.. code:: YAML + + ICs: santa_barbara.hdf5 + dt_max: 1.5 + shift: [2., 4., 5.] + +Comments can be inserted anywhere and start with a hash: + +.. code:: YAML + + # Descrption of the physics + viscosity_alpha: 2.0 + dt_max: 1.5 # seconds + +A typical SWIFT parameter file is split into multiple sections that +may or may not be present depending on the different configuration +options. The sections start with a label and can contain any number of +parameters: + +.. code:: YAML + + Cosmology: # Planck13 + Omega_m: 0.307 + Omega_lambda: 0.693 + Omega_b: 0.0455 + h: 0.6777 + a_begin: 0.0078125 # z = 127 + +The options can be integer values, floating point numbers, characters +or strings. If SWIFT expects a number and string is given, an error +will be raised. The code can also read an array of values: + +.. code:: YAML + + shift: [2., 4., 5.] + +Some options in the parameter file are optional and +when not provided, SWIFT will run with the default value. However, if +a compulsory parameter is missing an error will be raised at +start-up. + +Finally, SWIFT outputs two YAML files at the start of a run. The first +one ``used_parameters.yml`` contains all the parameters that were used +for this run, **including all the optional parameters with their +default values**. This file can be used to start an exact copy of the +run. The second file, ``unused_parameters.yml`` contains all the +values that were not read from the parameter file. This can be used to +simplify the parameter file or check that nothing important was +ignored (for instance because the code is not configured to use some +options). + +The rest of this page describes all the SWIFT parameters, split by +section. A list of all the possible parameters is kept in the file +``examples/parameter_examples.yml``. + +Internal Unit System +-------------------- + +This section describes the units used internally by the code. This is +the system of units in which all the equations are solved. All +physical constants are converted to this system and if the ICs use a +different system (see :ref:`ICs_units_label`) the particle quantities +will be converted when read in. + +The system of units is described using the value of the 5 basic units +of any system with respect to the CGS system. Instead of using a unit +of time we use a unit of velocity as this is more intuitive. Users +hence need to provide: + +* a unit of length: ``UnitLength_in_cgs``, +* a unit of mass: ``UnitMass_in_cgs``, +* a unit of velocity ``UnitVelocity_in_cgs``, +* a unit of electric current ``UnitCurrent_in_cgs``, +* a unit of temperature ``UnitTemp_in_cgs``. + +All these need to be expressed with respect to their cgs counter-part +(i.e. :math:`cm`, :math:`g`, :math:`cm/s`, :math:`A` and :math:`K`). Recall +that there are no h-factors in any of SWIFT's quantities; we, for instance, +use :math:`cm` and not :math:`cm/h`. + +For instance to use the commonly adopted system of 10^10 Msun as a +unit for mass, mega-parsec as a unit of length and km/s as a unit of +speed, we would use: + +.. code:: YAML + + # Common unit system for cosmo sims + InternalUnitSystem: + UnitMass_in_cgs: 1.98848e43 # 10^10 M_sun in grams + UnitLength_in_cgs: 3.08567758e24 # 1 Mpc in centimeters + UnitVelocity_in_cgs: 1e5 # 1 km/s in centimeters per second + UnitCurrent_in_cgs: 1 # 1 Ampere + UnitTemp_in_cgs: 1 # 1 Kelvin + +Note that there are currently no variables in any of the SWIFT physics +schemes that make use of the unit of electric current. There is also +no incentive to use anything else than Kelvin but that makes the whole +system consistent with any possible unit system. + +If one is interested in using the more humourous `FFF unit +system <https://en.wikipedia.org/wiki/FFF_system>`_ one would use + +.. code:: YAML + + # FFF unit system + InternalUnitSystem: + UnitMass_in_cgs: 40823.3133 # 1 Firkin (fir) in grams + UnitLength_in_cgs: 20116.8 # 1 Furlong (fur) in cm + UnitVelocity_in_cgs: 0.01663095 # 1 Furlong (fur) per Fortnight (ftn) in cm/s + UnitCurrent_in_cgs: 1 # 1 Ampere + UnitTemp_in_cgs: 1 # 1 Kelvin + +The value of the physical constants in this system is left as an +exercise for the reader [#f1]_. + +Cosmology +--------- + +When running a cosmological simulation, this section set the values of the +cosmological model. The epanded :math:`\Lambda\rm{CDM}` parameters governing the +background evolution of the Univese need to be specified here. These are: + +* The reduced Hubble constant: :math:`h`: ``h``, +* The matter density parameter :math:`\Omega_m`: ``Omega_m``, +* The cosmological constant density parameter :math:`\Omega_\Lambda`: ``Omega_lambda``, +* The baryon density parameter :math:`\Omega_b`: ``Omega_b``, +* The radiation density parameter :math:`\Omega_r`: ``Omega_r``. + +The last parameter can be omitted and will default to :math:`\Omega_r = 0`. + +This section als specifies the start and end of the simulation expressed in +terms of scale-factors. The two parameters are: + +* Initial scale-factor: ``a_begin``, +* Final scale-factor: ``a_end``. + +Two additional optional parameters can be used to change the equation of +state of dark energy :math:`w(a)`. We use the evolution law :math:`w(a) = +w_0 + w_a (1 - a)`. The two parameters in the YAML file are: + +* The :math:`z=0` dark energy equation of state parameter :math:`w_0`: ``w_0`` +* The dark energy equation of state evolutio parameter :math:`w_a`: ``w_a`` + +If unspecified these parameters default to the default +:math:`\Lambda\rm{CDM}` values of :math:`w_0 = -1` and :math:`w_a = 0`. + +For a Planck+13 cosmological model (ignoring radiation density as is +commonly done) and running from :math:`z=127` to :math:`z=0`, one would hence +use the following parameters: + +.. code:: YAML + + Cosmology: + a_begin: 0.0078125 # z = 127 + a_end: 1.0 # z = 0 + h: 0.6777 + Omega_m: 0.307 + Omega_lambda: 0.693 + Omega_b: 0.0455 + Omega_r: 0. # (Optional) + w_0: -1.0 # (Optional) + w_a: 0. # (Optional) + +When running a non-cosmological simulation (i.e. without the ``-c`` runtime +flag) this section of the YAML file is entirely ignored. + +Gravity +------- + +The behaviour of the self-gravity solver can be modifed by the parameters +provided in this section. The theory document puts these parameters into the +context of the equations being solved. We give a brief overview here. + +* The Plummer-equivalent co-moving softening length used for all particles :math:`\epsilon_{com}`: ``comoving_softening``, +* The Plummer-equivalent maximal physical softening length used for all particles :math:`\epsilon_{max}`: ``comoving_softening``, + +At any redshift :math:`z`, the Plummer-equivalent softening length used by the +code will be :math:`\epsilon=\min(\epsilon_{max}, +\frac{\epsilon_{com}}{z+1})`. This is expressed in internal units. + +* The opening angle (multipole acceptance criterion) used in the FMM :math:`\theta`: ``theta``, +* The time-step size pre-factor :math:`\eta`: ``eta``, + +The time-step of a given particle is given by :math:`\Delta t = +\eta\sqrt{\frac{\epsilon}{|\overrightarrow{a}|}}`, where +:math:`\overrightarrow{a}` is the particle's acceleration. Power et al. (2003) recommend using :math:`\eta=0.025`. +The last tree-related parameter is + +* The tree rebuild frequency: ``rebuild_frequency``. + +Thqe tree rebuild frequency is an optional parameter defaulting to +:math:`0.01`. It is used to trigger the re-construction of the tree every time a +fraction of the particles have been integrated (kicked) forward in time. + +Simulations using periodic boundary conditions use additional parameters for the +Particle-Mesh part of the calculation. The last three are optional: + +* The number cells along each axis of the mesh :math:`N`: ``mesh_side_length``, +* The mesh smoothing scale in units of the mesh cell-size :math:`a_{\rm + smooth}`: ``a_smooth`` (default: ``1.25``), +* The scale above which the short-range forces are assumed to be 0 (in units of + the mesh cell-size multiplied by :math:`a_{\rm smooth}`) :math:`r_{\rm + cut,max}`: ``r_cut_max`` (default: ``4.5``), +* The scale bewlo which the short-range forces are assumed to be exactly Newtonian (in units of + the mesh cell-size multiplied by :math:`a_{\rm smooth}`) :math:`r_{\rm + cut,min}`: ``r_cut_min`` (default: ``0.1``), + +For most runs, the default values can be used. Only the number of cells along +each axis needs to be sepcified. The remaining three values are best described +in the context of the full set of equations in the theory documents. + +As a summary, here are the values used for the EAGLE :math:`100^3~{\rm Mpc}^3` +simulation: + +.. code:: YAML + + # Parameters for the self-gravity scheme for the EAGLE-100 box + Gravity: + eta: 0.025 + theta: 0.7 + comoving_softening: 0.0026994 # 0.7 proper kpc at z=2.8. + max_physical_softening: 0.0007 # 0.7 proper kpc + rebuild_frequency: 0.01 # Default optional value + mesh_side_length: 512 + a_smooth: 1.25 # Default optional value + r_cut_max: 4.5 # Default optional value + r_cut_min: 0.1 # Default optional value + + + +SPH +--- + +Time Integration +---------------- + +Physical Constants +------------------ + +For some idealised test it can be useful to overwrite the value of +some physical constants; in particular the value of the gravitational +constant. SWIFT offers an optional parameter to overwrite the value of +:math:`G_N`. + +.. code:: YAML + + PhysicalConstants: + G: 1 + +Note that this set :math:`G` to the specified value in the internal system +of units. Setting a value of `1` when using the system of units (10^10 Msun, +Mpc, km/s) will mean that :math:`G_N=1` in these units [#f2]_ instead of the +normal value :math:`G_N=43.00927`. + +This option is only used for specific tests and debugging. This entire +section of the YAML file can typically be left out. More constants may +be handled in the same way in future versions. + +Snapshots +--------- + +Some additional specific options for the snapshot outputs are described in the +following pages: + +.. toctree:: + :maxdepth: 1 + + output_selection + +Statistics +---------- + +Restarts +-------- + +SWIFT can write check-pointing files and restart from them. The behaviour of +this mechanism is driven by the options int he `Restarts` section of the YAML +parameter file. All the parameters are optional but default to values that +ensure a reasonable behaviour. + +* Wether or not to enable the dump of restart files: ``enable`` (default: + ``1``). + +This parameter acts a master-switch for the check-pointing capabilities. All the +other options require the ``enable`` parameter to be set to ``1``. + +* Wether or not to save a copy of the previous set of check-pointing files: + ``save`` (default: ``1``), +* Wether or not to dump a set of restart file on regular exit: ``onexit`` + (default: ``0``), +* The wall-clock time in hours between two sets of restart files: + ``delta_hours`` (default: ``6.0``). + +Note that there is no buffer time added to the ``delta_hours`` value. If the +system's batch queue run time limit is set to 6 hours, the user must specify a +smaller value to allow for enough time to safely dump the check-point files. + +* The sub-directory in which to store the restart files: ``subdir`` (default: + ``restart``), +* The basename of the restart files: ``basename`` (default: ``swift``) + +If the directory does not exist, SWIFT will create it. When resuming a run, +SWIFT, will look for files with the name provided in the sub-directory specified +here. The files themselves are named ``basename_000001.rst`` where the basenme +is replaced by the user-specified name and the 6-digits number corresponds to +the MPI-rank. SWIFT writes one file per MPI rank. If the ``save`` option has +been activated, the previous set of restart files will be named +``basename_000000.rst.prev``. + +SWIFT can also be stopped by creating an empty file called ``stop`` in the +directory where the code runs. This will make SWIFT dump a fresh set of restart +file (irrespective of the specified ``delta_time`` between dumps) and exit +cleanly. One parameter governs this behaviour: + +* Number of steps between two checks for the presence of a ``stop`` file: + ``stop_steps`` (default: ``100``). + +The default value is chosen such that SWIFT does not need to poll the +file-system to often, which can take a significant amount of time on distributed +systems. For runs where the small time-steps take a much larger amount of time, +a smaller value is recommended to allow for a finer control over when the code +can be stopped. + +Finally, SWIFT can automatically stop after a specified amount of wall-clock +time. The code can also run a command when exiting in this fashion, which can be +used, for instance, to interact with the batch queue system: + +* Maximal wall-clock run time in hours: ``max_run_time`` (default: ``24.0``), +* Whether or not to run a command on exit: ``resubmit_on_exit`` (default: + ``0``), +* The command to run on exit: ``resubmit_command`` (default: ``./resub.sh``). + +Note that no check is performed on the validity of the command to run. SWIFT +simply calls ``system()`` with the user-specified command. + +To run SWIFT, dumping check-pointing files every 6 hours and running for 24 +hours after which a shell command will be run, one would use: + +.. code:: YAML + + Restarts: + enable: 1 + save: 1 # Keep copies + onexit: 0 + subdir: restart # Sub-directory of the directory where SWIFT is run + basename: swift + delta_hours: 6.0 + stop_steps: 100 + max_run_time: 24.0 # In hours + resubmit_on_exit: 1 + resubmit_command: ./resub.sh + + + +Scheduler +--------- + +Domain Decomposition +-------------------- + +.. [#f1] The thorough reader (or overly keen SWIFT tester) would find that the speed of light is :math:`c=1.8026\times10^{12}\,\rm{fur}\,\rm{ftn}^{-1}`, Newton's contant becomes :math:`G_N=4.896735\times10^{-4}~\rm{fur}^3\,\rm{fir}^{-1}\,\rm{ftn}^{-2}` and Planck's constant turns into :math:`h=4.851453\times 10^{-34}~\rm{fur}^2\,\rm{fir}\,\rm{ftn}^{-1}`. + + +.. [#f2] which would translate into a constant :math:`G_N=1.5517771\times10^{-9}~cm^{3}\,g^{-1}\,s^{-2}` if expressed in the CGS system. diff --git a/doc/RTD/source/GettingStarted/parameter_file.rst b/doc/RTD/source/ParameterFiles/output_selection.rst similarity index 69% rename from doc/RTD/source/GettingStarted/parameter_file.rst rename to doc/RTD/source/ParameterFiles/output_selection.rst index 550040ed25ec307633d6fade81eced58ed65a254..ca905c5e613082cdf9de9db718bdd16c4a3c8951 100644 --- a/doc/RTD/source/GettingStarted/parameter_file.rst +++ b/doc/RTD/source/ParameterFiles/output_selection.rst @@ -1,23 +1,17 @@ .. Parameter File Loic Hausammann, 1 june 2018 -.. _Parameter_File_label: - -Parameter File -============== - -To run SWIFT, you will need to provide a ``yaml`` parameter file. An example is -given in ``examples/parameter_file.yml`` which should contain all possible -parameters. Each section in this file corresponds to a different option in -SWIFT and are not always required depending on the configuration options and -the run time parameters. +.. _Output_list_label: Output List ~~~~~~~~~~~ -In the sections ``Snapshots`` and ``Statistics``, you can specify the options ``output_list_on`` and ``output_list`` which receive an int and a filename. -The ``output_list_on`` enable or not the output list and ``output_list`` is the filename containing the output times. -With the file header, you can choose between writing redshifts, scale factors or times. +In the sections ``Snapshots`` and ``Statistics``, you can specify the +options ``output_list_on`` and ``output_list`` which receive an int +and a filename. The ``output_list_on`` enable or not the output list +and ``output_list`` is the filename containing the output times. With +the file header, you can choose between writing redshifts, scale +factors or times. Example of file containing with times (in internal units):: @@ -42,6 +36,8 @@ Example of file with redshift:: 10 5 +.. _Output_selection_label: + Output Selection ~~~~~~~~~~~~~~~~ diff --git a/doc/RTD/source/VELOCIraptorInterface/index.rst b/doc/RTD/source/VELOCIraptorInterface/index.rst new file mode 100644 index 0000000000000000000000000000000000000000..3ae17f04b9950d30d1484ac5117b65063b7739c6 --- /dev/null +++ b/doc/RTD/source/VELOCIraptorInterface/index.rst @@ -0,0 +1,24 @@ +.. VELOCIraptor Interface + Folkert Nobels, 8th October 2018 + +VELOCIraptor Interface +====================== + +This section includes information on the VELOCIraptor interface implemented in +SWIFT. There are mainly four subsection; the first section explains shortly +how VELOCIraptor works, the second subsection explains how to configure SWIFT +with VELOCIraptor, the third subsection explains how to configure a standalone +version of VELOCIraptor and the last subsection explains how the output format +of VELOCIraptor works. + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + whatis + stfwithswift + stfalone + output + + + diff --git a/doc/RTD/source/VELOCIraptorInterface/output.rst b/doc/RTD/source/VELOCIraptorInterface/output.rst new file mode 100644 index 0000000000000000000000000000000000000000..5a7073da17b733e9925ba885c67b4cf48ccd420f --- /dev/null +++ b/doc/RTD/source/VELOCIraptorInterface/output.rst @@ -0,0 +1,294 @@ +.. VELOCIraptor output + Folkert Nobels 12th of October + +VELOCIraptor Output +=================== + +.. toctree:: + :maxdepth: 2 + :hidden: + :caption: Contents: + +In general VELOCIraptor outputs six files per snapshot, of which 2 files are +for unbound particles specifically. In this part we will explain what is +inside the different files. + +Catalog_groups file +------------------- + +The first output file of VELOCIraptor is the ``.catalog_group`` file, +this file contains all the information that is group specific, and does not go +into depth of physical properties but only on numbers of particles and +group sizes, the interesting data in the ``.catalog_group`` files are: + ++ The ``group_size``: gives a list of all the halos and the number of particles + in the halo, this list is numbered from 0 until the number of groups minus + one. It is important that the groups are not ordered in any way [#order]_ ++ The ``Num_of_groups`` or ``Total_num_of_groups``: gives the total number of + groups in the snapshot. ++ The ``Offset`` list: This list gives the offset off the particles. In the + output of VELOCIraptor there is no file which has an ID for every particle + and a corresponding group, rather the particles are ordered according to in + which group they are. So if we want to access the particles in group 0, we + need to look at the particles from ``Offset[0]`` until ``Offset[1]`` in the + ``.catalog_particles`` hdf5 file. In general this means that for group N we + need to look at particles ``Offset[N]`` until ``Offset[N+1]``. ++ The ``Offset_unbound`` list: This list works exactly the same as the + ``Offset`` list only this list is for the gravitational unbound particles. + +Catalog_particles file +---------------------- + +The second file that is produced by VELOCIraptor is the ``.catalog_particles`` +file, this file contains mainly all the IDs of the particles and has two +interesting parameters: + ++ The ``Num_of_particles_in_groups`` and ``Num_of_particles_in_groups`` + parameter: Gives the total number of particles in the file or the total + number of particles that are in halos. ++ The ``Particle_IDs``: The list of particles as sorted by halo, in which halo + the individual particles are present can be found by using the + ``.catalog_group`` file and the corresponding ``Offset`` list. + +Besides the ``.catalog_particles`` file, there is also a +``.catalog_particles.unbound`` file, this file contains the same information +but only for the unbound particles, a particle can only be present in one of +these two lists. + +Catalog_parttypes file +---------------------- + +The third file that is produced by VELOCIraptor is the ``.catalog_parttypes`` +file, this file contains the information what type of particle every particle +is, it is ordered the same as the ``Particle_IDs`` in ``.catalog_particles``. +There are only two interesting parameters of the file which are: + ++ The ``Num_of_particles_in_groups`` parameter: Gives the total number of + particles in the file which are in a halo. ++ The ``Particle_types`` list: Gives a list of particles types similar to the + snap shots (0 - gas, 1 - dm, 4 - stars). + +Besides the ``.catalog_parttypes`` file, there is also a +``.catalog_parttypes.unbound`` file, this file contains this information for +the unbound particles. + +Properties file +--------------- + +The Fourth file is the ``.properties`` file, this file contains many physical +useful information of the corresponding halos. This can be divided in several +useful groups of physical parameters, on this page we have divided the several +variables which are present in the ``.properties`` file. This file has most +physical interesting parameters of the halos. + +Mass-Radius determination: +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The ``.properties`` file contains many ways to determine the size and mass +of the halos, in this subsection we will list several available variables in +the output of VELOCIraptor and we list several mass and radius parameters in +the output which are not classified as a mass-radius pair. + +Critical Density related: +""""""""""""""""""""""""" + ++ ``Mass_200crit``: The mass of a halo with an over density on average of + :math:`\Delta=200` based on the critical density of the Universe + (:math:`M_{200}`). ++ ``R_200crit``: The :math:`R_{200}` radius of the halo based on the + critical density of the Universe + +Mean Density related: +""""""""""""""""""""" + ++ ``Mass_200mean``: The mass of a halo with an over density on average of + :math:`\Delta=200` based on the mean density of the Universe + (:math:`M_{200}`). ++ ``R_200mean``: The :math:`R_{200}` radius of the halo based on the + mean density ofthe Universe. + +Virial properties: +"""""""""""""""""" + ++ ``Mvir``: The virial mass of the halos. ++ ``Rvir``: The virial radius of the halo (:math:`R_{vir}`). + +Bryan and Norman 1998 properties: +""""""""""""""""""""""""""""""""" + ++ ``Mass_BN98``, The Bryan and Norman (1998) determination of the mass of the + halo [#BN98]_. ++ ``R_BN98``, the Bryan and Norman (1998) corresponding radius[#BN98]_. + +Several Mass types: +""""""""""""""""""" +This is a list of masses which cannot be categorized as easy as the other +properties. + ++ ``Mass_FOF``: The friends-of-friends mass of the halos. ++ ``M_gas``: The gas mass in the halo. ++ ``Mass_tot``: The total mass of the halo ++ ``M_gas_30kpc``: The gas mass within 30 kpc of the halo centre. ++ ``M_gas_500c``: The gas mass of the overdensity of 500 times the critical + density ++ ``M_gas_Rvmax``: The gas mass within the maximum rotation velocity. + +Several Radius types: +""""""""""""""""""""" + ++ ``R_HalfMass``: Radius of half the mass of the halo. ++ ``R_HalfMass_gas``: Radius of half the gas mass of the halo. ++ ``R_size``: ++ ``Rmax``: + +Mass Structure of the Halos: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In this subsection we listed the properties of the halos that are determining +the mass structure of the halo, so the exact profile and the inertia tensor. + +NFW profile properties: +""""""""""""""""""""""" ++ ``Xc``, ``Yc`` and ``Zc``: The x,y and z centre positions of the + halos. + + Centres are calculated using first all particles belonging to the + structure and then VELOCIraptor uses shrinking spheres to iterate to + a centre, stopping once the sphere contains <10% of all the + particles (this value can be changed to smaller amounts and there is + also a minimum particle number which can also be changed). + ++ ``Xc_gas``, ``Yc_gas``, ``Zc_gas``: The offset of the centre + positions of the halo based on the gas, to find the position of the + gas the offsets need to be added to ``Xc``, ``Yc`` and ``Zc``. + ++ ``cNFW``: The concentration of the halo. + + This is calculated using Vmax and Vvir, not using a fitted profile. + ++ ``VXc``, ``VYc`` and ``VZc`` are the velocities in the centre of the halo + [#check]_. ++ ``VXc_gas``, ``VYc_gas`` and ``VZc_gas`` are the velocities of the gas in + the centre of the halo [#check]_. + +Intertia Tensor properties: +""""""""""""""""""""""""""" + ++ ``eig_ij``: Are the normalized eigenvectors of the inertia tensor. ++ The eigenvalue ratios: + + 1. ``q`` is the semi-major over major; + 2. ``s`` is the minor over major. + ++ ``eig_ij_gas``: Are the normalized eigenvectors of the inertia tensor for + only the gas particles. ++ The eigenvalue ratios for only the gas, similar to all particles: + + 1. ``q_gas`` is the semi-major over major for only gas; + 2. ``s_gas`` is the minor over major for only gas. + +Dynamical Structure of the Halos: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In this subsection we list several properties that determine the dynamical +structure of the halo, like the angular momentum and the velocity dispersion +tensor. + +Angular momentum and spin parameters: +""""""""""""""""""""""""""""""""""""" + ++ ``lambda_b`` is the bullock spin parameter, see the paper by Bullock et al. + (2001) [#Bullock]_. ++ ``Lx``, ``Ly`` and ``Lz`` are the angular momentum of the halos, the + calculation includes all the particle types. ++ ``Lx_gas``, ``Ly_gas`` and ``Lz_gas`` are the angular momentum for only + the gas particles in the snapshot. + +Velocity Dispersion related: +"""""""""""""""""""""""""""" + ++ The complete velocity dispersion tensor (:math:`\sigma_{ij}`) which has + an array per component which gives the value for all the halos. In + general these components are called ``veldisp_ij`` in which i and j are + given by ``x``, ``y`` or ``z``. This means that there are nine + components stored in the ``.properties`` file. This omits the fact + that the dispersion tensor by nature is a symmetric tensor. All the + components are given by: + ``veldisp_xx``, ``veldisp_xy``, ``veldisp_xz``, ``veldisp_yx``, + ``veldisp_yy``, ``veldisp_yz``, ``veldisp_zx``, ``veldisp_zy``, + and ``veldisp_zz`` [#velodisp]_. ++ ``sigV``, the scalar velocity dispersion which corresponds with the + trace of the velocity dispersion tensor + (:math:`\sigma = \text{Tr}(\sigma_{ij})`). + + +Energy properties of the halos: +""""""""""""""""""""""""""""""" + ++ ``Ekin``, the kinetic energy of the halo. ++ ``Epot``, the potential energy of the halo. ++ ``Krot``, the rotational energy of the halo. ++ ``Krot_gas``, the rotational energy of the gas in the halo. + + +Halo and subhalo abstract variables: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In this subsection we list the ID convention for subhalos and halos and +some other abstract quantities of the halo which are not physical but +rather properties of the simulations. + +Structure types: +"""""""""""""""" + ++ ``ID`` is the halo ID. ++ ``Structuretype`` is the parameter that indicates what kind of structure + the current halo is. Halos have a structure type of ``10`` and subhalos + have a structure type of ``15``. ++ ``hostHaloID``, indicates the halo ID number of the host halo, in the case + that the halo has no parent (e.g. is the largest halo), the hostHaloID will + be ``-1``. ++ ``numSubStruct``, the number of substructures or subhalos in the halo. + +Particle types: +""""""""""""""" + ++ ``npart`` is the number of particles in the halo (all types of particles). ++ ``n_gas`` is the number of gas particles in the halo. + +Not specified parameters: +^^^^^^^^^^^^^^^^^^^^^^^^^ + +In this section we list parameters which cannot specifically be classified +in a group. + + +Most Bound Particle (MBP): +"""""""""""""""""""""""""" + ++ ``ID_mbp``, the ID of the most bound particle in the halo. ++ ``Xcmbp``, ``Ycmbp`` and ``Zcmbp`` are the positions of the most bound + halo particle [#check]_. ++ ``VXcmbp``, ``VYcmbp`` and ``VZcmbp`` are the velocities of the most bound + halo particle [#check]_. + +.. [#order] In most cases more massive groups appear earlier in the list, but + this is not guaranteed for larger simulations. The order of the groups is + more a matter of the way that VELOCIraptor searches instead of a physical + reason. +.. [#center] This is not the average positions of the halos particles, but + the halo position found by the VELOCIraptor algorithm. This includes a + fit for all the parameters including the gas particles or other types of + particles. +.. [#velodisp] In the velocity dispersion tensor ( :math:`\sigma_{ij}` ) + the following relations are satisfied between components: + + + :math:`\sigma_{xy}=\sigma_{yx}` + + :math:`\sigma_{xz}=\sigma_{zx}` + + :math:`\sigma_{yz}=\sigma_{yz}` +.. [#Bullock] The Bullock spin parameter is given by + :math:`\lambda = \frac{J}{\sqrt{2}MVR}`, for more information see + https://arxiv.org/abs/astro-ph/0011001. +.. [#BN98] The Bryan and Norman (1998) paper can be found here: + https://arxiv.org/abs/astro-ph/9710107 +.. [#check] Needs to be checked. diff --git a/doc/RTD/source/VELOCIraptorInterface/stfalone.rst b/doc/RTD/source/VELOCIraptorInterface/stfalone.rst new file mode 100644 index 0000000000000000000000000000000000000000..113cff53a51e446d321f6a912222c565f2bdb38e --- /dev/null +++ b/doc/RTD/source/VELOCIraptorInterface/stfalone.rst @@ -0,0 +1,92 @@ +.. VELOCIraptor stand alone + Folkert Nobels 12th October 2018 + +Stand alone VELOCIraptor configuration +====================================== + + +.. toctree:: + :maxdepth: 2 + :hidden: + :caption: Contents: + +Besides running VELOCIraptor on the fly when using SWIFT, it is also possible +to run VELOCIraptor alone without using SWIFT. In this section we explain how +VELOCIraptor can be run stand alone without using SWIFT. + +Setting up VELOCIraptor +----------------------- + +The first step is setting up VELOCIraptor, this requires us to download the +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 +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:: + + cd stf + cp Makefile.config.SWIFT-template Makefile.config + +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"``. + +Compiling VELOCIraptor +---------------------- + +Compoling goes completely different as compared to the on the fly halo finder +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]_) + +Running VELOCIraptor on a Snapshot +---------------------------------- + +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 + +which gives the information about the usage of the command:: + + USAGE: + + -C <configuration file (overrides other options)> + -I <input format [Gadget (Default) 1, HDF (if implemented)2, TIPSY 3, RAMSES 4, HDF 2, NCHILADA 5> + -i <input file> + -s <number of files per output for gadget input 1 [default]> + -Z <number of threads used in parallel read (1)> + -o <output filename> + ===== EXTRA OPTIONS FOR GADGET INPUT ====== + -g <number of extra sph/gas blocks for gadget> + -s <number of extra star blocks for gadget> + -b <number of extra bh blocks for gadget> + ===== EXTRA OPTIONS REQUIRED FOR RAMSES INPUT ====== + -t <ramses snapnumber> + +After this we can run a 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. + diff --git a/doc/RTD/source/VELOCIraptorInterface/stfwithswift.rst b/doc/RTD/source/VELOCIraptorInterface/stfwithswift.rst new file mode 100644 index 0000000000000000000000000000000000000000..ac8dcc5b0b3c4b6b77dbd5dc79be2613eae0edc6 --- /dev/null +++ b/doc/RTD/source/VELOCIraptorInterface/stfwithswift.rst @@ -0,0 +1,95 @@ +.. SWIFT with VELOCIraptor + Folkert Nobels 12th October 2018 + + +Configuring SWIFT with VELOCIraptor +=================================== + +.. toctree:: + :maxdepth: 2 + :hidden: + :caption: Contents: + +In the following three paragraphs we will explain how to setup VELOCIraptor, +how to compile it and how to compile SWIFT with VELOCIraptor. + + +Setting up VELOCIraptor +----------------------- + +Before we can run SWIFT with VELOCIraptor we first need to download +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 +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``:: + + 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. + + +Compiling VELOCIraptor +---------------------- + +After we downloaded the files and made a configuration file we can compile +VELOCIraptor as follows:: + + make lib + make libstf + +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 +HDF5 library, not a parallel build. + +Compiling SWIFT +--------------- +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 + make + +In which ``./autogen.sh`` only needs to be run once after the code is cloned +from the GitLab_, and ``/path/to/`` is the path to the ``VELOCIraptor-STF`` +directory on your machine. In general ``./configure`` can be run with other +options as desired. After this we can run SWIFT with VELOCIraptor, but for this +we first need to add several lines to the yaml file of our simulation:: + + + #structure finding options + StructureFinding: + config_file_name: stf_input_6dfof_dmonly_sub.cfg + basename: ./stf + output_time_format: 1 + scale_factor_first: 0.02 + delta_time: 1.02 + +In which we specify the ``.cfg`` file that is used by VELOCIraptor and the +other parameters which SWIFT needs to use. In the case of +the Small Cosmological Volume DMO example we can run a simulation with halo +finder as:: + + cd examples/SmallCosmoVolume_DM + ../swift -c -s -G -x -t 8 small_cosmo_volume_dm.yml + +In which there is an additional ``-x`` option which activates the VELOCIraptor +interface. + + +.. _GitHub: https://github.com/pelahi/VELOCIraptor-STF +.. _GitLab: https://gitlab.cosma.dur.ac.uk/swift/swiftsim diff --git a/doc/RTD/source/VELOCIraptorInterface/whatis.rst b/doc/RTD/source/VELOCIraptorInterface/whatis.rst new file mode 100644 index 0000000000000000000000000000000000000000..e7f067ec4723e41da0f3a95dddad8f55d9897e85 --- /dev/null +++ b/doc/RTD/source/VELOCIraptorInterface/whatis.rst @@ -0,0 +1,65 @@ +.. What is VELOCIraptor + Folkert Nobels 12th October 2018 + + +What is VELOCIraptor? +===================== + +.. toctree:: + :maxdepth: 2 + :hidden: + :caption: Contents: + +In SWIFT it is possible to run a cosmological simulation and at the same time +do on the fly halo finding at specific predefined intervals. For finding the +Halos SWIFT uses VELOCIraptor (Elahi, Thacker and Widrow; 2011) [#velo]_, this +is a C++ halo finder that can use MPI. It differs from other halo finder +algorithms in the sense that it uses the velocity distributions of the +particles in the simulations and the the positions of the particles to get +a better estimate of which particles are part of a specific halo and +whether there are substructures in halos. + +The Algorithm +------------- + +The VELOCIraptor algorithm consist basically off the following steps [#ref]_: + +1. A kd-tree is constructed based on the maximization of the Shannon-entropy, + this means that every level in the kd-tree an equal number of particles + are distributed between the 8 lower nodes. This is based on their position + and their corresponding density, this results in more equal density + distributed nodes. This is also the implicit step in the algorithm that + takes into account the absolute positions of the particles. +2. The next part is calculating the the centre of mass velocity and the + velocity distribution for every individual node in the kd-tree. +3. Than the algorithm estimates the background velocity density function for + every particle based on the cell of the particle and the six nearest + neighbour cells. This prevents the background velocity density function + to be over sensitive for variations between different cells due to dominant + halo features in the velocity density function. +4. After this the algorithm searches for the nearest velocity neighbours + (:math:`N_v`) from a set of nearest position neighbours (:math:`N_x>N_v`). + The position neighbours do not need to be in the cell of the particles, in + general the set of nearest position neighbours is substantially larger than + the nearest velocity neighbours, the default is set as :math:`N_x=32 N_v`. +5. The individual local velocity density function is calculated for every + particle. +6. The fractional difference is calculated between the local velocity density + function and the background velocity density function. +7. Based on the calculated ratio outliers are picked and the outliers are + grouped together in halos and subhalos. + + + +.. Every halo finder has limitations, the limitations of VELOCIraptor are: + +.. 1. The algorithm is mostly sensitive to substructures that are on the tail + of the Gaussian velocity density function, this means that VELOCIraptor + is most sensitive for subhalos which are cold (slow ratating) but have + a large bulk velocity + + +.. _Velociraptor: http://adsabs.harvard.edu/abs/2011MNRAS.418..320E +.. [#velo] For technical information regarding VELOCIraptor see: Velociraptor_ +.. [#ref] This part is based on the explanation given in the Elahi, Thacker and + Widrow (2011) paper (Velociraptor_) diff --git a/doc/RTD/source/index.rst b/doc/RTD/source/index.rst index 05c15c5a081cb03ae4e53c26bf6fe4e8dd78dfd5..d148398c1bd77eafbce5e0037457b34efddb4eca 100644 --- a/doc/RTD/source/index.rst +++ b/doc/RTD/source/index.rst @@ -15,9 +15,13 @@ difference is the parameter file that will need to be adapted for SWIFT. :maxdepth: 2 GettingStarted/index + CommandLineOptions/index + ParameterFiles/index InitialConditions/index HydroSchemes/index Cooling/index EquationOfState/index + ExternalPotentials/index NewOption/index Task/index + VELOCIraptorInterface/index diff --git a/examples/AgoraDisk/agora_disk.yml b/examples/AgoraDisk/agora_disk.yml index 7368700d8a2a5ca8de7d677e1da78be51d669835..92f2532b3132c0f6314b7697f0b9b65f1afedb3b 100644 --- a/examples/AgoraDisk/agora_disk.yml +++ b/examples/AgoraDisk/agora_disk.yml @@ -39,20 +39,18 @@ Gravity: SPH: resolution_eta: 1.2348 # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel). CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. - minimal_temperature: 10 # (internal units) + minimal_temperature: 10. # Kelvin # Parameters related to the initial conditions InitialConditions: file_name: ./agora_disk.hdf5 # The file to read - cleanup_h_factors: 1 # Remove the h-factors inherited from Gadget - shift: [674.1175, 674.1175, 674.1175] # (Optional) A shift to apply to all particles read from the ICs (in internal units). + periodic: 0 # Non-periodic BCs + cleanup_h_factors: 1 # Remove the h-factors inherited from Gadget + shift: [674.1175, 674.1175, 674.1175] # Centre the box # Dimensionless pre-factor for the time-step condition LambdaCooling: - lambda_cgs: 1.0e-22 # Cooling rate (in cgs units) - minimum_temperature: 1.0e2 # Minimal temperature (Kelvin) - mean_molecular_weight: 0.59 # Mean molecular weight - hydrogen_mass_abundance: 0.75 # Hydrogen mass abundance (dimensionless) + 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 # Dimensionless pre-factor for the time-step condition # Cooling with Grackle 2.0 diff --git a/examples/AgoraDisk/getIC.sh b/examples/AgoraDisk/getIC.sh old mode 100644 new mode 100755 index 620a751bedaf6c646119247270fad6dd3f740fde..c234b52b943ccb8d6dededed7d0f5070cd9fe5b2 --- a/examples/AgoraDisk/getIC.sh +++ b/examples/AgoraDisk/getIC.sh @@ -6,4 +6,4 @@ if [ "$#" -ne 1 ]; then exit fi -wget https://obswww.unige.ch/~lhausamm/swift/IC/AgoraDisk/$1 +wget https://obswww.unige.ch/~lhausamm/swift/IC/AgoraDisk/$1.hdf5 diff --git a/examples/AgoraDisk/getSolution.sh b/examples/AgoraDisk/getSolution.sh old mode 100644 new mode 100755 diff --git a/examples/AgoraDisk/run.sh b/examples/AgoraDisk/run.sh old mode 100644 new mode 100755 diff --git a/examples/ConstantCosmoVolume/constant_volume.yml b/examples/ConstantCosmoVolume/constant_volume.yml index db5b3de536b5b71229a207a3fdcfab8480718ef3..ebfcc4ffd72121571fa1a69f900985917b440c65 100644 --- a/examples/ConstantCosmoVolume/constant_volume.yml +++ b/examples/ConstantCosmoVolume/constant_volume.yml @@ -39,7 +39,8 @@ SPH: # Parameters related to the initial conditions InitialConditions: file_name: ./constantBox.hdf5 - + periodic: 1 + Scheduler: max_top_level_cells: 8 cell_split_size: 50 diff --git a/examples/CoolingBox/coolingBox.yml b/examples/CoolingBox/coolingBox.yml index 2bd2f19f6d78388ae638521f590255d410bc8697..1a06168cef739f33301a113cf1247b52cd3e2129 100644 --- a/examples/CoolingBox/coolingBox.yml +++ b/examples/CoolingBox/coolingBox.yml @@ -27,17 +27,16 @@ Statistics: SPH: resolution_eta: 1.2348 # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel). CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. + minimal_temperature: 100. # Kelvin # Parameters related to the initial conditions InitialConditions: file_name: ./coolingBox.hdf5 # The file to read - + periodic: 1 + # Dimensionless pre-factor for the time-step condition LambdaCooling: - lambda_cgs: 1.0e-22 # Cooling rate (in cgs units) - minimum_temperature: 1.0e4 # Minimal temperature (Kelvin) - mean_molecular_weight: 0.59 # Mean molecular weight - hydrogen_mass_abundance: 0.75 # Hydrogen mass abundance (dimensionless) + 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 # Dimensionless pre-factor for the time-step condition # Cooling with Grackle 2.0 diff --git a/examples/CoolingHalo/cooling_halo.yml b/examples/CoolingHalo/cooling_halo.yml index 68c3478b717261698ac175835fc246e134e3a6a7..3d6e44ae3efdb4ad0687f61d904d87d55bb2837b 100644 --- a/examples/CoolingHalo/cooling_halo.yml +++ b/examples/CoolingHalo/cooling_halo.yml @@ -27,11 +27,13 @@ Snapshots: SPH: resolution_eta: 1.2349 # Target smoothing length in units of the mean inter-particle separation (1.2349 == 48Ngbs with the cubic spline kernel). CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. - + minimal_temperature: 1e4 # Kelvin + # Parameters related to the initial conditions InitialConditions: file_name: CoolingHalo.hdf5 # The file to read - + periodic: 1 + # External potential parameters IsothermalPotential: vrot: 200. # rotation speed of isothermal potential in internal units @@ -40,8 +42,5 @@ IsothermalPotential: # Cooling parameters LambdaCooling: - lambda_cgs: 1.0e-22 # Cooling rate (in cgs units) - minimum_temperature: 1.0e4 # Minimal temperature (Kelvin) - mean_molecular_weight: 0.59 # Mean molecular weight - hydrogen_mass_abundance: 0.75 # Hydrogen mass abundance (dimensionless) + 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 # Dimensionless pre-factor for the time-step condition diff --git a/examples/CoolingHalo/makeIC.py b/examples/CoolingHalo/makeIC.py index 3ec1be6f7b5e568ebe8e0fefe508ef8287edb29c..046e5d619f047f8c6d40eab5a5cfce2e3a02074d 100644 --- a/examples/CoolingHalo/makeIC.py +++ b/examples/CoolingHalo/makeIC.py @@ -91,10 +91,6 @@ grp.attrs["Unit current in cgs (U_I)"] = 1. grp.attrs["Unit temperature in cgs (U_T)"] = 1. -# Runtime parameters -grp = file.create_group("/RuntimePars") -grp.attrs["PeriodicBoundariesOn"] = periodic - # set seed for random number np.random.seed(1234) diff --git a/examples/CoolingHalo/makeIC_random_box.py b/examples/CoolingHalo/makeIC_random_box.py index 4295cb135233f2d5a59405b44e6d8e9c80a1f6c0..be8f2f172e5b7aef385f0974445e44068021c99d 100644 --- a/examples/CoolingHalo/makeIC_random_box.py +++ b/examples/CoolingHalo/makeIC_random_box.py @@ -102,10 +102,6 @@ grp.attrs["MassTable"] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] grp.attrs["Flag_Entropy_ICs"] = [0, 0, 0, 0, 0, 0] grp.attrs["Dimension"] = 3 -# Runtime parameters -grp = file.create_group("/RuntimePars") -grp.attrs["PeriodicBoundariesOn"] = periodic - # set seed for random number np.random.seed(1234) diff --git a/examples/CoolingHaloWithSpin/cooling_halo.yml b/examples/CoolingHaloWithSpin/cooling_halo.yml index f6e9fe3b124631fc2d5336db8a7ffb18f7b34a95..1b29e1376e47ad32beacaf9bfb5408b8ff4d3191 100644 --- a/examples/CoolingHaloWithSpin/cooling_halo.yml +++ b/examples/CoolingHaloWithSpin/cooling_halo.yml @@ -27,11 +27,13 @@ Snapshots: SPH: resolution_eta: 1.2349 # Target smoothing length in units of the mean inter-particle separation (1.2349 == 48Ngbs with the cubic spline kernel). CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. + minimal_temperature: 1e4 # Kelvin # Parameters related to the initial conditions InitialConditions: file_name: CoolingHalo.hdf5 # The file to read - + periodic: 1 + # External potential parameters IsothermalPotential: vrot: 200. # Rotation speed of isothermal potential in internal units @@ -40,8 +42,5 @@ IsothermalPotential: # Cooling parameters LambdaCooling: - lambda_cgs: 1.0e-22 # Cooling rate (in cgs units) - minimum_temperature: 1.0e4 # Minimal temperature (Kelvin) - mean_molecular_weight: 0.59 # Mean molecular weight - hydrogen_mass_abundance: 0.75 # Hydrogen mass abundance (dimensionless) + lambda_nH2_cgs: 1e-22 # Cooling rate divided by square Hydrogen number density (in cgs units [erg * s^-1 * cm^3]) cooling_tstep_mult: 0.1 # Dimensionless pre-factor for the time-step condition diff --git a/examples/CoolingHaloWithSpin/makeIC.py b/examples/CoolingHaloWithSpin/makeIC.py index 2cf3127c743f61756b3ff6c4a7738c83d185f9cd..9a839bfd01594fd1d1c899d43223d0ebce12a72f 100644 --- a/examples/CoolingHaloWithSpin/makeIC.py +++ b/examples/CoolingHaloWithSpin/makeIC.py @@ -92,11 +92,6 @@ grp.attrs["Unit time in cgs (U_t)"] = const_unit_length_in_cgs / const_unit_velo grp.attrs["Unit current in cgs (U_I)"] = 1. grp.attrs["Unit temperature in cgs (U_T)"] = 1. - -# Runtime parameters -grp = file.create_group("/RuntimePars") -grp.attrs["PeriodicBoundariesOn"] = periodic - # set seed for random number np.random.seed(1234) diff --git a/examples/CoolingHaloWithSpin/makeIC_random_box.py b/examples/CoolingHaloWithSpin/makeIC_random_box.py index 4295cb135233f2d5a59405b44e6d8e9c80a1f6c0..be8f2f172e5b7aef385f0974445e44068021c99d 100644 --- a/examples/CoolingHaloWithSpin/makeIC_random_box.py +++ b/examples/CoolingHaloWithSpin/makeIC_random_box.py @@ -102,10 +102,6 @@ grp.attrs["MassTable"] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] grp.attrs["Flag_Entropy_ICs"] = [0, 0, 0, 0, 0, 0] grp.attrs["Dimension"] = 3 -# Runtime parameters -grp = file.create_group("/RuntimePars") -grp.attrs["PeriodicBoundariesOn"] = periodic - # set seed for random number np.random.seed(1234) diff --git a/examples/DiscPatch/GravityOnly/disc-patch.yml b/examples/DiscPatch/GravityOnly/disc-patch.yml index 4ec061add978bec82c267660cc343cf0bfa8f4c6..bcc7d1a3decfb36201b60349eedb5d214e61f9a6 100644 --- a/examples/DiscPatch/GravityOnly/disc-patch.yml +++ b/examples/DiscPatch/GravityOnly/disc-patch.yml @@ -34,7 +34,8 @@ SPH: # Parameters related to the initial conditions InitialConditions: file_name: Disc-Patch.hdf5 # The file to read - + periodic: 1 + # External potential parameters DiscPatchPotential: surface_density: 10. diff --git a/examples/DiscPatch/GravityOnly/makeIC.py b/examples/DiscPatch/GravityOnly/makeIC.py index 5f9650f44277cf858021c9b628d68134c47a19b7..3abf4f87fc6b6f78ed1814be08ca0d8e39359a26 100644 --- a/examples/DiscPatch/GravityOnly/makeIC.py +++ b/examples/DiscPatch/GravityOnly/makeIC.py @@ -111,10 +111,6 @@ grp.attrs["MassTable"] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] grp.attrs["Flag_Entropy_ICs"] = [0, 0, 0, 0, 0, 0] grp.attrs["Dimension"] = 3 -#Runtime parameters -grp = file.create_group("/RuntimePars") -grp.attrs["PeriodicBoundariesOn"] = periodic - # set seed for random number numpy.random.seed(1234) diff --git a/examples/DiscPatch/HydroStatic/disc-patch-icc.yml b/examples/DiscPatch/HydroStatic/disc-patch-icc.yml index 983a7dcc103135ab4db61d6ea77701532226c101..aee54057cf2c5b9d178abac5599d9e4133652362 100644 --- a/examples/DiscPatch/HydroStatic/disc-patch-icc.yml +++ b/examples/DiscPatch/HydroStatic/disc-patch-icc.yml @@ -37,7 +37,8 @@ EoS: # Parameters related to the initial conditions InitialConditions: file_name: Disc-Patch.hdf5 # The file to read - + periodic: 1 + # External potential parameters DiscPatchPotential: surface_density: 10. diff --git a/examples/DiscPatch/HydroStatic/disc-patch.yml b/examples/DiscPatch/HydroStatic/disc-patch.yml index 422e1cf910202e8f6dc0a9395fc7e36ce80443ed..8651ac09dbc4c4a97f0915ce7df6c678837b2f45 100644 --- a/examples/DiscPatch/HydroStatic/disc-patch.yml +++ b/examples/DiscPatch/HydroStatic/disc-patch.yml @@ -34,7 +34,8 @@ SPH: # Parameters related to the initial conditions InitialConditions: file_name: Disc-Patch-dynamic.hdf5 # The file to read - + periodic: 1 + # External potential parameters DiscPatchPotential: surface_density: 10. diff --git a/examples/DiscPatch/HydroStatic/makeIC.py b/examples/DiscPatch/HydroStatic/makeIC.py index 8b4c55560c34e7bdb538f2b4732369216f91a087..dd50a821a2eb376c0785afd849a3ea575e349703 100644 --- a/examples/DiscPatch/HydroStatic/makeIC.py +++ b/examples/DiscPatch/HydroStatic/makeIC.py @@ -182,10 +182,6 @@ grp.attrs["MassTable"] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] grp.attrs["Flag_Entropy_ICs"] = [0, 0, 0, 0, 0, 0] grp.attrs["Dimension"] = 3 -#Runtime parameters -grp = file.create_group("/RuntimePars") -grp.attrs["PeriodicBoundariesOn"] = 1 - # write gas particles grp0 = file.create_group("/PartType0") diff --git a/examples/DiscPatch/HydroStatic_1D/disc-patch-icc.yml b/examples/DiscPatch/HydroStatic_1D/disc-patch-icc.yml index 450689034f4ae782cc74bf01dac93e723e5d2ce2..ea5d2e24eb93c64e21f37a8c137603b22885392c 100644 --- a/examples/DiscPatch/HydroStatic_1D/disc-patch-icc.yml +++ b/examples/DiscPatch/HydroStatic_1D/disc-patch-icc.yml @@ -34,7 +34,8 @@ SPH: # Parameters related to the initial conditions InitialConditions: file_name: Disc-Patch.hdf5 # The file to read - + periodic: 1 + # External potential parameters DiscPatchPotential: surface_density: 10. diff --git a/examples/DiscPatch/HydroStatic_1D/makeIC.py b/examples/DiscPatch/HydroStatic_1D/makeIC.py index 983a550a3442c6470611792081a5884d38023a6a..b193c85e50d3526b8518cac06b9b00c3071c383a 100644 --- a/examples/DiscPatch/HydroStatic_1D/makeIC.py +++ b/examples/DiscPatch/HydroStatic_1D/makeIC.py @@ -168,10 +168,6 @@ grp.attrs["MassTable"] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] grp.attrs["Flag_Entropy_ICs"] = [0, 0, 0, 0, 0, 0] grp.attrs["Dimension"] = 1 -#Runtime parameters -grp = file.create_group("/RuntimePars") -grp.attrs["PeriodicBoundariesOn"] = 1 - # write gas particles grp0 = file.create_group("/PartType0") diff --git a/examples/DwarfGalaxy/README b/examples/DwarfGalaxy/README new file mode 100644 index 0000000000000000000000000000000000000000..7a9167694a24c088997316180233b28b9126f298 --- /dev/null +++ b/examples/DwarfGalaxy/README @@ -0,0 +1,7 @@ +This example is a galaxy extracted from the example "ZoomIn". It allows +to test SWIFT on a smaller problem. See the README in "ZoomIn" for more +information. + + +MD5 check-sum of the ICS: +ae2af84d88f30011b6a8af3f37d140cf dwarf_galaxy.hdf5 \ No newline at end of file diff --git a/examples/DwarfGalaxy/dwarf_galaxy.yml b/examples/DwarfGalaxy/dwarf_galaxy.yml new file mode 100644 index 0000000000000000000000000000000000000000..0d815a99c42249bcbbdaf21dbaa34a55f61731aa --- /dev/null +++ b/examples/DwarfGalaxy/dwarf_galaxy.yml @@ -0,0 +1,72 @@ +# Define the system of units to use internally. +InternalUnitSystem: + UnitMass_in_cgs: 1.98848e43 # 10^10 M_sun in grams + UnitLength_in_cgs: 3.08567758e21 # kpc in centimeters + UnitVelocity_in_cgs: 1e5 # km/s in centimeters per second + UnitCurrent_in_cgs: 1 # Amperes + UnitTemp_in_cgs: 1 # Kelvin + +# Structure finding options +StructureFinding: + config_file_name: stf_input.cfg # Name of the STF config file. + basename: ./stf # Common part of the name of output files. + output_time_format: 0 # Specifies the frequency format of structure finding. 0 for simulation steps (delta_step) and 1 for simulation time intervals (delta_time). + scale_factor_first: 0.92 # Scale-factor of the first snaphot (cosmological run) + time_first: 0.01 # Time of the first structure finding output (in internal units). + delta_step: 1000 # Time difference between consecutive structure finding outputs (in internal units) in simulation steps. + delta_time: 1.10 # Time difference between consecutive structure finding outputs (in internal units) in simulation time intervals. + +# Cosmological parameters +Cosmology: + h: 0.673 # Reduced Hubble constant + a_begin: 0.9873046739 # Initial scale-factor of the simulation + a_end: 1.0 # Final scale factor of the simulation + Omega_m: 0.315 # Matter density parameter + Omega_lambda: 0.685 # Dark-energy density parameter + Omega_b: 0.0486 # Baryon density parameter + +Scheduler: + max_top_level_cells: 8 + cell_split_size: 400 # (Optional) Maximal number of particles per cell (this is the default value). + +# Parameters governing the time integration +TimeIntegration: + time_begin: 0. # The starting time of the simulation (in internal units). + time_end: 1. # The end time of the simulation (in internal units). + dt_min: 1e-10 # 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: dwarf_galaxy # Common part of the name of output files + time_first: 0. # Time of the first output (non-cosmological run) (in internal units) + delta_time: 0.02 # Time difference between consecutive outputs (in internal units) + compression: 1 + +# Parameters governing the conserved quantities statistics +Statistics: + scale_factor_first: 0.987345 # Scale-factor of the first stat dump (cosmological run) + time_first: 0.01 # Time of the first stat dump (non-cosmological run) (in internal units) + delta_time: 1.05 # Time between statistics output + +# Parameters for the self-gravity scheme +Gravity: + eta: 0.025 # Constant dimensionless multiplier for time integration. + theta: 0.7 # Opening angle (Multipole acceptance criterion) + comoving_softening: 0.05 # Comoving softening length (in internal units). + max_physical_softening: 0.01 # Physical softening length (in internal units). + mesh_side_length: 16 + +# Parameters for the hydrodynamics scheme +SPH: + resolution_eta: 1.2348 # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel). + CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. + minimal_temperature: 100 # (internal units) + +# Parameters related to the initial conditions +InitialConditions: + file_name: ./dwarf_galaxy.hdf5 # The file to read + periodic: 1 + cleanup_h_factors: 1 # Remove the h-factors inherited from Gadget + cleanup_velocity_factors: 1 # Remove the sqrt(a) factor in the velocities inherited from Gadget + diff --git a/examples/DwarfGalaxy/getIC.sh b/examples/DwarfGalaxy/getIC.sh new file mode 100755 index 0000000000000000000000000000000000000000..92f4cd3939845d57a61683e95135163b8639371f --- /dev/null +++ b/examples/DwarfGalaxy/getIC.sh @@ -0,0 +1,2 @@ +#!/bin/bash +wget https://obswww.unige.ch/~lhausamm/swift/IC/DwarfGalaxy/dwarf_galaxy.hdf5 diff --git a/examples/DwarfGalaxy/run.sh b/examples/DwarfGalaxy/run.sh new file mode 100755 index 0000000000000000000000000000000000000000..4cc87880215a37c9eac59b19e584f4887cba2c38 --- /dev/null +++ b/examples/DwarfGalaxy/run.sh @@ -0,0 +1,11 @@ +#!/bin/bash + + # Generate the initial conditions if they are not present. +if [ ! -e dwarf_galaxy.hdf5 ] +then + echo "Fetching initial conditions for the dwarf galaxy example..." + ./getIC.sh +fi + +../swift -b -G -s -S -t 8 dwarf_galaxy.yml 2>&1 | tee output.log + diff --git a/examples/EAGLE_100/eagle_100.yml b/examples/EAGLE_100/eagle_100.yml index dc2b814e0a3c116edd6c8dcac3c20b21a96e5927..3bcda091bdac5b740f3568de9c0814cc84c3b846 100644 --- a/examples/EAGLE_100/eagle_100.yml +++ b/examples/EAGLE_100/eagle_100.yml @@ -55,6 +55,7 @@ SPH: # Parameters related to the initial conditions InitialConditions: file_name: ./EAGLE_ICs_100.hdf5 # The file to read + periodic: 1 cleanup_h_factors: 1 # Remove the h-factors inherited from Gadget cleanup_velocity_factors: 1 # Remove the sqrt(a) factor in the velocities inherited from Gadget diff --git a/examples/EAGLE_12/eagle_12.yml b/examples/EAGLE_12/eagle_12.yml index 6d143c3f00dc63eb8c2198b1b3f88944e7575249..aa42d2d00db776e114a25dc52d4207b6dad8f4ff 100644 --- a/examples/EAGLE_12/eagle_12.yml +++ b/examples/EAGLE_12/eagle_12.yml @@ -63,6 +63,7 @@ FOF: # Parameters related to the initial conditions InitialConditions: file_name: ./EAGLE_ICs_12.hdf5 # The file to read + periodic: 1 cleanup_h_factors: 1 # Remove the h-factors inherited from Gadget cleanup_velocity_factors: 1 # Remove the sqrt(a) factor in the velocities inherited from Gadget diff --git a/examples/EAGLE_25/eagle_25.yml b/examples/EAGLE_25/eagle_25.yml index 79a35421bc0dd082d3807234077bd76ba2d5e208..c5b2b9ec49135e818dd6bd97843ef7876554b41f 100644 --- a/examples/EAGLE_25/eagle_25.yml +++ b/examples/EAGLE_25/eagle_25.yml @@ -72,6 +72,7 @@ FOF: # Parameters related to the initial conditions InitialConditions: file_name: ./EAGLE_ICs_25.hdf5 # The file to read + periodic: 1 cleanup_h_factors: 1 # Remove the h-factors inherited from Gadget cleanup_velocity_factors: 1 # Remove the sqrt(a) factor in the velocities inherited from Gadget diff --git a/examples/EAGLE_50/eagle_50.yml b/examples/EAGLE_50/eagle_50.yml index f4bca303fe8919dbc25f3f7e926e0ec0f26df860..51f607eadd60d10a585641ab54769aa012931e5f 100644 --- a/examples/EAGLE_50/eagle_50.yml +++ b/examples/EAGLE_50/eagle_50.yml @@ -65,5 +65,6 @@ FOF: # Parameters related to the initial conditions InitialConditions: file_name: ./EAGLE_ICs_50.hdf5 # The file to read + periodic: 1 cleanup_h_factors: 1 # Remove the h-factors inherited from Gadget cleanup_velocity_factors: 1 # Remove the sqrt(a) factor in the velocities inherited from Gadget diff --git a/examples/EAGLE_6/eagle_6.yml b/examples/EAGLE_6/eagle_6.yml index 3b20475f7aeb08c5e7c47fd5fa7094b40d83ef39..c69e5a24d8d4812f84ba88c17ca5ed11bc6b9bb6 100644 --- a/examples/EAGLE_6/eagle_6.yml +++ b/examples/EAGLE_6/eagle_6.yml @@ -76,5 +76,6 @@ FOF: # Parameters related to the initial conditions InitialConditions: file_name: ./EAGLE_ICs_6.hdf5 # The file to read + periodic: 1 cleanup_h_factors: 1 # Remove the h-factors inherited from Gadget cleanup_velocity_factors: 1 # Remove the sqrt(a) factor in the velocities inherited from Gadget diff --git a/examples/EAGLE_DMO_100/eagle_100.yml b/examples/EAGLE_DMO_100/eagle_100.yml index f04c32c8d08b5548c2c710cf8782b39a59c3821e..5a3066195647b79eeb6a6d67d037d15ce8370c39 100644 --- a/examples/EAGLE_DMO_100/eagle_100.yml +++ b/examples/EAGLE_DMO_100/eagle_100.yml @@ -49,6 +49,7 @@ Gravity: # Parameters related to the initial conditions InitialConditions: file_name: EAGLE_DMO_ICs_100.hdf5 + periodic: 1 cleanup_h_factors: 1 # Remove the h-factors inherited from Gadget cleanup_velocity_factors: 1 # Remove the sqrt(a) factor in the velocities inherited from Gadget diff --git a/examples/EAGLE_DMO_12/eagle_12.yml b/examples/EAGLE_DMO_12/eagle_12.yml index 2354216a5b0dcefe139d6e39699b4c67035a4173..0660d98e87adfae62a2d795efec7ad6509cc1354 100644 --- a/examples/EAGLE_DMO_12/eagle_12.yml +++ b/examples/EAGLE_DMO_12/eagle_12.yml @@ -51,6 +51,7 @@ Gravity: # Parameters related to the initial conditions InitialConditions: file_name: EAGLE_DMO_ICs_12.hdf5 + periodic: 1 cleanup_h_factors: 1 # Remove the h-factors inherited from Gadget cleanup_velocity_factors: 1 # Remove the sqrt(a) factor in the velocities inherited from Gadget diff --git a/examples/EAGLE_DMO_25/eagle_25.yml b/examples/EAGLE_DMO_25/eagle_25.yml index b02f9742a597687d2742b7c2d9eddf836258b06a..558c68ffaad204ebbe1d5781f945f0d95108d227 100644 --- a/examples/EAGLE_DMO_25/eagle_25.yml +++ b/examples/EAGLE_DMO_25/eagle_25.yml @@ -50,6 +50,7 @@ Gravity: # Parameters related to the initial conditions InitialConditions: file_name: EAGLE_DMO_ICs_25.hdf5 + periodic: 1 cleanup_h_factors: 1 # Remove the h-factors inherited from Gadget cleanup_velocity_factors: 1 # Remove the sqrt(a) factor in the velocities inherited from Gadget diff --git a/examples/EAGLE_DMO_50/eagle_50.yml b/examples/EAGLE_DMO_50/eagle_50.yml index 97299df063cd1f611f59a56ccd9b091b1217bef3..3cab2b1dc869b5187cf647caa7893281b783591a 100644 --- a/examples/EAGLE_DMO_50/eagle_50.yml +++ b/examples/EAGLE_DMO_50/eagle_50.yml @@ -49,6 +49,7 @@ Gravity: # Parameters related to the initial conditions InitialConditions: file_name: EAGLE_DMO_ICs_50.hdf5 + periodic: 1 cleanup_h_factors: 1 # Remove the h-factors inherited from Gadget cleanup_velocity_factors: 1 # Remove the sqrt(a) factor in the velocities inherited from Gadget diff --git a/examples/EvrardCollapse_3D/evrard.yml b/examples/EvrardCollapse_3D/evrard.yml index f9a4e69f72e6bb19b818cb985ef92122b1a10b2a..c14f9151b5a4ba6af60307a689d5b2530068deb3 100644 --- a/examples/EvrardCollapse_3D/evrard.yml +++ b/examples/EvrardCollapse_3D/evrard.yml @@ -39,6 +39,7 @@ Gravity: # Parameters related to the initial conditions InitialConditions: file_name: ./evrard.hdf5 # The file to read - + periodic: 0 + PhysicalConstants: G: 1. diff --git a/examples/EvrardCollapse_3D/makeIC.py b/examples/EvrardCollapse_3D/makeIC.py index f4d3c4c5bf7f91e5f79cfcd4e9ae23388932144e..29c4acd69ebf0638edf1273efc0f411766aebb6d 100644 --- a/examples/EvrardCollapse_3D/makeIC.py +++ b/examples/EvrardCollapse_3D/makeIC.py @@ -86,10 +86,6 @@ grp.attrs["MassTable"] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] grp.attrs["Flag_Entropy_ICs"] = 0 grp.attrs["Dimension"] = 3 -#Runtime parameters -grp = file.create_group("/RuntimePars") -grp.attrs["PeriodicBoundariesOn"] = 0 - #Units grp = file.create_group("/Units") grp.attrs["Unit length in cgs (U_L)"] = 1. diff --git a/examples/ExternalPointMass/externalPointMass.yml b/examples/ExternalPointMass/externalPointMass.yml index de05a9ff3c10afa7871ebeafbf4d8d272056d39f..c9b1ef34d618eddfc2ba410785deb4919ed1b835 100644 --- a/examples/ExternalPointMass/externalPointMass.yml +++ b/examples/ExternalPointMass/externalPointMass.yml @@ -31,11 +31,13 @@ SPH: # Parameters related to the initial conditions InitialConditions: file_name: PointMass.hdf5 # The file to read + periodic: 0 shift: [50.,50.,50.] # A shift to apply to all particles read from the ICs (in internal units). # External potential parameters PointMassPotential: position: [50.,50.,50.] # location of external point mass in internal units + useabspos: 1 # Position is absolute mass: 1e10 # mass of external point mass in internal units timestep_mult: 0.03 # controls time step diff --git a/examples/ExternalPointMass/makeIC.py b/examples/ExternalPointMass/makeIC.py index fdc5b1fd67ffcbd85beae3a9d6d1274d3d48c279..7a9e2e1fd555e4823957721e3c7bf53da9eff48d 100644 --- a/examples/ExternalPointMass/makeIC.py +++ b/examples/ExternalPointMass/makeIC.py @@ -79,9 +79,6 @@ grp.attrs["MassTable"] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] grp.attrs["Flag_Entropy_ICs"] = [0, 0, 0, 0, 0, 0] grp.attrs["Dimension"] = 3 -#Runtime parameters -grp = file.create_group("/RuntimePars") -grp.attrs["PeriodicBoundariesOn"] = periodic #Units grp = file.create_group("/Units") diff --git a/examples/Gradients/gradientsCartesian.yml b/examples/Gradients/gradientsCartesian.yml index b2131bdd4d3a9242d30ff0f32b7bf3395cb433a8..0264e9ced8652f45feeba79573d3143e6b0086bb 100644 --- a/examples/Gradients/gradientsCartesian.yml +++ b/examples/Gradients/gradientsCartesian.yml @@ -31,4 +31,4 @@ SPH: # Parameters related to the initial conditions InitialConditions: file_name: ./Gradients_cartesian.hdf5 # The file to read - + periodic: 1 diff --git a/examples/Gradients/gradientsRandom.yml b/examples/Gradients/gradientsRandom.yml index 57ae849898bf8ccd63ccd7a5d685f9690403403d..1c6fcc1d077e0fd260b42e7de77490d58fb5aea9 100644 --- a/examples/Gradients/gradientsRandom.yml +++ b/examples/Gradients/gradientsRandom.yml @@ -31,4 +31,4 @@ SPH: # Parameters related to the initial conditions InitialConditions: file_name: ./Gradients_random.hdf5 # The file to read - + periodic: 1 diff --git a/examples/Gradients/makeICs.py b/examples/Gradients/makeICs.py index 38d035d2ad2dd3dd6daacfd6f58d824e9daf6742..be70a9e614e8bc32db0c0979c42ab892ef7d068f 100644 --- a/examples/Gradients/makeICs.py +++ b/examples/Gradients/makeICs.py @@ -26,7 +26,6 @@ import sys # reconstruction # Parameters -periodic= 1 # 1 For periodic box gamma = 5./3. # Gas adiabatic index gridtype = "cartesian" if len(sys.argv) > 1: @@ -153,10 +152,6 @@ grp.attrs["NumFilesPerSnapshot"] = 1 grp.attrs["MassTable"] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] grp.attrs["Flag_Entropy_ICs"] = [0, 0, 0, 0, 0, 0] -#Runtime parameters -grp = file.create_group("/RuntimePars") -grp.attrs["PeriodicBoundariesOn"] = periodic - #Particle group grp = file.create_group("/PartType0") ds = grp.create_dataset('Coordinates', (npart, 3), 'd') diff --git a/examples/Gravity_glass/makeIC.py b/examples/Gravity_glass/makeIC.py index 1a3fde9e2868c8881923fa61d1c308bca0f2f095..f573c79b19a5e3655d4f55f761ef20a6468342de 100644 --- a/examples/Gravity_glass/makeIC.py +++ b/examples/Gravity_glass/makeIC.py @@ -53,10 +53,6 @@ grp.attrs["MassTable"] = [0.0, mass, 0.0, 0.0, 0.0, 0.0] grp.attrs["Flag_Entropy_ICs"] = 0 grp.attrs["Dimension"] = 3 -#Runtime parameters -grp = file.create_group("/RuntimePars") -grp.attrs["PeriodicBoundariesOn"] = periodic - #Units grp = file.create_group("/Units") grp.attrs["Unit length in cgs (U_L)"] = 1. diff --git a/examples/Gravity_glass/uniform_DM_box.yml b/examples/Gravity_glass/uniform_DM_box.yml index 8f3ef6f025afb1a92320eeb702b50e8bf4befce6..00a5864cdb6ff0897501248437b3cc00be0f7acf 100644 --- a/examples/Gravity_glass/uniform_DM_box.yml +++ b/examples/Gravity_glass/uniform_DM_box.yml @@ -42,3 +42,4 @@ Statistics: # Parameters related to the initial conditions InitialConditions: file_name: ./uniform_DM_box.hdf5 + periodic: 1 \ No newline at end of file diff --git a/examples/GreshoVortex_2D/gresho.yml b/examples/GreshoVortex_2D/gresho.yml index df941450196a7de6cd1471e1d258756ca8c36fb1..2006bb451179ce646ec2cc41cb3aa5603489dc29 100644 --- a/examples/GreshoVortex_2D/gresho.yml +++ b/examples/GreshoVortex_2D/gresho.yml @@ -34,3 +34,4 @@ SPH: # Parameters related to the initial conditions InitialConditions: file_name: ./greshoVortex.hdf5 # The file to read + periodic: 1 \ No newline at end of file diff --git a/examples/GreshoVortex_2D/makeIC.py b/examples/GreshoVortex_2D/makeIC.py index 4f4ec3407b04971882fbf3d7d7479e74bf56c762..4fb382925e41a1d00463b369bc8d95c4bc6b0aa1 100644 --- a/examples/GreshoVortex_2D/makeIC.py +++ b/examples/GreshoVortex_2D/makeIC.py @@ -89,10 +89,6 @@ grp.attrs["MassTable"] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] grp.attrs["Flag_Entropy_ICs"] = [0, 0, 0, 0, 0, 0] grp.attrs["Dimension"] = 2 -#Runtime parameters -grp = fileOutput.create_group("/RuntimePars") -grp.attrs["PeriodicBoundariesOn"] = 1 - #Units grp = fileOutput.create_group("/Units") grp.attrs["Unit length in cgs (U_L)"] = 1. diff --git a/examples/GreshoVortex_3D/gresho.yml b/examples/GreshoVortex_3D/gresho.yml index 113c03b9bd0e411bf04f29c70937ac7fab3708f3..a95a0eae3255b87337fc838f1eabe5469a724a09 100644 --- a/examples/GreshoVortex_3D/gresho.yml +++ b/examples/GreshoVortex_3D/gresho.yml @@ -35,3 +35,4 @@ SPH: # Parameters related to the initial conditions InitialConditions: file_name: ./greshoVortex.hdf5 # The file to read + periodic: 1 \ No newline at end of file diff --git a/examples/GreshoVortex_3D/makeIC.py b/examples/GreshoVortex_3D/makeIC.py index cba2158016bc86f58b6e89f83cbfb473798e1cf7..03f99df1082928bd57779ff2c0e7e85f112b4f1f 100644 --- a/examples/GreshoVortex_3D/makeIC.py +++ b/examples/GreshoVortex_3D/makeIC.py @@ -90,10 +90,6 @@ grp.attrs["MassTable"] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] grp.attrs["Flag_Entropy_ICs"] = [0, 0, 0, 0, 0, 0] grp.attrs["Dimension"] = 3 -#Runtime parameters -grp = fileOutput.create_group("/RuntimePars") -grp.attrs["PeriodicBoundariesOn"] = 1 - #Units grp = fileOutput.create_group("/Units") grp.attrs["Unit length in cgs (U_L)"] = 1. diff --git a/examples/Hernquist_circularorbit/hernquistcirc.yml b/examples/Hernquist_circularorbit/hernquistcirc.yml new file mode 100755 index 0000000000000000000000000000000000000000..5e81d180003283ecb74209b19e1ff3db8097b08f --- /dev/null +++ b/examples/Hernquist_circularorbit/hernquistcirc.yml @@ -0,0 +1,38 @@ +# Define the system of units to use internally. +InternalUnitSystem: + UnitMass_in_cgs: 1.988e+33 # Grams + UnitLength_in_cgs: 3.086e+21 # Centimeters + UnitVelocity_in_cgs: 1e5 # Centimeters per second + UnitCurrent_in_cgs: 1 # Amperes + UnitTemp_in_cgs: 1 # Kelvin + +# Parameters governing the time integration (Set dt_min and dt_max to the same value for a fixed time-step run.) +TimeIntegration: + time_begin: 0. # The starting time of the simulation (in internal units). + time_end: 2.0 # The end time of the simulation (in internal units). + dt_min: 1e-10 # The minimal time-step size of the simulation (in internal units). + dt_max: 1e0 # The maximal time-step size of the simulation (in internal units). + +# Parameters governing the snapshots +Snapshots: + basename: output # Common part of the name of output files + time_first: 0. # Time of the first output (in internal units) + delta_time: 1e-3 # Time difference between consecutive outputs (in internal units) + +# Parameters governing the conserved quantities statistics +Statistics: + delta_time: 1e0 # Time between statistics output + +# Parameters related to the initial conditions +InitialConditions: + file_name: circularorbitshernquist.hdf5 # The file to read + periodic: 0 + +# Hernquist potential parameters +HernquistPotential: + useabspos: 0 # 0 -> positions based on centre, 1 -> absolute positions + position: [0.,0.,0.] # Location of centre of isothermal potential with respect to centre of the box (if 0) otherwise absolute (if 1) (internal units) + mass: 2e12 # Mass of the Hernquist potential + scalelength: 10.0 # Scale length of the potential + timestep_mult: 0.005 # Dimensionless pre-factor for the time-step condition + epsilon: 0.1 # Softening size (internal units) diff --git a/examples/Hernquist_circularorbit/makeIC.py b/examples/Hernquist_circularorbit/makeIC.py new file mode 100755 index 0000000000000000000000000000000000000000..474450f0e23704bfc43730872a978107f28704e9 --- /dev/null +++ b/examples/Hernquist_circularorbit/makeIC.py @@ -0,0 +1,81 @@ +############################################################################### +# This file is part of SWIFT. +# Copyright (c) 2018 Folkert Nobels (nobels@strw.leidenuniv.nl) +# +# 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/>. +# +################################################################################ +from galpy.potential import NFWPotential +from galpy.orbit import Orbit +from galpy.util import bovy_conversion +import numpy as np +import matplotlib.pyplot as plt +from astropy import units +import h5py as h5 + +C = 8.0 +M_200 = 2.0 +N_PARTICLES = 3 +print("Initial conditions written to 'test_nfw.hdf5'") + +pos = np.zeros((3, 3)) +pos[0, 2] = 50.0 +pos[1, 2] = 10.0 +pos[2, 2] = 2.0 +pos = pos + 500.0 +vel = np.zeros((3, 3)) +vel[0, 1] = 348.0 +vel[1, 1] = 466.9 +vel[2, 1] = 348.0 +ids = np.array([1.0, 2.0, 3.0]) +mass = np.array([1.0, 1.0, 1.0]) + +# File +file = h5.File("circularorbitshernquist.hdf5", "w") + +# Units +grp = file.create_group("/Units") +grp.attrs["Unit length in cgs (U_L)"] = 3.086e21 +grp.attrs["Unit mass in cgs (U_M)"] = 1.988e33 +grp.attrs["Unit time in cgs (U_t)"] = 3.086e16 +grp.attrs["Unit current in cgs (U_I)"] = 1.0 +grp.attrs["Unit temperature in cgs (U_T)"] = 1.0 + +# Header +grp = file.create_group("/Header") +grp.attrs["BoxSize"] = 1000.0 +grp.attrs["NumPart_Total"] = [0, N_PARTICLES, 0, 0, 0, 0] +grp.attrs["NumPart_Total_HighWord"] = [0, 0, 0, 0, 0, 0] +grp.attrs["NumPart_ThisFile"] = [0, N_PARTICLES, 0, 0, 0, 0] +grp.attrs["Time"] = 0.0 +grp.attrs["NumFilesPerSnapshot"] = 1 +grp.attrs["MassTable"] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] +grp.attrs["Flag_Entropy_ICs"] = [0, 0, 0, 0, 0, 0] +grp.attrs["Dimension"] = 3 + +# Runtime parameters +grp = file.create_group("/RuntimePars") +grp.attrs["PeriodicBoundariesOn"] = 1 + +# Particle group +grp1 = file.create_group("/PartType1") +ds = grp1.create_dataset("Velocities", (N_PARTICLES, 3), "f", data=vel) + +ds = grp1.create_dataset("Masses", (N_PARTICLES,), "f", data=mass) + +ds = grp1.create_dataset("ParticleIDs", (N_PARTICLES,), "L", data=ids) + +ds = grp1.create_dataset("Coordinates", (N_PARTICLES, 3), "d", data=pos) + +file.close() diff --git a/examples/Hernquist_circularorbit/plotprog.py b/examples/Hernquist_circularorbit/plotprog.py new file mode 100755 index 0000000000000000000000000000000000000000..849ae4e365e0712faac7436a9b01a4e51c9794f0 --- /dev/null +++ b/examples/Hernquist_circularorbit/plotprog.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python +############################################################################### +# This file is part of SWIFT. +# Copyright (c) 2018 Folkert Nobels (nobels@strw.leidenuniv.nl) +# +# 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 numpy as np +import h5py +import matplotlib.pyplot as plt +from scipy.integrate import odeint + +t = np.linspace(0, 40, 1e5) +y0 = [0, 10] +a = 30.0 +G = 4.300927e-06 +M = 1e15 +GM = G * M + + +lengthrun = 2001 +numbpar = 3 + +radius = np.zeros((numbpar, lengthrun)) +xx = np.zeros((numbpar, lengthrun)) +yy = np.zeros((numbpar, lengthrun)) +zz = np.zeros((numbpar, lengthrun)) +time = np.zeros(lengthrun) +for i in range(0, lengthrun): + Data = h5py.File("output_%04d.hdf5" % i, "r") + header = Data["Header"] + time[i] = header.attrs["Time"] + particles = Data["PartType1"] + positions = particles["Coordinates"] + xx[:, i] = positions[:, 0] - 500.0 + yy[:, i] = positions[:, 1] - 500.0 + zz[:, i] = positions[:, 2] - 500.0 + +col = ["b", "r", "c", "y", "k"] +print(np.shape(xx), np.shape(yy), np.shape(zz)) + +for i in range(0, numbpar): + plt.plot(xx[i, :], yy[i, :], col[i]) + +plt.ylabel("y (kpc)") +plt.xlabel("x (kpc)") +plt.savefig("xyplot.png") +plt.close() + + +for i in range(0, numbpar): + plt.plot(xx[i, :], zz[i, :], col[i]) + +plt.ylabel("z (kpc)") +plt.xlabel("x (kpc)") +plt.savefig("xzplot.png") +plt.close() + +for i in range(0, numbpar): + plt.plot(yy[i, :], zz[i, :], col[i]) + +plt.ylabel("z (kpc)") +plt.xlabel("y (kpc)") +plt.savefig("yzplot.png") +plt.close() diff --git a/examples/Hernquist_circularorbit/run.sh b/examples/Hernquist_circularorbit/run.sh new file mode 100755 index 0000000000000000000000000000000000000000..a2fedd0914edece43995d20776e048fd85e33963 --- /dev/null +++ b/examples/Hernquist_circularorbit/run.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +if [ ! -e circularorbitshernquist.hdf5 ] +then + echo "Generate initial conditions for circular orbits" + if command -v python3 &>/dev/null; then + python3 makeIC.py + else + python makeIC.py + fi + +fi + +# self gravity G, external potential g, hydro s, threads t and high verbosity v +../swift -g -t 6 hernquistcirc.yml 2>&1 | tee output.log + + +echo "Save plots of the circular orbits" +if command -v python3 &>/dev/null; then + python3 plotprog.py +else + python plotprog.py +fi diff --git a/examples/Hernquist_radialinfall/README b/examples/Hernquist_radialinfall/README new file mode 100644 index 0000000000000000000000000000000000000000..be22a1a11a5b1e0538723781607aa374644a4e0f --- /dev/null +++ b/examples/Hernquist_radialinfall/README @@ -0,0 +1,3 @@ +This example generates 5 particles at radii of 10, 20, 30, 40 and 50 kpc +without velocitiy and follows the evolution of these particles in an Hernquist +potential as they are free falling. diff --git a/examples/Hernquist_radialinfall/hernquist.yml b/examples/Hernquist_radialinfall/hernquist.yml new file mode 100644 index 0000000000000000000000000000000000000000..adea54ed9a33ee889b39bb519c8098917b33ef9f --- /dev/null +++ b/examples/Hernquist_radialinfall/hernquist.yml @@ -0,0 +1,39 @@ +# Define the system of units to use internally. +InternalUnitSystem: + UnitMass_in_cgs: 1.98848e33 # M_sun + UnitLength_in_cgs: 3.08567758e21 # kpc + UnitVelocity_in_cgs: 1e5 # km/s + UnitCurrent_in_cgs: 1 # Amperes + UnitTemp_in_cgs: 1 # Kelvin + +# Parameters governing the time integration +TimeIntegration: + time_begin: 0. # The starting time of the simulation (in internal units). + time_end: 40. # The end time of the simulation (in internal units). + dt_min: 9e-10 # The minimal time-step size of the simulation (in internal units). + dt_max: 1e-2 # The maximal time-step size of the simulation (in internal units). + +# Parameters governing the conserved quantities statistics +Statistics: + delta_time: 1e-3 # Time between statistics output + +# Parameters governing the snapshots +Snapshots: + basename: hernquist # Common part of the name of output files + time_first: 0. # Time of the first output (in internal units) + delta_time: 0.02 # Time difference between consecutive outputs (in internal units) + +# Parameters related to the initial conditions +InitialConditions: + file_name: Hernquist.hdf5 # The file to read + periodic: 1 + shift: [200.,200.,200.] # Shift all particles to be in the potential + +# External potential parameters +HernquistPotential: + useabspos: 0 # Whether to use absolute position (1) or relative potential to centre of box (0) + position: [0.,0.,0.] + mass: 1e9 + scalelength: 1.0 + timestep_mult: 0.01 # controls time step + epsilon: 2.0 # No softening at the centre of the halo diff --git a/examples/Hernquist_radialinfall/makeIC.py b/examples/Hernquist_radialinfall/makeIC.py new file mode 100644 index 0000000000000000000000000000000000000000..567e15a95302bc8848c1d026b82dc5be54c7a0c6 --- /dev/null +++ b/examples/Hernquist_radialinfall/makeIC.py @@ -0,0 +1,167 @@ +############################################################################### +# This file is part of SWIFT. +# Copyright (c) 2018 Folkert Nobels (nobels@strw.leidenuniv.nl) +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +############################################################################## + +import h5py +import sys +import numpy +import math +import random +import numpy as np + +# Generates N particles in a spherical distribution centred on [0,0,0], to be moved in an isothermal potential +# usage: python makeIC.py 1000 0 : generate 1000 particles on circular orbits +# python makeIC.py 1000 1 : generate 1000 particles with Lz/L uniform in [0,1] +# all particles move in the xy plane, and start at y=0 + +# physical constants in cgs +NEWTON_GRAVITY_CGS = 6.67408e-8 +SOLAR_MASS_IN_CGS = 1.98848e33 +PARSEC_IN_CGS = 3.08567758e18 +YEAR_IN_CGS = 3.15569252e7 + +# choice of units +const_unit_length_in_cgs = 1000 * PARSEC_IN_CGS +const_unit_mass_in_cgs = SOLAR_MASS_IN_CGS +const_unit_velocity_in_cgs = 1e5 + + +# Properties of the Hernquist potential +Mass = 1e15 +scaleLength = 30.0 # kpc + + +# derived units +const_unit_time_in_cgs = const_unit_length_in_cgs / const_unit_velocity_in_cgs +const_G = ( + NEWTON_GRAVITY_CGS + * const_unit_mass_in_cgs + * const_unit_time_in_cgs + * const_unit_time_in_cgs + / (const_unit_length_in_cgs * const_unit_length_in_cgs * const_unit_length_in_cgs) +) +print("G=", const_G) + + +def hernquistcircvel(r, M, a): + """ Function that calculates the circular velocity in a + Hernquist potential. + @param r: radius from centre of potential + @param M: mass of the Hernquist potential + @param a: Scale length of the potential + @return: circular velocity + """ + return (const_G * M * r) ** 0.5 / (r + a) + + +# Parameters +periodic = 1 # 1 For periodic box +boxSize = 400.0 # [kpc] +Radius = 100.0 # maximum radius of particles [kpc] +G = const_G + +N = 5 +L = N ** (1.0 / 3.0) + +fileName = "Hernquist.hdf5" + + +# --------------------------------------------------- +numPart = N +mass = 1 + +# -------------------------------------------------- + +# File +file = h5py.File(fileName, "w") + +# Units +grp = file.create_group("/Units") +grp.attrs["Unit length in cgs (U_L)"] = const_unit_length_in_cgs +grp.attrs["Unit mass in cgs (U_M)"] = const_unit_mass_in_cgs +grp.attrs["Unit time in cgs (U_t)"] = ( + const_unit_length_in_cgs / const_unit_velocity_in_cgs +) +grp.attrs["Unit current in cgs (U_I)"] = 1.0 +grp.attrs["Unit temperature in cgs (U_T)"] = 1.0 + +# Header +grp = file.create_group("/Header") +grp.attrs["BoxSize"] = boxSize +grp.attrs["NumPart_Total"] = [0, numPart, 0, 0, 0, 0] +grp.attrs["NumPart_Total_HighWord"] = [0, 0, 0, 0, 0, 0] +grp.attrs["NumPart_ThisFile"] = [0, numPart, 0, 0, 0, 0] +grp.attrs["Time"] = 0.0 +grp.attrs["NumFilesPerSnapshot"] = 1 +grp.attrs["MassTable"] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] +grp.attrs["Flag_Entropy_ICs"] = [0, 0, 0, 0, 0, 0] +grp.attrs["Dimension"] = 3 + +# set seed for random number +numpy.random.seed(1234) + +# Particle group +grp1 = file.create_group("/PartType1") +# generate particle positions +# radius = Radius * (numpy.random.rand(N))**(1./3.) + 10. +radius = np.zeros(N) +radius[0] = 10 +radius[1] = 20 +radius[2] = 30 +radius[3] = 40 +radius[4] = 50 +# this part is not even used: +# ctheta = -1. + 2 * numpy.random.rand(N) +# stheta = numpy.sqrt(1.-ctheta**2) +# phi = 2 * math.pi * numpy.random.rand(N) +# end +r = numpy.zeros((numPart, 3)) +r[:, 0] = radius + +# import matplotlib.pyplot as plt +# plt.plot(r[:,0],'.') +# plt.show() + +# print('Mass = ', Mass) +# print('radius = ', radius) +# print('scaleLength = ',scaleLength) +# +v = numpy.zeros((numPart, 3)) +# v[:,0] = hernquistcircvel(radius,Mass,scaleLength) +omega = v[:, 0] / radius +period = 2.0 * math.pi / omega +print("period = minimum = ", min(period), " maximum = ", max(period)) +print("Circular velocity = minimum =", min(v[:, 0]), " maximum = ", max(v[:, 0])) + +omegav = omega + +v[:, 0] = -omegav * r[:, 1] +v[:, 1] = omegav * r[:, 0] + +ds = grp1.create_dataset("Velocities", (numPart, 3), "f", data=v) + +m = numpy.full((numPart,), mass, dtype="f") +ds = grp1.create_dataset("Masses", (numPart,), "f", data=m) + +ids = 1 + numpy.linspace(0, numPart, numPart, endpoint=False) +ds = grp1.create_dataset("ParticleIDs", (numPart,), "L", data=ids) + +ds = grp1.create_dataset("Coordinates", (numPart, 3), "d", data=r) + + +file.close() diff --git a/examples/Hernquist_radialinfall/plotprog.py b/examples/Hernquist_radialinfall/plotprog.py new file mode 100755 index 0000000000000000000000000000000000000000..d8de00a6b694bb33bf96ef7065c972aa6bb3f6cb --- /dev/null +++ b/examples/Hernquist_radialinfall/plotprog.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python +############################################################################### +# This file is part of SWIFT. +# Copyright (c) 2018 Folkert Nobels (nobels@strw.leidenuniv.nl) +# +# 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 numpy as np +import h5py +import matplotlib.pyplot as plt +from scipy.integrate import odeint + + +lengthrun = 2001 +numbpar = 5 + +radius = np.zeros((numbpar, lengthrun)) +time = np.zeros(lengthrun) +for i in range(0, lengthrun): + Data = h5py.File("hernquist_%04d.hdf5" % i, "r") + header = Data["Header"] + time[i] = header.attrs["Time"] + particles = Data["PartType1"] + positions = particles["Coordinates"] + radius[:, i] = positions[:, 0] - 200.0 + +col = ["b", "r", "c", "y", "k"] + +for i in range(0, numbpar): + plt.plot(time, radius[i, :], col[i]) + plt.axhline(np.max(radius[i, :]), color=col[i], linestyle="--") + plt.axhline(-np.max(radius[i, :]), color=col[i], linestyle="--") + + +plt.ylabel("Radial distance (kpc)") +plt.xlabel("Simulation time (internal units)") +plt.savefig("radial_infall.png") +plt.close() diff --git a/examples/Hernquist_radialinfall/run.sh b/examples/Hernquist_radialinfall/run.sh new file mode 100755 index 0000000000000000000000000000000000000000..b2bcd99f9e7b0e571cffcd18b0fc29e50cad8b06 --- /dev/null +++ b/examples/Hernquist_radialinfall/run.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +# Generate the initial conditions if they are not present. +if [ ! -e Hernquist.hdf5 ] +then + echo "Generate initial conditions for radial orbits" + if command -v python3 &>/dev/null; then + python3 makeIC.py + else + python makeIC.py + fi +fi + +rm -rf hernquist_*.hdf5 +../swift -g -t 1 hernquist.yml 2>&1 | tee output.log + + + +echo "Make plots of the radially free falling particles" +if command -v python3 &>/dev/null; then + python3 plotprog.py +else + python plotprog.py +fi diff --git a/examples/HydrostaticHalo/hydrostatic.yml b/examples/HydrostaticHalo/hydrostatic.yml index 0cc11d0d8708b518b8b0b3a8df1374b6a5ead7e2..874d6344cf5787bb310b6a1b730acb3455a8b6a6 100644 --- a/examples/HydrostaticHalo/hydrostatic.yml +++ b/examples/HydrostaticHalo/hydrostatic.yml @@ -31,7 +31,8 @@ SPH: # Parameters related to the initial conditions InitialConditions: file_name: Hydrostatic.hdf5 # The file to read - + periodic: 1 + # External potential parameters IsothermalPotential: vrot: 200. # rotation speed of isothermal potential in internal units diff --git a/examples/HydrostaticHalo/makeIC.py b/examples/HydrostaticHalo/makeIC.py index d5081ac84473edc87857c6872278b4d0ca6389b1..b8a4036b77c430866f700047fd06bf2c8de490e7 100644 --- a/examples/HydrostaticHalo/makeIC.py +++ b/examples/HydrostaticHalo/makeIC.py @@ -91,10 +91,6 @@ grp.attrs["Unit current in cgs (U_I)"] = 1. grp.attrs["Unit temperature in cgs (U_T)"] = 1. -# Runtime parameters -grp = file.create_group("/RuntimePars") -grp.attrs["PeriodicBoundariesOn"] = periodic - # set seed for random number np.random.seed(1234) diff --git a/examples/InteractingBlastWaves_1D/interactingBlastWaves.yml b/examples/InteractingBlastWaves_1D/interactingBlastWaves.yml index e845599730828fd7b9880ae9aca11420ba50026c..c4960dfa2c07b6b08cd6559b1de49f27b518bf94 100644 --- a/examples/InteractingBlastWaves_1D/interactingBlastWaves.yml +++ b/examples/InteractingBlastWaves_1D/interactingBlastWaves.yml @@ -31,3 +31,4 @@ SPH: # Parameters related to the initial conditions InitialConditions: file_name: ./interactingBlastWaves.hdf5 # The file to read + periodic: 1 diff --git a/examples/InteractingBlastWaves_1D/makeIC.py b/examples/InteractingBlastWaves_1D/makeIC.py index bed0e20c833ccbe54ed571b954cad03ab93f4c0c..3a47bf7c42e1359dc1a9aa151e360ad0f93d2d32 100644 --- a/examples/InteractingBlastWaves_1D/makeIC.py +++ b/examples/InteractingBlastWaves_1D/makeIC.py @@ -62,10 +62,6 @@ 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 -#Runtime parameters -grp = file.create_group("/RuntimePars") -grp.attrs["PeriodicBoundariesOn"] = 1 - #Units grp = file.create_group("/Units") grp.attrs["Unit length in cgs (U_L)"] = 1. diff --git a/examples/IsothermalPotential/energy_plot.py b/examples/IsothermalPotential/energy_plot.py index dab30715fbdaa0393f62c764ba552bbe4106325d..d157e4233cae2221f23d37f6bdf0c30a2486f972 100644 --- a/examples/IsothermalPotential/energy_plot.py +++ b/examples/IsothermalPotential/energy_plot.py @@ -86,7 +86,7 @@ for i in range(402): time_snap[i] = f["Header"].attrs["Time"] E_kin_snap[i] = np.sum(0.5 * mass * (vel_x[:]**2 + vel_y[:]**2 + vel_z[:]**2)) - E_pot_snap[i] = np.sum(-mass * Vrot**2 * log(r)) + E_pot_snap[i] = np.sum(mass * Vrot**2 * log(r)) E_tot_snap[i] = E_kin_snap[i] + E_pot_snap[i] Lz_snap[i] = np.sum(Lz) diff --git a/examples/IsothermalPotential/isothermal.yml b/examples/IsothermalPotential/isothermal.yml index 5f626ff72e979ad0f3d404e01002be6b6018c758..4f8d98a1f7615659ddb3c922b149fc2db04415c6 100644 --- a/examples/IsothermalPotential/isothermal.yml +++ b/examples/IsothermalPotential/isothermal.yml @@ -26,10 +26,13 @@ Snapshots: # Parameters related to the initial conditions InitialConditions: file_name: Isothermal.hdf5 # The file to read + periodic: 1 shift: [200.,200.,200.] # Shift all particles to be in the potential # External potential parameters IsothermalPotential: + useabspos: 0 # Whether to use absolute position (1) or relative potential to centre of box (0) + position: [0.,0.,0.] vrot: 200. # rotation speed of isothermal potential in internal units timestep_mult: 0.01 # controls time step epsilon: 0. # No softening at the centre of the halo diff --git a/examples/IsothermalPotential/makeIC.py b/examples/IsothermalPotential/makeIC.py index eab16d21e6a4abd077dc0f4a015a4577427a3591..ebcbb6dda11f1a2d88dfcfb717578f114f3512e9 100644 --- a/examples/IsothermalPotential/makeIC.py +++ b/examples/IsothermalPotential/makeIC.py @@ -97,10 +97,6 @@ grp.attrs["MassTable"] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] grp.attrs["Flag_Entropy_ICs"] = [0, 0, 0, 0, 0, 0] grp.attrs["Dimension"] = 3 -#Runtime parameters -grp = file.create_group("/RuntimePars") -grp.attrs["PeriodicBoundariesOn"] = periodic - # set seed for random number numpy.random.seed(1234) diff --git a/examples/KelvinHelmholtzGrowthRate_2D/kelvinHelmholtzGrowthRate.yml b/examples/KelvinHelmholtzGrowthRate_2D/kelvinHelmholtzGrowthRate.yml index 380dc2ab3a530e89b952aa41f425e50709d73ee9..e5a46cca1aa0c8972a5427126d2ce57a26d1b262 100644 --- a/examples/KelvinHelmholtzGrowthRate_2D/kelvinHelmholtzGrowthRate.yml +++ b/examples/KelvinHelmholtzGrowthRate_2D/kelvinHelmholtzGrowthRate.yml @@ -31,3 +31,4 @@ SPH: # Parameters related to the initial conditions InitialConditions: file_name: ./kelvinHelmholtzGrowthRate.hdf5 # The file to read + periodic: 1 diff --git a/examples/KelvinHelmholtzGrowthRate_2D/makeIC.py b/examples/KelvinHelmholtzGrowthRate_2D/makeIC.py index f21d0c0abf9b15f8253f627bcb1da43ae276fb35..25ef65fd758e0dd97d45732a2da6d2aa19f793bc 100644 --- a/examples/KelvinHelmholtzGrowthRate_2D/makeIC.py +++ b/examples/KelvinHelmholtzGrowthRate_2D/makeIC.py @@ -76,10 +76,6 @@ grp.attrs["MassTable"] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] grp.attrs["Flag_Entropy_ICs"] = [0, 0, 0, 0, 0, 0] grp.attrs["Dimension"] = 2 -#Runtime parameters -grp = fileOutput.create_group("/RuntimePars") -grp.attrs["PeriodicBoundariesOn"] = 1 - #Units grp = fileOutput.create_group("/Units") grp.attrs["Unit length in cgs (U_L)"] = 1. diff --git a/examples/KelvinHelmholtzGrowthRate_2D/makeIC_regular.py b/examples/KelvinHelmholtzGrowthRate_2D/makeIC_regular.py index 5029165a6a328b6c706d37b632b14cbcd51501d0..55cd17823a1101164191c89810029370dee21e26 100644 --- a/examples/KelvinHelmholtzGrowthRate_2D/makeIC_regular.py +++ b/examples/KelvinHelmholtzGrowthRate_2D/makeIC_regular.py @@ -82,10 +82,6 @@ grp.attrs["MassTable"] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] grp.attrs["Flag_Entropy_ICs"] = [0, 0, 0, 0, 0, 0] grp.attrs["Dimension"] = 2 -#Runtime parameters -grp = fileOutput.create_group("/RuntimePars") -grp.attrs["PeriodicBoundariesOn"] = 1 - #Units grp = fileOutput.create_group("/Units") grp.attrs["Unit length in cgs (U_L)"] = 1. diff --git a/examples/KelvinHelmholtzGrowthRate_3D/kelvinHelmholtzGrowthRate.yml b/examples/KelvinHelmholtzGrowthRate_3D/kelvinHelmholtzGrowthRate.yml index e39c01645b766ae585558452683dc8e1bdf425a8..f5f7157f7d3252e8fe256b7bfc4ba83cb09ef03e 100644 --- a/examples/KelvinHelmholtzGrowthRate_3D/kelvinHelmholtzGrowthRate.yml +++ b/examples/KelvinHelmholtzGrowthRate_3D/kelvinHelmholtzGrowthRate.yml @@ -32,3 +32,4 @@ SPH: # Parameters related to the initial conditions InitialConditions: file_name: ./kelvinHelmholtzGrowthRate.hdf5 # The file to read + periodic: 1 diff --git a/examples/KelvinHelmholtzGrowthRate_3D/makeIC.py b/examples/KelvinHelmholtzGrowthRate_3D/makeIC.py index a9bc20559b9fbb5da400ba5de2563cd715f473d5..d28f3617214193eca6159a7220263d36500dd1aa 100644 --- a/examples/KelvinHelmholtzGrowthRate_3D/makeIC.py +++ b/examples/KelvinHelmholtzGrowthRate_3D/makeIC.py @@ -76,10 +76,6 @@ grp.attrs["MassTable"] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] grp.attrs["Flag_Entropy_ICs"] = [0, 0, 0, 0, 0, 0] grp.attrs["Dimension"] = 3 -#Runtime parameters -grp = fileOutput.create_group("/RuntimePars") -grp.attrs["PeriodicBoundariesOn"] = 1 - #Units grp = fileOutput.create_group("/Units") grp.attrs["Unit length in cgs (U_L)"] = 1. diff --git a/examples/KelvinHelmholtzGrowthRate_3D/makeIC_regular.py b/examples/KelvinHelmholtzGrowthRate_3D/makeIC_regular.py index aa7dd8f214f8ece1c1d142bf02bd653cd35f9973..51ab694f387d380c83a0b646696fd23111b3f98c 100644 --- a/examples/KelvinHelmholtzGrowthRate_3D/makeIC_regular.py +++ b/examples/KelvinHelmholtzGrowthRate_3D/makeIC_regular.py @@ -84,10 +84,6 @@ grp.attrs["MassTable"] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] grp.attrs["Flag_Entropy_ICs"] = [0, 0, 0, 0, 0, 0] grp.attrs["Dimension"] = 3 -#Runtime parameters -grp = fileOutput.create_group("/RuntimePars") -grp.attrs["PeriodicBoundariesOn"] = 1 - #Units grp = fileOutput.create_group("/Units") grp.attrs["Unit length in cgs (U_L)"] = 1. diff --git a/examples/KelvinHelmholtz_2D/kelvinHelmholtz.yml b/examples/KelvinHelmholtz_2D/kelvinHelmholtz.yml index ccc7526b391374a4da0883f6615a65c7b93a0948..6e4e2bd43cfa3def8386b85c84570e9b9a48fbcf 100644 --- a/examples/KelvinHelmholtz_2D/kelvinHelmholtz.yml +++ b/examples/KelvinHelmholtz_2D/kelvinHelmholtz.yml @@ -31,3 +31,4 @@ SPH: # Parameters related to the initial conditions InitialConditions: file_name: ./kelvinHelmholtz.hdf5 # The file to read + periodic: 1 diff --git a/examples/KelvinHelmholtz_2D/makeIC.py b/examples/KelvinHelmholtz_2D/makeIC.py index 744b39de8260720521ae8e77ed5d0a12161f2b6a..919066955c519dbac4e78e8e2a0eece842c40ab3 100644 --- a/examples/KelvinHelmholtz_2D/makeIC.py +++ b/examples/KelvinHelmholtz_2D/makeIC.py @@ -122,10 +122,6 @@ grp.attrs["MassTable"] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] grp.attrs["Flag_Entropy_ICs"] = [0, 0, 0, 0, 0, 0] grp.attrs["Dimension"] = 2 -#Runtime parameters -grp = fileOutput.create_group("/RuntimePars") -grp.attrs["PeriodicBoundariesOn"] = 1 - #Units grp = fileOutput.create_group("/Units") grp.attrs["Unit length in cgs (U_L)"] = 1. diff --git a/examples/KeplerianRing/keplerian_ring.yml b/examples/KeplerianRing/keplerian_ring.yml index cc5db2a06adbe9678207454c6504a6fa315675cf..2195acfb55121ff595c471ad146b40752d9aa84e 100644 --- a/examples/KeplerianRing/keplerian_ring.yml +++ b/examples/KeplerianRing/keplerian_ring.yml @@ -32,7 +32,8 @@ SPH: # Parameters related to the initial conditions InitialConditions: file_name: initial_conditions.hdf5 # The file to read - + periodic: 1 + # External potential parameters PointMassPotential: position: [5.,5.,5.] # location of external point mass in internal units diff --git a/examples/Makefile.am b/examples/Makefile.am index dae300933aa1c8a479d4c44b604c5ad11b5a0217..91c8baeadeb2db2644b8b8bd2fc2e9d0c666f979 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -19,7 +19,7 @@ MYFLAGS = # 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) $(GRACKLE_INCS) AM_LDFLAGS = $(HDF5_LDFLAGS) @@ -97,7 +97,8 @@ EXTRA_DIST = CoolingBox/coolingBox.yml CoolingBox/energy_plot.py CoolingBox/make PerturbedBox_3D/makeIC.py PerturbedBox_3D/perturbedBox.yml PerturbedBox_3D/run.sh \ PMillennium-384/p-mill-384.yml \ PMillennium-768/p-mill-768.yml \ - SantaBarbara/README SantaBarbara/getIC.sh SantaBarbara/santa_barbara.yml \ + SantaBarbara/README SantaBarbara/getIC.sh SantaBarbara/santa_barbara.yml SantaBarbara/run.sh \ + SantaBarbara_low/README SantaBarbara_low/getIC.sh SantaBarbara_low/santa_barbara.yml SantaBarbara_low/run.sh \ SedovBlast_1D/makeIC.py SedovBlast_1D/plotSolution.py SedovBlast_1D/run.sh SedovBlast_1D/sedov.yml \ SedovBlast_2D/getGlass.sh SedovBlast_2D/makeIC.py SedovBlast_2D/plotSolution.py SedovBlast_2D/run.sh SedovBlast_2D/sedov.yml \ SedovBlast_3D/getGlass.sh SedovBlast_3D/makeIC.py SedovBlast_3D/plotSolution.py SedovBlast_3D/run.sh SedovBlast_3D/sedov.yml \ diff --git a/examples/MultiTypes/makeIC.py b/examples/MultiTypes/makeIC.py index 41a5ef5f2ffc4073ef8a4e93a130b43fcbe2c1f5..80d49c762b1fe13bbfafd05c6818d3f202e5b033 100644 --- a/examples/MultiTypes/makeIC.py +++ b/examples/MultiTypes/makeIC.py @@ -93,10 +93,6 @@ for n in range(num_files): grp.attrs["MassTable"] = [0.0, massDM, 0.0, 0.0, 0.0, 0.0] grp.attrs["Flag_Entropy_ICs"] = 0 grp.attrs["Dimension"] = 3 - - #Runtime parameters - grp = file.create_group("/RuntimePars") - grp.attrs["PeriodicBoundariesOn"] = periodic #Units grp = file.create_group("/Units") diff --git a/examples/MultiTypes/multiTypes.yml b/examples/MultiTypes/multiTypes.yml index 04647f0f00e69f5baf2560aca0feeb14a26cc50a..121a15b0837df19e4d2e9e64a56107c24fbde066 100644 --- a/examples/MultiTypes/multiTypes.yml +++ b/examples/MultiTypes/multiTypes.yml @@ -31,6 +31,7 @@ SPH: # Parameters related to the initial conditions InitialConditions: file_name: ./multiTypes.hdf5 # The file to read + periodic: 1 replicate: 2 # Replicate all particles twice along each axis # External potential parameters diff --git a/examples/NFW_Halo/README b/examples/NFW_Halo/README new file mode 100755 index 0000000000000000000000000000000000000000..059d35c9a94d7851233dd0fa423abca3a1d7cddf --- /dev/null +++ b/examples/NFW_Halo/README @@ -0,0 +1,5 @@ +This just provides a test that the NFW potential is giving the correct orbit +for an elliptical orbit as calculated by Jo Bovy's galpy package. If +galpy is not installed on your system you can install it by using: +pp install galpy --user + diff --git a/examples/NFW_Halo/makeIC.py b/examples/NFW_Halo/makeIC.py new file mode 100755 index 0000000000000000000000000000000000000000..68d8108f84aa759fe16956226122d53765c5ed1d --- /dev/null +++ b/examples/NFW_Halo/makeIC.py @@ -0,0 +1,75 @@ +################################################################################ +# This file is part of SWIFT. +# Copyright (c) 2018 Ashley Kelly () +# Folkert Nobels (nobels@strw.leidenuniv.nl) +# +# 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 numpy as np +import matplotlib.pyplot as plt +from astropy import units +import h5py as h5 + +C = 8.0 +M_200 = 2.0 +N_PARTICLES = 1 + + +print("\nInitial conditions written to 'test_nfw.hdf5'") + +pos = np.array([8.0, 0.0, 0.0]) + 500.0 +vel = np.array([0.0, 240.0, 5.0]) +ids = np.array([1.0]) +mass = np.array([1.0]) + +# File +file = h5.File("test_nfw.hdf5", "w") + +# Units +grp = file.create_group("/Units") +grp.attrs["Unit length in cgs (U_L)"] = 3.086e21 +grp.attrs["Unit mass in cgs (U_M)"] = 1.988e33 +grp.attrs["Unit time in cgs (U_t)"] = 3.086e16 +grp.attrs["Unit current in cgs (U_I)"] = 1.0 +grp.attrs["Unit temperature in cgs (U_T)"] = 1.0 + +# Header +grp = file.create_group("/Header") +grp.attrs["BoxSize"] = 1000.0 +grp.attrs["NumPart_Total"] = [0, N_PARTICLES, 0, 0, 0, 0] +grp.attrs["NumPart_Total_HighWord"] = [0, 0, 0, 0, 0, 0] +grp.attrs["NumPart_ThisFile"] = [0, N_PARTICLES, 0, 0, 0, 0] +grp.attrs["Time"] = 0.0 +grp.attrs["NumFilesPerSnapshot"] = 1 +grp.attrs["MassTable"] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] +grp.attrs["Flag_Entropy_ICs"] = [0, 0, 0, 0, 0, 0] +grp.attrs["Dimension"] = 3 + +# Runtime parameters +grp = file.create_group("/RuntimePars") +grp.attrs["PeriodicBoundariesOn"] = 1 + +# Particle group +grp1 = file.create_group("/PartType1") +ds = grp1.create_dataset("Velocities", (N_PARTICLES, 3), "f", data=vel) + +ds = grp1.create_dataset("Masses", (N_PARTICLES,), "f", data=mass) + +ds = grp1.create_dataset("ParticleIDs", (N_PARTICLES,), "L", data=ids) + +ds = grp1.create_dataset("Coordinates", (N_PARTICLES, 3), "d", data=pos) + +file.close() diff --git a/examples/NFW_Halo/makePlots.py b/examples/NFW_Halo/makePlots.py new file mode 100755 index 0000000000000000000000000000000000000000..5e6f24d7a72dafe47d26ccb1b2d33b136affad98 --- /dev/null +++ b/examples/NFW_Halo/makePlots.py @@ -0,0 +1,73 @@ +################################################################################ +# This file is part of SWIFT. +# Copyright (c) 2018 Ashley Kelly () +# Folkert Nobels (nobels@strw.leidenuniv.nl) +# +# 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/>. +# +################################################################################ +from galpy.potential import NFWPotential +from galpy.orbit import Orbit +import numpy as np +import matplotlib.pyplot as plt +from astropy import units +import h5py as h5 + +C = 8.0 +M_200 = 2.0 + + +def read_data(): + R = np.array([]) + z = np.array([]) + for frame in range(0, 599, 1): + try: + sim = h5.File("output_%04d.hdf5" % frame, "r") + except IOError: + break + + boxSize = sim["/Header"].attrs["BoxSize"][0] + pos = sim["/PartType1/Coordinates"][:, :] - boxSize / 2.0 + R = np.append(R, np.sqrt(pos[0, 0] ** 2 + pos[0, 1] ** 2)) + z = np.append(z, pos[0, 2]) + return (R, z) + + +def galpy_nfw_orbit(): + # Setting up the potential + nfw = NFWPotential(conc=C, mvir=M_200, H=70.0, wrtcrit=True, overdens=200) + nfw.turn_physical_on() + vxvv = [ + 8.0 * units.kpc, + 0.0 * units.km / units.s, + 240.0 * units.km / units.s, + 0.0 * units.pc, + 5.0 * units.km / units.s, + ] + + # Calculating the orbit + ts = np.linspace(0.0, 0.58, 1000) * units.Gyr + o = Orbit(vxvv=vxvv) + o.integrate(ts, nfw, method="odeint") + + return o + + +o = galpy_nfw_orbit() +(R, z) = read_data() + +o.plot() +plt.scatter(R, z, s=1, color="black", marker="x") +plt.savefig("comparison.png") +plt.close() diff --git a/examples/NFW_Halo/run.sh b/examples/NFW_Halo/run.sh new file mode 100755 index 0000000000000000000000000000000000000000..5501f09ef4076715ae9650daf2cded91dbc0be9e --- /dev/null +++ b/examples/NFW_Halo/run.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +if [ ! -e test_nfw.hdf5 ] +then + echo "Generate initial conditions for NFW example" + if command -v python3 &>/dev/null; then + python3 makeIC.py + else + python makeIC.py + fi +fi + +# self gravity G, external potential g, hydro s, threads t and high verbosity v +../swift -g -t 6 test.yml 2>&1 | tee output.log + +if command -v python3 &>/dev/null; then + python3 makePlots.py +else + python makePlots.py +fi diff --git a/examples/NFW_Halo/test.yml b/examples/NFW_Halo/test.yml new file mode 100755 index 0000000000000000000000000000000000000000..73831af30769942bd7aa1c89bd7464025d2ddc85 --- /dev/null +++ b/examples/NFW_Halo/test.yml @@ -0,0 +1,41 @@ +# Define the system of units to use internally. +InternalUnitSystem: + UnitMass_in_cgs: 1.988e+33 # Solar mass + UnitLength_in_cgs: 3.086e+21 # kpc + UnitVelocity_in_cgs: 1e5 # km / s + UnitCurrent_in_cgs: 1 # Amperes + UnitTemp_in_cgs: 1 # Kelvin + +# Parameters governing the time integration (Set dt_min and dt_max to the same value for a fixed time-step run.) +TimeIntegration: + time_begin: 0. # The starting time of the simulation (in internal units). + time_end: 0.6 # The end time of the simulation (in internal units). + dt_min: 1e-8 # The minimal time-step size of the simulation (in internal units). + dt_max: 1e-1 # The maximal time-step size of the simulation (in internal units). + +# Parameters governing the snapshots +Snapshots: + basename: output # Common part of the name of output files + time_first: 0. # Time of the first output (in internal units) + delta_time: 1e-3 # Time difference between consecutive outputs (in internal units) + +# Parameters governing the conserved quantities statistics +Statistics: + delta_time: 1e-3 # Time between statistics output + +# Parameters related to the initial conditions +InitialConditions: + file_name: test_nfw.hdf5 # The file to read + shift_x: 0. # (Optional) A shift to apply to all particles read from the ICs (in internal units). + shift_y: 0. + shift_z: 0. + periodic: 0 + +# Isothermal potential parameters +NFWPotential: + useabspos: 0 + position: [0.0,0.0,0.0] # Location of centre of potential with respect to centre of the box (internal units) + concentration: 8. + M_200: 2.0e+12 # Virial mass (internal units) + critical_density: 140 # Critical density (internal units) + timestep_mult: 0.01 # Dimensionless pre-factor for the time-step condition diff --git a/examples/Noh_1D/makeIC.py b/examples/Noh_1D/makeIC.py index 176f3517455db7a8b0994ac7d1e65fb9cb7419d4..9d9a5e5b62edeedd8f5b2732c240b9ea2878c92d 100644 --- a/examples/Noh_1D/makeIC.py +++ b/examples/Noh_1D/makeIC.py @@ -66,10 +66,6 @@ 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 -#Runtime parameters -grp = file.create_group("/RuntimePars") -grp.attrs["PeriodicBoundariesOn"] = 1 - #Units grp = file.create_group("/Units") grp.attrs["Unit length in cgs (U_L)"] = 1. diff --git a/examples/Noh_1D/noh.yml b/examples/Noh_1D/noh.yml index 1d126f19babd0c9fe28afff907b3fe8259467a24..58e13ddda8939c8fc5fa4360a498a87f1c5b189a 100644 --- a/examples/Noh_1D/noh.yml +++ b/examples/Noh_1D/noh.yml @@ -31,4 +31,6 @@ SPH: # Parameters related to the initial conditions InitialConditions: file_name: ./noh.hdf5 # The file to read + periodic: 1 + \ No newline at end of file diff --git a/examples/Noh_2D/makeIC.py b/examples/Noh_2D/makeIC.py index f7239fa3cd188637df929f86451d20a9978bd1f5..83bb1ac6773074d0c10d3eb425b34c082a971fd8 100644 --- a/examples/Noh_2D/makeIC.py +++ b/examples/Noh_2D/makeIC.py @@ -73,10 +73,6 @@ 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 -#Runtime parameters -grp = file.create_group("/RuntimePars") -grp.attrs["PeriodicBoundariesOn"] = 1 - #Units grp = file.create_group("/Units") grp.attrs["Unit length in cgs (U_L)"] = 1. diff --git a/examples/Noh_2D/noh.yml b/examples/Noh_2D/noh.yml index 1d126f19babd0c9fe28afff907b3fe8259467a24..eaf991631854e9a9781f0fcee50d996f8af949cd 100644 --- a/examples/Noh_2D/noh.yml +++ b/examples/Noh_2D/noh.yml @@ -31,4 +31,5 @@ SPH: # Parameters related to the initial conditions InitialConditions: file_name: ./noh.hdf5 # The file to read + periodic: 1 diff --git a/examples/Noh_3D/makeIC.py b/examples/Noh_3D/makeIC.py index 0c25a5c8b3e967185cf16bae4b1f21c215266def..2d560a1e869c6c12e557c82402d6e8629ecf661c 100644 --- a/examples/Noh_3D/makeIC.py +++ b/examples/Noh_3D/makeIC.py @@ -75,10 +75,6 @@ grp.attrs["MassTable"] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] grp.attrs["Flag_Entropy_ICs"] = 0 grp.attrs["Dimension"] = 3 -#Runtime parameters -grp = file.create_group("/RuntimePars") -grp.attrs["PeriodicBoundariesOn"] = 1 - #Units grp = file.create_group("/Units") grp.attrs["Unit length in cgs (U_L)"] = 1. diff --git a/examples/Noh_3D/noh.yml b/examples/Noh_3D/noh.yml index cc15af7ec190cd2c10cdff3a3ccb3f0beaf7e177..e005d394a6d3645ca33950af625b0267a62ca7d7 100644 --- a/examples/Noh_3D/noh.yml +++ b/examples/Noh_3D/noh.yml @@ -32,4 +32,5 @@ SPH: # Parameters related to the initial conditions InitialConditions: file_name: ./noh.hdf5 # The file to read + periodic: 1 diff --git a/examples/PMillennium-384/p-mill-384.yml b/examples/PMillennium-384/p-mill-384.yml index b7fc6f762205a0a493b13392ff3001c653445d8d..4aede77c0c1a8a6818c95c318364150ede919a01 100644 --- a/examples/PMillennium-384/p-mill-384.yml +++ b/examples/PMillennium-384/p-mill-384.yml @@ -46,5 +46,6 @@ Gravity: # Parameters related to the initial conditions InitialConditions: file_name: ics.hdf5 + periodic: 1 cleanup_h_factors: 1 cleanup_velocity_factors: 1 diff --git a/examples/PMillennium-768/p-mill-768.yml b/examples/PMillennium-768/p-mill-768.yml index 8b93a7752d09545c08b98af87db1b1d46eb15189..a70c9c70831af9c237a466165b25b6300df69336 100644 --- a/examples/PMillennium-768/p-mill-768.yml +++ b/examples/PMillennium-768/p-mill-768.yml @@ -46,5 +46,6 @@ Gravity: # Parameters related to the initial conditions InitialConditions: file_name: ics.hdf5 + periodic: 1 cleanup_h_factors: 1 cleanup_velocity_factors: 1 diff --git a/examples/PerturbedBox_2D/makeIC.py b/examples/PerturbedBox_2D/makeIC.py index 87a41517772570870e04c79d3694c115a909e214..7f52525bdf508603a23f93c0fc7d8cda7f8f13cb 100644 --- a/examples/PerturbedBox_2D/makeIC.py +++ b/examples/PerturbedBox_2D/makeIC.py @@ -86,10 +86,6 @@ grp.attrs["Flag_Entropy_ICs"] = [0, 0, 0, 0, 0, 0] grp.attrs["NumPart_Total"] = numPart grp.attrs["Dimension"] = 2 -#Runtime parameters -grp = file.create_group("/RuntimePars") -grp.attrs["PeriodicBoundariesOn"] = periodic - #Units grp = file.create_group("/Units") grp.attrs["Unit length in cgs (U_L)"] = 1. diff --git a/examples/PerturbedBox_2D/perturbedPlane.yml b/examples/PerturbedBox_2D/perturbedPlane.yml index a0c6b6d9dbc7a677002dbce5abc6e5d268b56e97..4d03b30398bec34414636803caf6bf3bdc99251d 100644 --- a/examples/PerturbedBox_2D/perturbedPlane.yml +++ b/examples/PerturbedBox_2D/perturbedPlane.yml @@ -31,3 +31,4 @@ SPH: # Parameters related to the initial conditions InitialConditions: file_name: ./perturbedPlane.hdf5 # The file to read + periodic: 1 diff --git a/examples/PerturbedBox_3D/makeIC.py b/examples/PerturbedBox_3D/makeIC.py index 1b0fc284e4c40b51fca45f117b92175a0ea45f31..f2d8357f2f96a4aa6efaa14822c442a884415b56 100644 --- a/examples/PerturbedBox_3D/makeIC.py +++ b/examples/PerturbedBox_3D/makeIC.py @@ -88,10 +88,6 @@ grp.attrs["Flag_Entropy_ICs"] = [0, 0, 0, 0, 0, 0] grp.attrs["NumPart_Total"] = numPart grp.attrs["Dimension"] = 3 -#Runtime parameters -grp = file.create_group("/RuntimePars") -grp.attrs["PeriodicBoundariesOn"] = periodic - #Units grp = file.create_group("/Units") grp.attrs["Unit length in cgs (U_L)"] = 1. diff --git a/examples/PerturbedBox_3D/perturbedBox.yml b/examples/PerturbedBox_3D/perturbedBox.yml index 3148510979d0e349c0d6242bf11e1a0db94f9e1f..6010cf457b2b67c0fce0332a0216aa9359673e3b 100644 --- a/examples/PerturbedBox_3D/perturbedBox.yml +++ b/examples/PerturbedBox_3D/perturbedBox.yml @@ -31,3 +31,4 @@ SPH: # Parameters related to the initial conditions InitialConditions: file_name: ./perturbedBox.hdf5 # The file to read + periodic: 1 diff --git a/examples/SantaBarbara/santa_barbara.yml b/examples/SantaBarbara/santa_barbara.yml index b01321c521ec28b78c97cd082f0fd520d7024c3d..65e6c239e152d46647a6b0e40b2f100a9d7a3d32 100644 --- a/examples/SantaBarbara/santa_barbara.yml +++ b/examples/SantaBarbara/santa_barbara.yml @@ -53,6 +53,7 @@ SPH: # Parameters related to the initial conditions InitialConditions: file_name: ./SantaBarbara.hdf5 + periodic: 1 cleanup_h_factors: 1 # ICs were generated for Gadget, we need to get rid of h-factors cleanup_velocity_factors: 1 # ICs were generated for Gadget, we need to get rid of sqrt(a) factors in the velocity generate_gas_in_ics: 1 # Generate gas particles from the DM-only ICs diff --git a/examples/SantaBarbara_low/README b/examples/SantaBarbara_low/README new file mode 100644 index 0000000000000000000000000000000000000000..f86f1a4a4e1d16c3f4011c9e3ed8f35f643bd47e --- /dev/null +++ b/examples/SantaBarbara_low/README @@ -0,0 +1,21 @@ +Initital conditions for the Santa-Barbara cluster comparison project. +These have been regenerated from the orinigal Frenk et al. 1999 paper. + +The cosmology is Omega_m = 1, Omega_b = 0.1, h = 0.5 and sigma_8 = 0.9. + +The ICs are 128^3 particles in a 64^3 Mpc^3 volume. This is about 10x +higher resolution than in the original paper. The ICs have been +created for Gadget and the positions and box size are hence expressed +in h-full units (e.g. box size of 32 / h Mpc). Similarly, the peculiar +velocitites contain an extra sqrt(a) factor. + +We will use SWIFT to cancel the h- and a-factors from the ICs. Gas +particles will be generated at startup. + +MD5 check-sum of the ICS: +1a1600b41002789b6057b1fa6333f3f0 SantaBarbara_128.hdf5 + +You can use the script run_velociraptor.sh to also run a basic 3D FoF +with VELOCIraptor on your output data. You will need to set the +VELOCIRAPTOR_PATH environment variable to tell us where the stf-gas +binary lives. diff --git a/examples/SantaBarbara_low/getIC.sh b/examples/SantaBarbara_low/getIC.sh new file mode 100755 index 0000000000000000000000000000000000000000..759cef50dcfc346b389b1400054fe38358793fdd --- /dev/null +++ b/examples/SantaBarbara_low/getIC.sh @@ -0,0 +1,2 @@ +#!/bin/bash +wget http://virgodb.cosma.dur.ac.uk/swift-webstorage/ICs/SantaBarbara_128.hdf5 diff --git a/examples/SantaBarbara_low/run.sh b/examples/SantaBarbara_low/run.sh new file mode 100755 index 0000000000000000000000000000000000000000..044f9f4ef340ab95ffe643104294552469a676ce --- /dev/null +++ b/examples/SantaBarbara_low/run.sh @@ -0,0 +1,4 @@ +#!/bin/bash +# Run SWIFT +../swift -c -s -G -t 28 santa_barbara.yml + diff --git a/examples/SantaBarbara_low/santa_barbara.yml b/examples/SantaBarbara_low/santa_barbara.yml new file mode 100644 index 0000000000000000000000000000000000000000..0e3c66b1a1c1e04bf6fad30e806327b83f03737e --- /dev/null +++ b/examples/SantaBarbara_low/santa_barbara.yml @@ -0,0 +1,60 @@ +# Define the system of units to use internally. +InternalUnitSystem: + UnitMass_in_cgs: 1.98848e43 # 10^10 M_sun in grams + UnitLength_in_cgs: 3.08567758e24 # Mpc in centimeters + UnitVelocity_in_cgs: 1e5 # 1 km/s + UnitCurrent_in_cgs: 1 # Amperes + UnitTemp_in_cgs: 1 # Kelvin + +# Cosmological parameters +Cosmology: + h: 0.5 + a_begin: 0.047619048 # z_ini = 20 + a_end: 1.0 # z_end = 0 + Omega_m: 1.0 + Omega_lambda: 0.0 + Omega_b: 0.1 + +# Parameters governing the time integration +TimeIntegration: + dt_max: 0.01 + dt_min: 1e-10 + +Scheduler: + max_top_level_cells: 16 + cell_split_size: 100 + +# Parameters governing the snapshots +Snapshots: + basename: santabarbara_low + scale_factor_first: 0.05 + delta_time: 1.02 + +# Parameters governing the conserved quantities statistics +Statistics: + delta_time: 1.02 + scale_factor_first: 0.05 + +# Parameters for the self-gravity scheme +Gravity: + eta: 0.025 + theta: 0.5 + comoving_softening: 0.02 # 20 kpc = 1/25 mean inter-particle separation + max_physical_softening: 0.00526 # 20 ckpc = 5.26 pkpc at z=2.8 (EAGLE-like evolution of softening). + mesh_side_length: 64 + +# Parameters of the hydro scheme +SPH: + resolution_eta: 1.2348 # "48 Ngb" with the cubic spline kernel + CFL_condition: 0.1 + initial_temperature: 1200. # (1 + z_ini)^2 * 2.72K + minimal_temperature: 100. + +# Parameters related to the initial conditions +InitialConditions: + file_name: ./SantaBarbara_128.hdf5 + periodic: 1 + cleanup_h_factors: 1 # ICs were generated for Gadget, we need to get rid of h-factors + cleanup_velocity_factors: 1 # ICs were generated for Gadget, we need to get rid of sqrt(a) factors in the velocity + generate_gas_in_ics: 1 # Generate gas particles from the DM-only ICs + cleanup_smoothing_lengths: 1 # Since we generate gas, make use of the (expensive) cleaning-up procedure. \ No newline at end of file diff --git a/examples/SedovBlast_1D/makeIC.py b/examples/SedovBlast_1D/makeIC.py index 7177f3a7670aa054e3d7341a11a7359b3d855837..28b9c4bfd69395b94628bda3cfc3e59166460c79 100644 --- a/examples/SedovBlast_1D/makeIC.py +++ b/examples/SedovBlast_1D/makeIC.py @@ -72,10 +72,6 @@ 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 -#Runtime parameters -grp = file.create_group("/RuntimePars") -grp.attrs["PeriodicBoundariesOn"] = 1 - #Units grp = file.create_group("/Units") grp.attrs["Unit length in cgs (U_L)"] = 1. diff --git a/examples/SedovBlast_1D/sedov.yml b/examples/SedovBlast_1D/sedov.yml index 5ef105b06c23ba577129f29a817c058457e7387f..b4912a95e797440dc6eb0c9f48806a5954adbc41 100644 --- a/examples/SedovBlast_1D/sedov.yml +++ b/examples/SedovBlast_1D/sedov.yml @@ -31,4 +31,4 @@ SPH: # Parameters related to the initial conditions InitialConditions: file_name: ./sedov.hdf5 # The file to read - + periodic: 1 diff --git a/examples/SedovBlast_2D/makeIC.py b/examples/SedovBlast_2D/makeIC.py index 0e83c7b19b9ac9bd69e20950a64e8a49dd8d0df9..cd1e433c104fd013a71c5a501c166194a7f3f50f 100644 --- a/examples/SedovBlast_2D/makeIC.py +++ b/examples/SedovBlast_2D/makeIC.py @@ -72,10 +72,6 @@ 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 -#Runtime parameters -grp = file.create_group("/RuntimePars") -grp.attrs["PeriodicBoundariesOn"] = 1 - #Units grp = file.create_group("/Units") grp.attrs["Unit length in cgs (U_L)"] = 1. diff --git a/examples/SedovBlast_2D/sedov.yml b/examples/SedovBlast_2D/sedov.yml index 098ca7a0d6264f016727709723aafdfb1224d460..84177ece31ef98ec55c41513276c9c0158e69bcf 100644 --- a/examples/SedovBlast_2D/sedov.yml +++ b/examples/SedovBlast_2D/sedov.yml @@ -31,4 +31,4 @@ SPH: # Parameters related to the initial conditions InitialConditions: file_name: ./sedov.hdf5 # The file to read - + periodic: 1 diff --git a/examples/SedovBlast_3D/makeIC.py b/examples/SedovBlast_3D/makeIC.py index e1b743c6cdcd8dcc2f8da14d1d5589fb9ed111f0..30e0e31927db6343e58549bc9c7754bc274f51ce 100644 --- a/examples/SedovBlast_3D/makeIC.py +++ b/examples/SedovBlast_3D/makeIC.py @@ -72,10 +72,6 @@ grp.attrs["MassTable"] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] grp.attrs["Flag_Entropy_ICs"] = 0 grp.attrs["Dimension"] = 3 -#Runtime parameters -grp = file.create_group("/RuntimePars") -grp.attrs["PeriodicBoundariesOn"] = 1 - #Units grp = file.create_group("/Units") grp.attrs["Unit length in cgs (U_L)"] = 1. diff --git a/examples/SedovBlast_3D/sedov.yml b/examples/SedovBlast_3D/sedov.yml index 75849e33c0c644a18cd7357f901699d0d682c160..6cf5b02427b8004787b646e6bcdd4bacaa25bc06 100644 --- a/examples/SedovBlast_3D/sedov.yml +++ b/examples/SedovBlast_3D/sedov.yml @@ -32,5 +32,5 @@ SPH: # Parameters related to the initial conditions InitialConditions: file_name: ./sedov.hdf5 + periodic: 1 smoothing_length_scaling: 3.33 - diff --git a/examples/SineWavePotential_1D/makeIC.py b/examples/SineWavePotential_1D/makeIC.py index afbf1bc0fa47a27677cb9c5645d439432bd9fd9a..39a78393650c7a8c0c01814fa10f514cc277e685 100644 --- a/examples/SineWavePotential_1D/makeIC.py +++ b/examples/SineWavePotential_1D/makeIC.py @@ -74,10 +74,6 @@ 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 -#Runtime parameters -grp = file.create_group("/RuntimePars") -grp.attrs["PeriodicBoundariesOn"] = 1 - #Units grp = file.create_group("/Units") grp.attrs["Unit length in cgs (U_L)"] = 1. diff --git a/examples/SineWavePotential_1D/sineWavePotential.yml b/examples/SineWavePotential_1D/sineWavePotential.yml index e6285785099f10902ea60b21334a0ad26c0593de..a21a0b5936ab0a62a7b1f29c56145bed79ba73c4 100644 --- a/examples/SineWavePotential_1D/sineWavePotential.yml +++ b/examples/SineWavePotential_1D/sineWavePotential.yml @@ -31,7 +31,8 @@ SPH: # Parameters related to the initial conditions InitialConditions: file_name: sineWavePotential.hdf5 # The file to read - + periodic: 1 + # External potential parameters SineWavePotential: amplitude: 10. diff --git a/examples/SineWavePotential_2D/makeIC.py b/examples/SineWavePotential_2D/makeIC.py index 62ae89f8f52bff9c0db37cd537f286ab817da3fe..057760502e561b5ec5d98e716b79119e3637ef57 100644 --- a/examples/SineWavePotential_2D/makeIC.py +++ b/examples/SineWavePotential_2D/makeIC.py @@ -70,10 +70,6 @@ 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 -#Runtime parameters -grp = file.create_group("/RuntimePars") -grp.attrs["PeriodicBoundariesOn"] = 1 - #Units grp = file.create_group("/Units") grp.attrs["Unit length in cgs (U_L)"] = 1. diff --git a/examples/SineWavePotential_2D/sineWavePotential.yml b/examples/SineWavePotential_2D/sineWavePotential.yml index 9107652f65c343d68fc92e699d45710265d65308..63d575e7e2486cf4428bb8b11e1ba16da6e08d99 100644 --- a/examples/SineWavePotential_2D/sineWavePotential.yml +++ b/examples/SineWavePotential_2D/sineWavePotential.yml @@ -31,7 +31,8 @@ SPH: # Parameters related to the initial conditions InitialConditions: file_name: sineWavePotential.hdf5 # The file to read - + periodic: 1 + # External potential parameters SineWavePotential: amplitude: 10. diff --git a/examples/SineWavePotential_3D/makeIC.py b/examples/SineWavePotential_3D/makeIC.py index 4833ec1b055e27b63751136f0491e972fb9e492a..a4f39238ba40bf6769e0fb44fe8da706730fe45b 100644 --- a/examples/SineWavePotential_3D/makeIC.py +++ b/examples/SineWavePotential_3D/makeIC.py @@ -81,10 +81,6 @@ grp.attrs["MassTable"] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] grp.attrs["Flag_Entropy_ICs"] = 0 grp.attrs["Dimension"] = 3 -#Runtime parameters -grp = file.create_group("/RuntimePars") -grp.attrs["PeriodicBoundariesOn"] = 1 - #Units grp = file.create_group("/Units") grp.attrs["Unit length in cgs (U_L)"] = 1. diff --git a/examples/SineWavePotential_3D/sineWavePotential.yml b/examples/SineWavePotential_3D/sineWavePotential.yml index 8a49d8bc40eb662d62b2b6550b70fe380a7564f5..5b91feae0ecf8ad2f4f257374900a01f031acff1 100644 --- a/examples/SineWavePotential_3D/sineWavePotential.yml +++ b/examples/SineWavePotential_3D/sineWavePotential.yml @@ -31,7 +31,8 @@ SPH: # Parameters related to the initial conditions InitialConditions: file_name: sineWavePotential.hdf5 # The file to read - + periodic: 1 + # External potential parameters SineWavePotential: amplitude: 10. diff --git a/examples/SmallCosmoVolume/small_cosmo_volume.yml b/examples/SmallCosmoVolume/small_cosmo_volume.yml index 353ab469c8375e87652738daea12a4a0144bfcd8..a6ce1f28198a99422ea1c80178fc8000b66d777e 100644 --- a/examples/SmallCosmoVolume/small_cosmo_volume.yml +++ b/examples/SmallCosmoVolume/small_cosmo_volume.yml @@ -52,7 +52,8 @@ Scheduler: # Parameters related to the initial conditions InitialConditions: file_name: small_cosmo_volume.hdf5 + periodic: 1 cleanup_h_factors: 1 cleanup_velocity_factors: 1 - generate_gas_in_ics: 1 # Generate gas particles from the DM-only ICs - cleanup_smoothing_lengths: 1 # Since we generate gas, make use of the (expensive) cleaning-up procedure. + generate_gas_in_ics: 1 # Generate gas particles from the DM-only ICs + cleanup_smoothing_lengths: 1 # Since we generate gas, make use of the (expensive) cleaning-up procedure. diff --git a/examples/SmallCosmoVolume_DM/small_cosmo_volume_dm.yml b/examples/SmallCosmoVolume_DM/small_cosmo_volume_dm.yml index ae4cb62c8da9e1b56ca56f3d14bdbf120ef80c6a..910137edc442c994a9f31a8c62e16818ca4ae97d 100644 --- a/examples/SmallCosmoVolume_DM/small_cosmo_volume_dm.yml +++ b/examples/SmallCosmoVolume_DM/small_cosmo_volume_dm.yml @@ -53,5 +53,6 @@ Scheduler: # Parameters related to the initial conditions InitialConditions: file_name: small_cosmo_volume.hdf5 + periodic: 1 cleanup_h_factors: 1 cleanup_velocity_factors: 1 diff --git a/examples/SmallCosmoVolume_cooling/README b/examples/SmallCosmoVolume_cooling/README new file mode 100644 index 0000000000000000000000000000000000000000..2ee364ca2f00a4280a492a11520bf7b9a1ac1f7d --- /dev/null +++ b/examples/SmallCosmoVolume_cooling/README @@ -0,0 +1,19 @@ +Small LCDM cosmological simulation generated by C. Power. Cosmology +is WMAP9 and the box is 100Mpc/h in size with 64^3 particles. +We use a softening length of 1/25th of the mean inter-particle separation. + +The ICs have been generated to run with Gadget-2 so we need to switch +on the options to cancel the h-factors and a-factors at reading time. +We generate gas from the ICs using SWIFT's internal mechanism and set the +temperature to the expected gas temperature at this redshift. + +This example runs with cooling switch on. Depending on the cooling +model chosen at the time SWIFT was configured, the answer will be +different. Interesting cases to compare to the no-cooling case are +a constant cooling rate or Compton cooling. + +The 'plotTempEvolution.py' plots the temperature evolution of the gas +in the simulated volume. + +MD5 checksum of the ICs: +08736c3101fd738e22f5159f78e6022b small_cosmo_volume.hdf5 diff --git a/examples/SmallCosmoVolume_cooling/getIC.sh b/examples/SmallCosmoVolume_cooling/getIC.sh new file mode 100755 index 0000000000000000000000000000000000000000..3b8136cc5aca00a25792655c6c505cfeeb0f2bc9 --- /dev/null +++ b/examples/SmallCosmoVolume_cooling/getIC.sh @@ -0,0 +1,3 @@ +#!/bin/bash +wget http://virgodb.cosma.dur.ac.uk/swift-webstorage/ICs/small_cosmo_volume.hdf5 + diff --git a/examples/SmallCosmoVolume_cooling/plotTempEvolution.py b/examples/SmallCosmoVolume_cooling/plotTempEvolution.py new file mode 100644 index 0000000000000000000000000000000000000000..d3e4e9047ed7f2cc57ef581526488e64ccc26092 --- /dev/null +++ b/examples/SmallCosmoVolume_cooling/plotTempEvolution.py @@ -0,0 +1,192 @@ +################################################################################ +# 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/>. +# +################################################################################ + +# Computes the temperature evolution of the gas in a cosmological box + +# Physical constants needed for internal energy to temperature conversion +k_in_J_K = 1.38064852e-23 +mH_in_kg = 1.6737236e-27 + +# Number of snapshots generated +n_snapshots = 200 + +import matplotlib +matplotlib.use("Agg") +from pylab import * +import h5py +import os.path + +# Plot parameters +params = {'axes.labelsize': 10, +'axes.titlesize': 10, +'font.size': 9, +'legend.fontsize': 9, +'xtick.labelsize': 10, +'ytick.labelsize': 10, +'text.usetex': True, + 'figure.figsize' : (3.15,3.15), +'figure.subplot.left' : 0.14, +'figure.subplot.right' : 0.99, +'figure.subplot.bottom' : 0.12, +'figure.subplot.top' : 0.99, +'figure.subplot.wspace' : 0.15, +'figure.subplot.hspace' : 0.12, +'lines.markersize' : 6, +'lines.linewidth' : 2., +'text.latex.unicode': True +} +rcParams.update(params) +rc('font',**{'family':'sans-serif','sans-serif':['Times']}) + +# Read the simulation data +sim = h5py.File("snap_0000.hdf5", "r") +boxSize = sim["/Header"].attrs["BoxSize"][0] +time = sim["/Header"].attrs["Time"][0] +scheme = sim["/HydroScheme"].attrs["Scheme"][0] +kernel = sim["/HydroScheme"].attrs["Kernel function"][0] +neighbours = sim["/HydroScheme"].attrs["Kernel target N_ngb"][0] +eta = sim["/HydroScheme"].attrs["Kernel eta"][0] +alpha = sim["/HydroScheme"].attrs["Alpha viscosity"][0] +H_mass_fraction = sim["/HydroScheme"].attrs["Hydrogen mass fraction"][0] +H_transition_temp = sim["/HydroScheme"].attrs["Hydrogen ionization transition temperature"][0] +T_initial = sim["/HydroScheme"].attrs["Initial temperature"][0] +T_minimal = sim["/HydroScheme"].attrs["Minimal temperature"][0] +git = sim["Code"].attrs["Git Revision"] +cooling_model = sim["/SubgridScheme"].attrs["Cooling Model"] + +if cooling_model == "Constant Lambda": + Lambda = sim["/SubgridScheme"].attrs["Lambda/n_H^2 [cgs]"][0] + +# Cosmological parameters +H_0 = sim["/Cosmology"].attrs["H0 [internal units]"][0] +gas_gamma = sim["/HydroScheme"].attrs["Adiabatic index"][0] + +unit_length_in_cgs = sim["/Units"].attrs["Unit length in cgs (U_L)"] +unit_mass_in_cgs = sim["/Units"].attrs["Unit mass in cgs (U_M)"] +unit_time_in_cgs = sim["/Units"].attrs["Unit time in cgs (U_t)"] + +unit_length_in_si = 0.01 * unit_length_in_cgs +unit_mass_in_si = 0.001 * unit_mass_in_cgs +unit_time_in_si = unit_time_in_cgs + +# Primoridal mean molecular weight as a function of temperature +def mu(T, H_frac=H_mass_fraction, T_trans=H_transition_temp): + if T > T_trans: + return 4. / (8. - 5. * (1. - H_frac)) + else: + return 4. / (1. + 3. * H_frac) + +# Temperature of some primoridal gas with a given internal energy +def T(u, H_frac=H_mass_fraction, T_trans=H_transition_temp): + T_over_mu = (gas_gamma - 1.) * u * mH_in_kg / k_in_J_K + ret = np.ones(np.size(u)) * T_trans + + # Enough energy to be ionized? + mask_ionized = (T_over_mu > (T_trans+1) / mu(T_trans+1, H_frac, T_trans)) + if np.sum(mask_ionized) > 0: + ret[mask_ionized] = T_over_mu[mask_ionized] * mu(T_trans*10, H_frac, T_trans) + + # Neutral gas? + mask_neutral = (T_over_mu < (T_trans-1) / mu((T_trans-1), H_frac, T_trans)) + if np.sum(mask_neutral) > 0: + ret[mask_neutral] = T_over_mu[mask_neutral] * mu(0, H_frac, T_trans) + + return ret + + +z = np.zeros(n_snapshots) +a = np.zeros(n_snapshots) +T_mean = np.zeros(n_snapshots) +T_std = np.zeros(n_snapshots) +T_log_mean = np.zeros(n_snapshots) +T_log_std = np.zeros(n_snapshots) +T_median = np.zeros(n_snapshots) +T_min = np.zeros(n_snapshots) +T_max = np.zeros(n_snapshots) + +# Loop over all the snapshots +for i in range(n_snapshots): + sim = h5py.File("snap_%04d.hdf5"%i, "r") + + z[i] = sim["/Cosmology"].attrs["Redshift"][0] + a[i] = sim["/Cosmology"].attrs["Scale-factor"][0] + + u = sim["/PartType0/InternalEnergy"][:] + + # Compute the temperature + u *= (unit_length_in_si**2 / unit_time_in_si**2) + u /= a[i]**(3 * (gas_gamma - 1.)) + Temp = T(u) + + # Gather statistics + T_median[i] = np.median(Temp) + T_mean[i] = Temp.mean() + T_std[i] = Temp.std() + T_log_mean[i] = np.log10(Temp).mean() + T_log_std[i] = np.log10(Temp).std() + T_min[i] = Temp.min() + T_max[i] = Temp.max() + +# CMB evolution +a_evol = np.logspace(-3, 0, 60) +T_cmb = (1. / a_evol)**2 * 2.72 + +# Plot the interesting quantities +figure() +subplot(111, xscale="log", yscale="log") + +fill_between(a, T_mean-T_std, T_mean+T_std, color='C0', alpha=0.1) +plot(a, T_max, ls='-.', color='C0', lw=1., label="${\\rm max}~T$") +plot(a, T_min, ls=':', color='C0', lw=1., label="${\\rm min}~T$") +plot(a, T_mean, color='C0', label="${\\rm mean}~T$", lw=1.5) +fill_between(a, 10**(T_log_mean-T_log_std), 10**(T_log_mean+T_log_std), color='C1', alpha=0.1) +plot(a, 10**T_log_mean, color='C1', label="${\\rm mean}~{\\rm log} T$", lw=1.5) +plot(a, T_median, color='C2', label="${\\rm median}~T$", lw=1.5) + +legend(loc="upper left", frameon=False, handlelength=1.5) + +# Cooling model +if cooling_model == "Constant Lambda": + text(1e-2, 6e4, "$\Lambda_{\\rm const}/n_{\\rm H}^2 = %.1f\\times10^{%d}~[\\rm{cgs}]$"%(Lambda/10.**(int(log10(Lambda))), log10(Lambda)), fontsize=7) +else: + text(1e-2, 6e4, "No cooling") + +# Expected lines +plot([1e-10, 1e10], [H_transition_temp, H_transition_temp], 'k--', lw=0.5, alpha=0.7) +text(2.5e-2, H_transition_temp*1.07, "$T_{\\rm HII\\rightarrow HI}$", va="bottom", alpha=0.7, fontsize=8) +plot([1e-10, 1e10], [T_minimal, T_minimal], 'k--', lw=0.5, alpha=0.7) +text(1e-2, T_minimal*0.8, "$T_{\\rm min}$", va="top", alpha=0.7, fontsize=8) +plot(a_evol, T_cmb, 'k--', lw=0.5, alpha=0.7) +text(a_evol[20], T_cmb[20]*0.55, "$(1+z)^2\\times T_{\\rm CMB,0}$", rotation=-34, alpha=0.7, fontsize=8, va="top", bbox=dict(facecolor='w', edgecolor='none', pad=1.0, alpha=0.9)) + + +redshift_ticks = np.array([0., 1., 2., 5., 10., 20., 50., 100.]) +redshift_labels = ["$0$", "$1$", "$2$", "$5$", "$10$", "$20$", "$50$", "$100$"] +a_ticks = 1. / (redshift_ticks + 1.) + +xticks(a_ticks, redshift_labels) +minorticks_off() + +xlabel("${\\rm Redshift}~z$", labelpad=0) +ylabel("${\\rm Temperature}~T~[{\\rm K}]$", labelpad=0) +xlim(9e-3, 1.1) +ylim(20, 2.5e7) + +savefig("Temperature_evolution.png", dpi=200) + diff --git a/examples/SmallCosmoVolume_cooling/run.sh b/examples/SmallCosmoVolume_cooling/run.sh new file mode 100755 index 0000000000000000000000000000000000000000..454ed279503db17ea2deddb2ae982206238ec23f --- /dev/null +++ b/examples/SmallCosmoVolume_cooling/run.sh @@ -0,0 +1,14 @@ +#!/bin/bash + + # Generate the initial conditions if they are not present. +if [ ! -e small_cosmo_volume.hdf5 ] +then + echo "Fetching initial conditions for the small cosmological volume example..." + ./getIC.sh +fi + +# Run SWIFT +../swift -c -s -G -C -t 8 small_cosmo_volume.yml 2>&1 | tee output.log + +# Plot the temperature evolution +python plotTempEvolution.py diff --git a/examples/SmallCosmoVolume_cooling/small_cosmo_volume.yml b/examples/SmallCosmoVolume_cooling/small_cosmo_volume.yml new file mode 100644 index 0000000000000000000000000000000000000000..b091207fa98d8b6604124fb9d99c80d65e97dfb2 --- /dev/null +++ b/examples/SmallCosmoVolume_cooling/small_cosmo_volume.yml @@ -0,0 +1,63 @@ +# Define the system of units to use internally. +InternalUnitSystem: + UnitMass_in_cgs: 1.98848e43 # 10^10 M_sun + UnitLength_in_cgs: 3.08567758e24 # 1 Mpc + UnitVelocity_in_cgs: 1e5 # 1 km/s + UnitCurrent_in_cgs: 1 # Amperes + UnitTemp_in_cgs: 1 # Kelvin + +Cosmology: # WMAP9 cosmology + Omega_m: 0.276 + Omega_lambda: 0.724 + Omega_b: 0.0455 + h: 0.703 + a_begin: 0.019607843 # z_ini = 50. + a_end: 1.0 # z_end = 0. + +# Parameters governing the time integration +TimeIntegration: + dt_min: 1e-6 + dt_max: 1e-2 + +# Parameters for the self-gravity scheme +Gravity: + eta: 0.025 + theta: 0.3 + comoving_softening: 0.0889 # 1/25th of the mean inter-particle separation: 88.9 kpc + max_physical_softening: 0.0889 # 1/25th of the mean inter-particle separation: 88.9 kpc + mesh_side_length: 64 + +# Parameters of the hydro scheme +SPH: + resolution_eta: 1.2348 # "48 Ngb" with the cubic spline kernel + CFL_condition: 0.1 + initial_temperature: 7075. # (1 + z_ini)^2 * 2.72K + minimal_temperature: 100. + +# Parameters governing the snapshots +Snapshots: + basename: snap + delta_time: 1.02 + scale_factor_first: 0.02 + +# Parameters governing the conserved quantities statistics +Statistics: + delta_time: 1.02 + scale_factor_first: 0.02 + +Scheduler: + max_top_level_cells: 8 + cell_split_size: 50 + +# Parameters related to the initial conditions +InitialConditions: + file_name: small_cosmo_volume.hdf5 + periodic: 1 + cleanup_h_factors: 1 + cleanup_velocity_factors: 1 + generate_gas_in_ics: 1 # Generate gas particles from the DM-only ICs + cleanup_smoothing_lengths: 1 # Since we generate gas, make use of the (expensive) cleaning-up procedure. + +# Constant lambda cooling function +LambdaCooling: + lambda_nH2_cgs: 1e-26 # Cooling rate divided by square Hydrogen number density (in cgs units [erg * s^-1 * cm^3]) diff --git a/examples/SmoothedMetallicity/makeIC.py b/examples/SmoothedMetallicity/makeIC.py index 86679d5efe897b9dfae7db94b36d74bb047661e6..542b4c5911c942015d16595f42e73ca8978d20da 100644 --- a/examples/SmoothedMetallicity/makeIC.py +++ b/examples/SmoothedMetallicity/makeIC.py @@ -84,10 +84,6 @@ grp.attrs["MassTable"] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] grp.attrs["Flag_Entropy_ICs"] = 0 grp.attrs["Dimension"] = 3 -# Runtime parameters -grp = file.create_group("/RuntimePars") -grp.attrs["PeriodicBoundariesOn"] = 1 - # Units grp = file.create_group("/Units") grp.attrs["Unit length in cgs (U_L)"] = 1. diff --git a/examples/SmoothedMetallicity/smoothed_metallicity.yml b/examples/SmoothedMetallicity/smoothed_metallicity.yml index 2e37695392b12c545bbbdbe7fd94748d5b3b9ff8..f6841c6bd0744b4bbeacbe136a126b4ed5631f6f 100644 --- a/examples/SmoothedMetallicity/smoothed_metallicity.yml +++ b/examples/SmoothedMetallicity/smoothed_metallicity.yml @@ -31,4 +31,5 @@ SPH: # Parameters related to the initial conditions InitialConditions: file_name: ./smoothed_metallicity.hdf5 # The file to read + periodic: 1 diff --git a/examples/SodShockSpherical_2D/makeIC.py b/examples/SodShockSpherical_2D/makeIC.py index ac9f6e193769d7466f5b8e41a408da2350777be6..bc2c7ed1dcae5adfbfdcaf01c6b5a36bf5669e9e 100644 --- a/examples/SodShockSpherical_2D/makeIC.py +++ b/examples/SodShockSpherical_2D/makeIC.py @@ -100,10 +100,6 @@ 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 -#Runtime parameters -grp = file.create_group("/RuntimePars") -grp.attrs["PeriodicBoundariesOn"] = 1 - #Units grp = file.create_group("/Units") grp.attrs["Unit length in cgs (U_L)"] = 1. diff --git a/examples/SodShockSpherical_2D/sodShock.yml b/examples/SodShockSpherical_2D/sodShock.yml index a26ab95b21c782ce83310038432ac08df0e024c3..4ef13c26ccf55163f9276b6e095c351efd9ecb35 100644 --- a/examples/SodShockSpherical_2D/sodShock.yml +++ b/examples/SodShockSpherical_2D/sodShock.yml @@ -31,4 +31,5 @@ SPH: # Parameters related to the initial conditions InitialConditions: file_name: ./sodShock.hdf5 # The file to read + periodic: 1 diff --git a/examples/SodShockSpherical_3D/makeIC.py b/examples/SodShockSpherical_3D/makeIC.py index be8f9b61a1beef00f49786860ce94287b30e2ab3..3884fc29280209d465b721230ae19b474a42f6a0 100644 --- a/examples/SodShockSpherical_3D/makeIC.py +++ b/examples/SodShockSpherical_3D/makeIC.py @@ -102,10 +102,6 @@ grp.attrs["MassTable"] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] grp.attrs["Flag_Entropy_ICs"] = 0 grp.attrs["Dimension"] = 3 -#Runtime parameters -grp = file.create_group("/RuntimePars") -grp.attrs["PeriodicBoundariesOn"] = 1 - #Units grp = file.create_group("/Units") grp.attrs["Unit length in cgs (U_L)"] = 1. diff --git a/examples/SodShockSpherical_3D/sodShock.yml b/examples/SodShockSpherical_3D/sodShock.yml index 3fc4a1fb2b8cc5f6a603abf4c87ac99c7647b9bd..16d3bd313cf8a365fb82d3142ba1ac4fd065d193 100644 --- a/examples/SodShockSpherical_3D/sodShock.yml +++ b/examples/SodShockSpherical_3D/sodShock.yml @@ -32,4 +32,5 @@ SPH: # Parameters related to the initial conditions InitialConditions: file_name: ./sodShock.hdf5 # The file to read + periodic: 1 diff --git a/examples/SodShock_1D/makeIC.py b/examples/SodShock_1D/makeIC.py index a5c7f03b24d10e81057dbe25855f33f795218f19..d26bbbb4dbf71c1d6a63ad3c7900edfabe0fb9ec 100644 --- a/examples/SodShock_1D/makeIC.py +++ b/examples/SodShock_1D/makeIC.py @@ -92,10 +92,6 @@ 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 -#Runtime parameters -grp = file.create_group("/RuntimePars") -grp.attrs["PeriodicBoundariesOn"] = 1 - #Units grp = file.create_group("/Units") grp.attrs["Unit length in cgs (U_L)"] = 1. diff --git a/examples/SodShock_1D/sodShock.yml b/examples/SodShock_1D/sodShock.yml index e827edadb9c287975d83214249d4fdd7734a5f6c..69554b4db733166fc5dbb6d198966fd8f9b8d49c 100644 --- a/examples/SodShock_1D/sodShock.yml +++ b/examples/SodShock_1D/sodShock.yml @@ -31,4 +31,4 @@ SPH: # Parameters related to the initial conditions InitialConditions: file_name: ./sodShock.hdf5 # The file to read - + periodic: 1 diff --git a/examples/SodShock_2D/makeIC.py b/examples/SodShock_2D/makeIC.py index 850ca24f54c39990a9b0c54c0d2f361a2aa01e95..2d3bd75fcc41e0fee6dd7cfde62873980bbc7143 100644 --- a/examples/SodShock_2D/makeIC.py +++ b/examples/SodShock_2D/makeIC.py @@ -98,10 +98,6 @@ 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 -#Runtime parameters -grp = file.create_group("/RuntimePars") -grp.attrs["PeriodicBoundariesOn"] = 1 - #Units grp = file.create_group("/Units") grp.attrs["Unit length in cgs (U_L)"] = 1. diff --git a/examples/SodShock_2D/sodShock.yml b/examples/SodShock_2D/sodShock.yml index 51a188b6d4537d490cb837a03dab15f74c3b083c..b831dd78278fea619d75e2db8806cf00d8faf575 100644 --- a/examples/SodShock_2D/sodShock.yml +++ b/examples/SodShock_2D/sodShock.yml @@ -31,4 +31,5 @@ SPH: # Parameters related to the initial conditions InitialConditions: file_name: ./sodShock.hdf5 # The file to read + periodic: 1 diff --git a/examples/SodShock_3D/makeIC.py b/examples/SodShock_3D/makeIC.py index c71c07c6c97bb715c580f747cf8d39ddf08445c3..69f1bc506680d3f2f149c0fd7b75b069f9b00b64 100644 --- a/examples/SodShock_3D/makeIC.py +++ b/examples/SodShock_3D/makeIC.py @@ -98,10 +98,6 @@ grp.attrs["MassTable"] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] grp.attrs["Flag_Entropy_ICs"] = 0 grp.attrs["Dimension"] = 3 -#Runtime parameters -grp = file.create_group("/RuntimePars") -grp.attrs["PeriodicBoundariesOn"] = 1 - #Units grp = file.create_group("/Units") grp.attrs["Unit length in cgs (U_L)"] = 1. diff --git a/examples/SodShock_3D/sodShock.yml b/examples/SodShock_3D/sodShock.yml index 6042c8090d00fef5467a7fed3d6f5a104c626f43..b2d783cd74d66a8eaa3cbbf4b08fc686b0298244 100644 --- a/examples/SodShock_3D/sodShock.yml +++ b/examples/SodShock_3D/sodShock.yml @@ -32,4 +32,5 @@ SPH: # Parameters related to the initial conditions InitialConditions: file_name: ./sodShock.hdf5 # The file to read + periodic: 1 diff --git a/examples/SquareTest_2D/makeIC.py b/examples/SquareTest_2D/makeIC.py index 186e653124a6ff62a964c37cf0fb2220f1152a0e..12a394873edf42f7ecfdf07c9795b62e3ad89745 100644 --- a/examples/SquareTest_2D/makeIC.py +++ b/examples/SquareTest_2D/makeIC.py @@ -96,10 +96,6 @@ grp.attrs["MassTable"] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] grp.attrs["Flag_Entropy_ICs"] = [0, 0, 0, 0, 0, 0] grp.attrs["Dimension"] = 2 -#Runtime parameters -grp = fileOutput.create_group("/RuntimePars") -grp.attrs["PeriodicBoundariesOn"] = 1 - #Units grp = fileOutput.create_group("/Units") grp.attrs["Unit length in cgs (U_L)"] = 1. diff --git a/examples/SquareTest_2D/square.yml b/examples/SquareTest_2D/square.yml index b700c441a619ef8faac52656909567c944e344c3..54e0effa676cd5b1233ae7c38aded18d089f0ef2 100644 --- a/examples/SquareTest_2D/square.yml +++ b/examples/SquareTest_2D/square.yml @@ -31,3 +31,4 @@ SPH: # Parameters related to the initial conditions InitialConditions: file_name: ./square.hdf5 # The file to read + periodic: 1 diff --git a/examples/UniformBox_2D/makeIC.py b/examples/UniformBox_2D/makeIC.py index 642896c6ec406a5a75127e024d19775ea4a8e09b..36bb1ba6118a31db3251a1cd7f332f01b2ba3df1 100644 --- a/examples/UniformBox_2D/makeIC.py +++ b/examples/UniformBox_2D/makeIC.py @@ -85,10 +85,6 @@ grp.attrs["Flag_Entropy_ICs"] = [0, 0, 0, 0, 0, 0] grp.attrs["NumPart_Total"] = numPart grp.attrs["Dimension"] = 2 -#Runtime parameters -grp = file.create_group("/RuntimePars") -grp.attrs["PeriodicBoundariesOn"] = periodic - #Units grp = file.create_group("/Units") grp.attrs["Unit length in cgs (U_L)"] = 1. diff --git a/examples/UniformBox_2D/uniformPlane.yml b/examples/UniformBox_2D/uniformPlane.yml index 58fe0d50557db0c0624fe89cbde888d2c92775e5..77f53d59c497b10b1c95ce5dcb763fa8bffcd5ca 100644 --- a/examples/UniformBox_2D/uniformPlane.yml +++ b/examples/UniformBox_2D/uniformPlane.yml @@ -31,3 +31,4 @@ SPH: # Parameters related to the initial conditions InitialConditions: file_name: ./uniformPlane.hdf5 # The file to read + periodic: 1 diff --git a/examples/UniformBox_3D/makeIC.py b/examples/UniformBox_3D/makeIC.py index 01e37c67b6e2eec2984d62f4ffd503b23b5bd9ec..8311aae951f921b4c7f759ba09cc8fe73cf4a9f1 100644 --- a/examples/UniformBox_3D/makeIC.py +++ b/examples/UniformBox_3D/makeIC.py @@ -57,10 +57,6 @@ grp.attrs["MassTable"] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] grp.attrs["Flag_Entropy_ICs"] = 0 grp.attrs["Dimension"] = 3 -#Runtime parameters -grp = file.create_group("/RuntimePars") -grp.attrs["PeriodicBoundariesOn"] = periodic - #Units grp = file.create_group("/Units") grp.attrs["Unit length in cgs (U_L)"] = 1. diff --git a/examples/UniformBox_3D/uniformBox.yml b/examples/UniformBox_3D/uniformBox.yml index 17dd5632edd345802402cb9c6d1dcf184e909806..202ff8298fe763a8c194ab4570b1252fe352dccc 100644 --- a/examples/UniformBox_3D/uniformBox.yml +++ b/examples/UniformBox_3D/uniformBox.yml @@ -31,3 +31,4 @@ SPH: # Parameters related to the initial conditions InitialConditions: file_name: ./uniformBox.hdf5 # The file to read + periodic: 1 diff --git a/examples/VacuumSpherical_2D/makeIC.py b/examples/VacuumSpherical_2D/makeIC.py index 498f1b5bc5277188d8ff8d34a5ec24cd314332d4..05f0d8414cfa88755ecceb2be757e24ca3cefdde 100644 --- a/examples/VacuumSpherical_2D/makeIC.py +++ b/examples/VacuumSpherical_2D/makeIC.py @@ -77,10 +77,6 @@ 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 -#Runtime parameters -grp = file.create_group("/RuntimePars") -grp.attrs["PeriodicBoundariesOn"] = 1 - #Units grp = file.create_group("/Units") grp.attrs["Unit length in cgs (U_L)"] = 1. diff --git a/examples/VacuumSpherical_2D/vacuum.yml b/examples/VacuumSpherical_2D/vacuum.yml index 881b155b62c7f1f2af12a1d013ff5c05f1c16a88..1d5642d5c1b645808229c5c6b99fb6d319351880 100644 --- a/examples/VacuumSpherical_2D/vacuum.yml +++ b/examples/VacuumSpherical_2D/vacuum.yml @@ -31,4 +31,4 @@ SPH: # Parameters related to the initial conditions InitialConditions: file_name: ./vacuum.hdf5 # The file to read - + periodic: 1 diff --git a/examples/VacuumSpherical_3D/makeIC.py b/examples/VacuumSpherical_3D/makeIC.py index d67a30707a904268a09641210a6a3bfcbf305dad..dd4ddd7e8a8d6335e4d3d3b383c54bf301a06f1d 100644 --- a/examples/VacuumSpherical_3D/makeIC.py +++ b/examples/VacuumSpherical_3D/makeIC.py @@ -80,10 +80,6 @@ grp.attrs["MassTable"] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] grp.attrs["Flag_Entropy_ICs"] = 0 grp.attrs["Dimension"] = 3 -#Runtime parameters -grp = file.create_group("/RuntimePars") -grp.attrs["PeriodicBoundariesOn"] = 1 - #Units grp = file.create_group("/Units") grp.attrs["Unit length in cgs (U_L)"] = 1. diff --git a/examples/VacuumSpherical_3D/vacuum.yml b/examples/VacuumSpherical_3D/vacuum.yml index 8792f029d97f413882ae0ea6c8603d64efaddbfa..851abf74441a48a58eac551bd0526f1d4b6e4ce0 100644 --- a/examples/VacuumSpherical_3D/vacuum.yml +++ b/examples/VacuumSpherical_3D/vacuum.yml @@ -32,4 +32,6 @@ SPH: # Parameters related to the initial conditions InitialConditions: file_name: ./vacuum.hdf5 # The file to read + periodic: 1 + \ No newline at end of file diff --git a/examples/Vacuum_1D/makeIC.py b/examples/Vacuum_1D/makeIC.py index 067304ec951182da862cf2812cdc68a51a56d23b..5b057b340cbfa9718fb230ab1af839bc63678032 100644 --- a/examples/Vacuum_1D/makeIC.py +++ b/examples/Vacuum_1D/makeIC.py @@ -63,10 +63,6 @@ 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 -#Runtime parameters -grp = file.create_group("/RuntimePars") -grp.attrs["PeriodicBoundariesOn"] = 1 - #Units grp = file.create_group("/Units") grp.attrs["Unit length in cgs (U_L)"] = 1. diff --git a/examples/Vacuum_1D/vacuum.yml b/examples/Vacuum_1D/vacuum.yml index 5ef5ce3da68febb086a14ad1a2207711f680d9ff..0be6427e50e1f674f7f59d4b865f2c4f9605a378 100644 --- a/examples/Vacuum_1D/vacuum.yml +++ b/examples/Vacuum_1D/vacuum.yml @@ -31,4 +31,5 @@ SPH: # Parameters related to the initial conditions InitialConditions: file_name: ./vacuum.hdf5 # The file to read + periodic: 1 diff --git a/examples/Vacuum_2D/makeIC.py b/examples/Vacuum_2D/makeIC.py index ef267c092cafdb95457d5adad1e6858df0e14bd3..4d9181b83c0e383d0e3fb0dc6ca79dbda6f88891 100644 --- a/examples/Vacuum_2D/makeIC.py +++ b/examples/Vacuum_2D/makeIC.py @@ -71,10 +71,6 @@ 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 -#Runtime parameters -grp = file.create_group("/RuntimePars") -grp.attrs["PeriodicBoundariesOn"] = 1 - #Units grp = file.create_group("/Units") grp.attrs["Unit length in cgs (U_L)"] = 1. diff --git a/examples/Vacuum_2D/vacuum.yml b/examples/Vacuum_2D/vacuum.yml index 5ef5ce3da68febb086a14ad1a2207711f680d9ff..0be6427e50e1f674f7f59d4b865f2c4f9605a378 100644 --- a/examples/Vacuum_2D/vacuum.yml +++ b/examples/Vacuum_2D/vacuum.yml @@ -31,4 +31,5 @@ SPH: # Parameters related to the initial conditions InitialConditions: file_name: ./vacuum.hdf5 # The file to read + periodic: 1 diff --git a/examples/Vacuum_3D/makeIC.py b/examples/Vacuum_3D/makeIC.py index 09c3cb4d6f5525d54fab59643ab4a7d0540a2a92..cee2d28d5190305a3536315001453e7595b7c7f2 100644 --- a/examples/Vacuum_3D/makeIC.py +++ b/examples/Vacuum_3D/makeIC.py @@ -73,10 +73,6 @@ grp.attrs["MassTable"] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] grp.attrs["Flag_Entropy_ICs"] = 0 grp.attrs["Dimension"] = 3 -#Runtime parameters -grp = file.create_group("/RuntimePars") -grp.attrs["PeriodicBoundariesOn"] = 1 - #Units grp = file.create_group("/Units") grp.attrs["Unit length in cgs (U_L)"] = 1. diff --git a/examples/Vacuum_3D/vacuum.yml b/examples/Vacuum_3D/vacuum.yml index cf44d2441f5009d2fc75084a2c872e3618e40912..49bd9747d677bfdf64009bd1e02a86bc52a8db9c 100644 --- a/examples/Vacuum_3D/vacuum.yml +++ b/examples/Vacuum_3D/vacuum.yml @@ -32,4 +32,5 @@ SPH: # Parameters related to the initial conditions InitialConditions: file_name: ./vacuum.hdf5 # The file to read + periodic: 1 diff --git a/examples/ZeldovichPancake_3D/makeIC.py b/examples/ZeldovichPancake_3D/makeIC.py index 79ed7e71e924941102049b8457fe070ebd08f5c2..efce60f128cacd04e153912d97e0d94b4ab15785 100644 --- a/examples/ZeldovichPancake_3D/makeIC.py +++ b/examples/ZeldovichPancake_3D/makeIC.py @@ -123,10 +123,6 @@ grp.attrs["MassTable"] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] grp.attrs["Flag_Entropy_ICs"] = 0 grp.attrs["Dimension"] = 3 -#Runtime parameters -grp = file.create_group("/RuntimePars") -grp.attrs["PeriodicBoundariesOn"] = 1 - #Units grp = file.create_group("/Units") grp.attrs["Unit length in cgs (U_L)"] = 100. * unit_l_in_si diff --git a/examples/ZeldovichPancake_3D/zeldovichPancake.yml b/examples/ZeldovichPancake_3D/zeldovichPancake.yml index 4d83d805cfebb837f37058167a4e3c974a936317..a1d2342b56d6816c3cfbe7da70220ab244104fbd 100644 --- a/examples/ZeldovichPancake_3D/zeldovichPancake.yml +++ b/examples/ZeldovichPancake_3D/zeldovichPancake.yml @@ -39,7 +39,8 @@ SPH: # Parameters related to the initial conditions InitialConditions: file_name: ./zeldovichPancake.hdf5 # The file to read - + periodic: 1 + Scheduler: max_top_level_cells: 8 cell_split_size: 50 diff --git a/examples/ZoomIn/README b/examples/ZoomIn/README new file mode 100644 index 0000000000000000000000000000000000000000..cffc275f2ae1046156d392f8725a7b542c80471a --- /dev/null +++ b/examples/ZoomIn/README @@ -0,0 +1,16 @@ +Initial conditions for a zoom in cosmological simulation of dwarf +galaxies. These have been generated by MUSIC and ran up to z=0 with +GEAR (see Revaz and Jablonka 2018 for more details on the simulation). + +The cosmology is taken from Planck 2015. + +The initial conditions have been cleaned to contain only the required +fields. The ICs have been created for Gadget and the positions and box +size are hence expressed in h-full units (e.g. box size of 32 / h Mpc). +Similarly, the peculiar velocitites contain an extra sqrt(a) factor. + +We will use SWIFT to cancel the h- and a-factors from the ICs. Gas +particles will be generated at startup. + +MD5 check-sum of the ICS: +9aafe154438478ed435e88664c1c5dba zoom_in.hdf5 diff --git a/examples/ZoomIn/getIC.sh b/examples/ZoomIn/getIC.sh new file mode 100755 index 0000000000000000000000000000000000000000..6cdfaec981af515249578faa72798c53448e7ecb --- /dev/null +++ b/examples/ZoomIn/getIC.sh @@ -0,0 +1,2 @@ +#!/bin/bash +wget https://obswww.unige.ch/~lhausamm/swift/IC/ZoomIn/zoom_in.hdf5 diff --git a/examples/ZoomIn/run.sh b/examples/ZoomIn/run.sh new file mode 100755 index 0000000000000000000000000000000000000000..99eda1cfc779c1958d19d0c7ae234b6c211f8127 --- /dev/null +++ b/examples/ZoomIn/run.sh @@ -0,0 +1,11 @@ +#!/bin/bash + + # Generate the initial conditions if they are not present. +if [ ! -e zoom_in.hdf5 ] +then + echo "Fetching initial conditions for the zoom in example..." + ./getIC.sh +fi + +../swift -b -c -G -s -S -t 8 zoom_in.yml 2>&1 | tee output.log + diff --git a/examples/ZoomIn/zoom_in.yml b/examples/ZoomIn/zoom_in.yml new file mode 100644 index 0000000000000000000000000000000000000000..8e5763c4af700b7fd95beb6188ed886198b559b3 --- /dev/null +++ b/examples/ZoomIn/zoom_in.yml @@ -0,0 +1,62 @@ +# Define the system of units to use internally. +InternalUnitSystem: + UnitMass_in_cgs: 1.98848e43 # 10^10 M_sun in grams + UnitLength_in_cgs: 3.08567758e21 # kpc in centimeters + UnitVelocity_in_cgs: 1e5 # km/s in centimeters per second + UnitCurrent_in_cgs: 1 # Amperes + UnitTemp_in_cgs: 1 # Kelvin + +# Cosmological parameters +Cosmology: + h: 0.673 # Reduced Hubble constant + a_begin: 0.9873046739 # Initial scale-factor of the simulation + a_end: 1.0 # Final scale factor of the simulation + Omega_m: 0.315 # Matter density parameter + Omega_lambda: 0.685 # Dark-energy density parameter + Omega_b: 0.0486 # Baryon density parameter + +Scheduler: + max_top_level_cells: 8 + +# Parameters governing the time integration +TimeIntegration: + time_begin: 0. # The starting time of the simulation (in internal units). + time_end: 1e-2 # The end time of the simulation (in internal units). + dt_min: 1e-10 # The minimal time-step size of the simulation (in internal units). + dt_max: 1e-3 # The maximal time-step size of the simulation (in internal units). + +# Parameters governing the snapshots +Snapshots: + basename: zoom_in # Common part of the name of output files + scale_factor_first: 0.987345 # Scale-factor of the first snaphot (cosmological run) + time_first: 0.01 # Time of the first output (non-cosmological run) (in internal units) + delta_time: 1.01 # Time difference between consecutive outputs (in internal units) + compression: 1 + +# Parameters governing the conserved quantities statistics +Statistics: + scale_factor_first: 0.987345 # Scale-factor of the first stat dump (cosmological run) + time_first: 0.01 # Time of the first stat dump (non-cosmological run) (in internal units) + delta_time: 1.05 # Time between statistics output + +# Parameters for the self-gravity scheme +Gravity: + eta: 0.025 # Constant dimensionless multiplier for time integration. + theta: 0.7 # Opening angle (Multipole acceptance criterion) + comoving_softening: 0.05 # Comoving softening length (in internal units). + max_physical_softening: 0.01 # Physical softening length (in internal units). + mesh_side_length: 16 + +# Parameters for the hydrodynamics scheme +SPH: + resolution_eta: 1.2348 # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel). + CFL_condition: 0.1 # Courant-Friedrich-Levy condition for time integration. + minimal_temperature: 100 # (internal units) + +# Parameters related to the initial conditions +InitialConditions: + file_name: ./zoom_in.hdf5 # The file to read + periodic: 1 + cleanup_h_factors: 1 # Remove the h-factors inherited from Gadget + cleanup_velocity_factors: 1 # Remove the sqrt(a) factor in the velocities inherited from Gadget + diff --git a/examples/analye_runtime.py b/examples/analyse_runtime.py similarity index 93% rename from examples/analye_runtime.py rename to examples/analyse_runtime.py index 9adbe9c5cf722e2953c35b995bb9f9470ad052fb..9093dfc2346e7ee5f5707a7085a786672caa2104 100644 --- a/examples/analye_runtime.py +++ b/examples/analyse_runtime.py @@ -52,8 +52,9 @@ labels = ['Gpart assignment', 'Mesh comunication', 'Forward Fourier transform', 'Making gravity tasks', 'Splitting tasks', 'Counting and linking tasks', 'Setting super-pointers', 'Linking gravity tasks', 'Creating send tasks', 'Exchanging cell tags', 'Creating recv tasks', 'Setting unlocks', 'Ranking the tasks', 'scheduler_reweight:', 'space_rebuild:', 'engine_drift_all:', 'engine_unskip:', 'engine_collect_end_of_step:', 'engine_launch:', 'writing particle properties', - 'engine_repartition:', 'engine_exchange_cells:', 'Dumping restart files', 'engine_print_stats:', 'engine_marktasks:'] -is_rebuild = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1] + 'engine_repartition:', 'engine_exchange_cells:', 'Dumping restart files', 'engine_print_stats:', 'engine_marktasks:', + 'Reading initial conditions', 'engine_print_task_counts:', 'engine_drift_top_multipoles:', 'Communicating rebuild flag'] +is_rebuild = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0] times = np.zeros(len(labels)) counts = np.zeros(len(labels)) @@ -81,7 +82,7 @@ for i in range(num_files): # Extract the different blocks if re.search("%s took"%labels[i], line): counts[i] += 1. - times[i] += float(re.findall(r'[+-]?([0-9]*[.])?[0-9]+', line)[-1]) + times[i] += float(re.findall(r'[+-]?((\d+\.?\d*)|(\.\d+))', line)[-1][0]) # Find the last line with meaningful output (avoid crash report, batch system stuf....) if re.findall(r'\[[0-9]{4}\][ ]\[*', line) or re.findall(r'^\[[0-9]*[.][0-9]+\][ ]', line): diff --git a/examples/analyse_tasks.py b/examples/analyse_tasks.py index 78d03ae5436a1fc56abcd6f6b99a4920011fa6db..48a00a63ea5da5cb80ebd6f10187cc613c1a5ed5 100755 --- a/examples/analyse_tasks.py +++ b/examples/analyse_tasks.py @@ -54,7 +54,7 @@ infile = args.input TASKTYPES = ["none", "sort", "self", "pair", "sub_self", "sub_pair", "init_grav", "init_grav_out", "ghost_in", "ghost", "ghost_out", "extra_ghost", "drift_part", "drift_gpart", "end_force", "kick1", "kick2", "timestep", "send", "recv", "grav_long_range", "grav_mm", "grav_down_in", - "grav_down", "grav_mesh", "cooling", "sourceterms", + "grav_down", "grav_mesh", "cooling", "star_formation", "sourceterms", "stars_ghost_in", "stars_ghost", "stars_ghost_out", "count"] diff --git a/examples/getCoolingTable.sh b/examples/getCoolingTable.sh old mode 100644 new mode 100755 diff --git a/examples/main.c b/examples/main.c index 768640afe54f82cdd8208efeb1d13690e8e2c5e3..ca3c041702db6592a5d13e8d26ce7570ec9243a9 100644 --- a/examples/main.c +++ b/examples/main.c @@ -605,9 +605,23 @@ int main(int argc, char *argv[]) { /* How often to check for the stop file and dump restarts and exit the * application. */ - int restart_stop_steps = + const int restart_stop_steps = parser_get_opt_param_int(params, "Restarts:stop_steps", 100); + /* Get the maximal wall-clock time of this run */ + const float restart_max_hours_runtime = + parser_get_opt_param_float(params, "Restarts:max_run_time", FLT_MAX); + + /* Do we want to resubmit when we hit the limit? */ + const int resubmit_after_max_hours = + parser_get_opt_param_int(params, "Restarts:resubmit_on_exit", 0); + + /* What command should we run to resubmit at the end? */ + char resubmit_command[PARSER_MAX_LINE_SIZE]; + if (resubmit_after_max_hours) + parser_get_param_string(params, "Restarts:resubmit_command", + resubmit_command); + /* If restarting, look for the restart files. */ if (restart) { @@ -693,6 +707,28 @@ int main(int argc, char *argv[]) { phys_const_print(&prog_const); } + /* Read particles and space information from ICs */ + char ICfileName[200] = ""; + parser_get_param_string(params, "InitialConditions:file_name", ICfileName); + const int periodic = + parser_get_param_int(params, "InitialConditions:periodic"); + const int replicate = + parser_get_opt_param_int(params, "InitialConditions:replicate", 1); + clean_smoothing_length_values = parser_get_opt_param_int( + params, "InitialConditions:cleanup_smoothing_lengths", 0); + const int cleanup_h = parser_get_opt_param_int( + params, "InitialConditions:cleanup_h_factors", 0); + const int cleanup_sqrt_a = parser_get_opt_param_int( + params, "InitialConditions:cleanup_velocity_factors", 0); + const int generate_gas_in_ics = parser_get_opt_param_int( + params, "InitialConditions:generate_gas_in_ics", 0); + + /* Some checks that we are not doing something stupid */ + if (generate_gas_in_ics && flag_entropy_ICs) + error("Can't generate gas if the entropy flag is set in the ICs."); + if (generate_gas_in_ics && !with_cosmology) + error("Can't generate gas if the run is not cosmological."); + /* Initialise the cosmology */ if (with_cosmology) cosmology_init(params, &us, &prog_const, &cosmo); @@ -721,27 +757,12 @@ int main(int argc, char *argv[]) { /* Initialise the gravity properties */ if (with_self_gravity) - gravity_props_init(&gravity_properties, params, &cosmo, with_cosmology); + gravity_props_init(&gravity_properties, params, &cosmo, with_cosmology, + periodic); else bzero(&gravity_properties, sizeof(struct gravity_props)); - /* Read particles and space information from (GADGET) ICs */ - char ICfileName[200] = ""; - parser_get_param_string(params, "InitialConditions:file_name", ICfileName); - const int replicate = - parser_get_opt_param_int(params, "InitialConditions:replicate", 1); - clean_smoothing_length_values = parser_get_opt_param_int( - params, "InitialConditions:cleanup_smoothing_lengths", 0); - const int cleanup_h = parser_get_opt_param_int( - params, "InitialConditions:cleanup_h_factors", 0); - const int cleanup_sqrt_a = parser_get_opt_param_int( - params, "InitialConditions:cleanup_velocity_factors", 0); - const int generate_gas_in_ics = parser_get_opt_param_int( - params, "InitialConditions:generate_gas_in_ics", 0); - if (generate_gas_in_ics && flag_entropy_ICs) - error("Can't generate gas if the entropy flag is set in the ICs."); - if (generate_gas_in_ics && !with_cosmology) - error("Can't generate gas if the run is not cosmological."); + /* Be verbose about what happens next */ if (myrank == 0) message("Reading ICs from file '%s'", ICfileName); if (myrank == 0 && cleanup_h) message("Cleaning up h-factors (h=%f)", cosmo.h); @@ -752,20 +773,19 @@ int main(int argc, char *argv[]) { /* Get ready to read particles of all kinds */ size_t Ngas = 0, Ngpart = 0, Nspart = 0; double dim[3] = {0., 0., 0.}; - int periodic = 0; if (myrank == 0) clocks_gettime(&tic); #if defined(HAVE_HDF5) #if defined(WITH_MPI) #if defined(HAVE_PARALLEL_HDF5) read_ic_parallel(ICfileName, &us, dim, &parts, &gparts, &sparts, &Ngas, - &Ngpart, &Nspart, &periodic, &flag_entropy_ICs, with_hydro, + &Ngpart, &Nspart, &flag_entropy_ICs, with_hydro, (with_external_gravity || with_self_gravity), with_stars, cleanup_h, cleanup_sqrt_a, cosmo.h, cosmo.a, myrank, nr_nodes, MPI_COMM_WORLD, MPI_INFO_NULL, nr_threads, dry_run); #else read_ic_serial(ICfileName, &us, dim, &parts, &gparts, &sparts, &Ngas, - &Ngpart, &Nspart, &periodic, &flag_entropy_ICs, with_hydro, + &Ngpart, &Nspart, &flag_entropy_ICs, with_hydro, (with_external_gravity || with_self_gravity), with_stars, cleanup_h, cleanup_sqrt_a, cosmo.h, cosmo.a, myrank, nr_nodes, MPI_COMM_WORLD, MPI_INFO_NULL, nr_threads, @@ -773,7 +793,7 @@ int main(int argc, char *argv[]) { #endif #else read_ic_single(ICfileName, &us, dim, &parts, &gparts, &sparts, &Ngas, - &Ngpart, &Nspart, &periodic, &flag_entropy_ICs, with_hydro, + &Ngpart, &Nspart, &flag_entropy_ICs, with_hydro, (with_external_gravity || with_self_gravity), with_stars, cleanup_h, cleanup_sqrt_a, cosmo.h, cosmo.a, nr_threads, dry_run); @@ -931,6 +951,9 @@ int main(int argc, char *argv[]) { engine_policies |= engine_policy_structure_finding; if (with_fof) engine_policies |= engine_policy_fof; + // 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], @@ -1001,6 +1024,10 @@ int main(int argc, char *argv[]) { engine_init_particles(&e, flag_entropy_ICs, clean_smoothing_length_values, 1); /* Write the state of the system before starting time integration. */ +#ifdef WITH_LOGGER + logger_log_all(e.logger, &e); + engine_dump_index(&e); +#endif engine_dump_snapshot(&e); engine_print_stats(&e); @@ -1049,7 +1076,7 @@ int main(int argc, char *argv[]) { /* Main simulation loop */ /* ==================== */ - int force_stop = 0; + int force_stop = 0, resubmit = 0; for (int j = 0; !engine_is_done(&e) && e.step - 1 != nsteps && !force_stop; j++) { @@ -1070,6 +1097,13 @@ int main(int argc, char *argv[]) { message("Forcing application exit, dumping restart files..."); } + /* Did we exceed the maximal runtime? */ + if (clocks_get_hours_since_start() > restart_max_hours_runtime) { + force_stop = 1; + message("Runtime limit reached, dumping restart files..."); + if (resubmit_after_max_hours) resubmit = 1; + } + /* Also if using nsteps to exit, will not have saved any restarts on exit, * make sure we do that (useful in testing only). */ if (force_stop || (e.restart_onexit && e.step - 1 == nsteps)) @@ -1081,8 +1115,8 @@ int main(int argc, char *argv[]) { #ifdef WITH_MPI /* Make sure output file is empty, only on one rank. */ - char dumpfile[30]; - snprintf(dumpfile, 30, "thread_info_MPI-step%d.dat", j + 1); + char dumpfile[35]; + snprintf(dumpfile, sizeof(dumpfile), "thread_info_MPI-step%d.dat", j + 1); FILE *file_thread; if (myrank == 0) { file_thread = fopen(dumpfile, "w"); @@ -1108,21 +1142,24 @@ int main(int argc, char *argv[]) { int count = 0; for (int l = 0; l < e.sched.nr_tasks; l++) { if (!e.sched.tasks[l].implicit && e.sched.tasks[l].toc != 0) { - fprintf( - file_thread, - " %03i %i %i %i %i %lli %lli %i %i %i %i %lli %i\n", myrank, - e.sched.tasks[l].rid, e.sched.tasks[l].type, - e.sched.tasks[l].subtype, (e.sched.tasks[l].cj == NULL), - e.sched.tasks[l].tic, e.sched.tasks[l].toc, - (e.sched.tasks[l].ci != NULL) ? e.sched.tasks[l].ci->count - : 0, - (e.sched.tasks[l].cj != NULL) ? e.sched.tasks[l].cj->count - : 0, - (e.sched.tasks[l].ci != NULL) ? e.sched.tasks[l].ci->gcount - : 0, - (e.sched.tasks[l].cj != NULL) ? e.sched.tasks[l].cj->gcount - : 0, - e.sched.tasks[l].flags, e.sched.tasks[l].sid); + fprintf(file_thread, + " %03i %i %i %i %i %lli %lli %i %i %i %i %lli %i\n", + myrank, e.sched.tasks[l].rid, e.sched.tasks[l].type, + e.sched.tasks[l].subtype, (e.sched.tasks[l].cj == NULL), + e.sched.tasks[l].tic, e.sched.tasks[l].toc, + (e.sched.tasks[l].ci != NULL) + ? e.sched.tasks[l].ci->hydro.count + : 0, + (e.sched.tasks[l].cj != NULL) + ? e.sched.tasks[l].cj->hydro.count + : 0, + (e.sched.tasks[l].ci != NULL) + ? e.sched.tasks[l].ci->grav.count + : 0, + (e.sched.tasks[l].cj != NULL) + ? e.sched.tasks[l].cj->grav.count + : 0, + e.sched.tasks[l].flags, e.sched.tasks[l].sid); } fflush(stdout); count++; @@ -1135,8 +1172,8 @@ int main(int argc, char *argv[]) { } #else - char dumpfile[30]; - snprintf(dumpfile, 30, "thread_info-step%d.dat", j + 1); + char dumpfile[32]; + snprintf(dumpfile, sizeof(dumpfile), "thread_info-step%d.dat", j + 1); FILE *file_thread; file_thread = fopen(dumpfile, "w"); /* Add some information to help with the plots */ @@ -1150,10 +1187,14 @@ int main(int argc, char *argv[]) { e.sched.tasks[l].rid, e.sched.tasks[l].type, e.sched.tasks[l].subtype, (e.sched.tasks[l].cj == NULL), e.sched.tasks[l].tic, e.sched.tasks[l].toc, - (e.sched.tasks[l].ci == NULL) ? 0 : e.sched.tasks[l].ci->count, - (e.sched.tasks[l].cj == NULL) ? 0 : e.sched.tasks[l].cj->count, - (e.sched.tasks[l].ci == NULL) ? 0 : e.sched.tasks[l].ci->gcount, - (e.sched.tasks[l].cj == NULL) ? 0 : e.sched.tasks[l].cj->gcount, + (e.sched.tasks[l].ci == NULL) ? 0 + : e.sched.tasks[l].ci->hydro.count, + (e.sched.tasks[l].cj == NULL) ? 0 + : e.sched.tasks[l].cj->hydro.count, + (e.sched.tasks[l].ci == NULL) ? 0 + : e.sched.tasks[l].ci->grav.count, + (e.sched.tasks[l].cj == NULL) ? 0 + : e.sched.tasks[l].cj->grav.count, e.sched.tasks[l].sid); } } @@ -1212,17 +1253,24 @@ int main(int argc, char *argv[]) { } /* Write final output. */ - engine_drift_all(&e); - engine_print_stats(&e); - engine_dump_snapshot(&e); + if (!force_stop) { + engine_drift_all(&e); + engine_print_stats(&e); +#ifdef WITH_LOGGER + logger_log_all(e.logger, &e); + engine_dump_index(&e); +#endif + // write a final snapshot with logger, in order to facilitate a restart + engine_dump_snapshot(&e); #ifdef HAVE_VELOCIRAPTOR - /* Call VELOCIraptor at the end of the run to find groups. */ - if (e.policy & engine_policy_structure_finding) { - velociraptor_init(&e); - velociraptor_invoke(&e); - } + /* Call VELOCIraptor at the end of the run to find groups. */ + if (e.policy & engine_policy_structure_finding) { + velociraptor_init(&e); + velociraptor_invoke(&e); + } #endif + } #ifdef WITH_MPI if ((res = MPI_Finalize()) != MPI_SUCCESS) @@ -1233,10 +1281,19 @@ int main(int argc, char *argv[]) { * stop file if normal exit happened first. */ if (myrank == 0) force_stop = restart_stop_now(restart_dir, 1); + /* Did we want to run a re-submission command just before dying? */ + if (myrank == 0 && resubmit) { + message("Running the resubmission command:"); + restart_resubmit(resubmit_command); + fflush(stdout); + fflush(stderr); + message("resubmission command completed."); + } + /* Clean everything */ if (with_verbose_timers) timers_close_file(); - if (with_cosmology) cosmology_clean(&cosmo); - if (with_self_gravity) pm_mesh_clean(&mesh); + if (with_cosmology) cosmology_clean(e.cosmology); + if (with_self_gravity) pm_mesh_clean(e.mesh); engine_clean(&e); free(params); diff --git a/examples/parameter_example.yml b/examples/parameter_example.yml index 3f83a8f25b312cb167922f7e094c616f16211bf9..63a61af3e714d5dd6b19312e9a233f51deda0011 100644 --- a/examples/parameter_example.yml +++ b/examples/parameter_example.yml @@ -34,6 +34,10 @@ SPH: minimal_temperature: 0 # (Optional) Minimal temperature (in internal units) allowed for the gas particles. Value is ignored if set to 0. H_mass_fraction: 0.755 # (Optional) Hydrogen mass fraction used for initial conversion from temp to internal energy. Default value is derived from the physical constants. H_ionization_temperature: 1e4 # (Optional) Temperature of the transition from neutral to ionized Hydrogen for primoridal gas. + viscosity_alpha: 0.8 # (Optional) Override for the initial value of the artificial viscosity. In schemes that have a fixed AV, this remains as alpha throughout the run. + viscosity_alpha_max: 2.0 # (Optional) Maximal value for the artificial viscosity in schemes that allow alpha to vary + viscosity_alpha_min: 0.1 # (Optional) Minimal value for the artificial viscosity in schemes that allow alpha to vary + viscosity_length: 0.1 # (Optional) Decay length for the artificial viscosity in schemes that allow alpha to vary # Parameters for the self-gravity scheme Gravity: @@ -87,6 +91,13 @@ Snapshots: output_list_on: 0 # (Optional) Enable the output list output_list: snaplist.txt # (Optional) File containing the output times (see documentation in "Parameter File" section) +# Parameters governing the logger snapshot system +Logger: + delta_step: 10 # Update the particle log every this many updates + initial_buffer_size: 1 # buffer size in GB + buffer_scale: 10 # (Optional) When buffer size is too small, update it with required memory times buffer_scale + basename: index # Common part of the filenames + # Parameters governing the conserved quantities statistics Statistics: delta_time: 1e-2 # Time between statistics output @@ -100,6 +111,7 @@ Statistics: # Parameters related to the initial conditions InitialConditions: file_name: SedovBlast/sedov.hdf5 # The file to read + periodic: 1 # Are we running with periodic ICs? generate_gas_in_ics: 0 # (Optional) Generate gas particles from the DM-only ICs (e.g. from panphasia). cleanup_h_factors: 0 # (Optional) Clean up the h-factors used in the ICs (e.g. in Gadget files). cleanup_velocity_factors: 0 # (Optional) Clean up the scale-factors used in the definition of the velocity variable in the ICs (e.g. in Gadget files). @@ -110,13 +122,16 @@ InitialConditions: # Parameters controlling restarts Restarts: - enable: 1 # (Optional) whether to enable dumping restarts at fixed intervals. - save: 1 # (Optional) whether to save copies of the previous set of restart files (named .prev) - onexit: 0 # (Optional) whether to dump restarts on exit (*needs enable*) - subdir: restart # (Optional) name of subdirectory for restart files. - basename: swift # (Optional) prefix used in naming restart files. - delta_hours: 6.0 # (Optional) decimal hours between dumps of restart files. - stop_steps: 100 # (Optional) how many steps to process before checking if the <subdir>/stop file exists. When present the application will attempt to exit early, dumping restart files first. + enable: 1 # (Optional) whether to enable dumping restarts at fixed intervals. + save: 1 # (Optional) whether to save copies of the previous set of restart files (named .prev) + onexit: 0 # (Optional) whether to dump restarts on exit (*needs enable*) + subdir: restart # (Optional) name of subdirectory for restart files. + basename: swift # (Optional) prefix used in naming restart files. + delta_hours: 6.0 # (Optional) decimal hours between dumps of restart files. + stop_steps: 100 # (Optional) how many steps to process before checking if the <subdir>/stop file exists. When present the application will attempt to exit early, dumping restart files first. + max_run_time: 24.0 # (optional) Maximal wall-clock time in hours. The application will exit when this limit is reached. + resubmit_on_exit: 0 # (Optional) whether to run a command when exiting after the time limit has been reached. + resubmit_command: ./resub.sh # (Optional) Command to run when time limit is reached. Compulsory if resubmit_on_exit is switched on. Note potentially unsafe. # Parameters governing domain decomposition DomainDecomposition: @@ -133,9 +148,9 @@ DomainDecomposition: # new decomposition, or number of steps (>1) between decompositions minfrac: 0.9 # (Optional) Fractional of all particles that should be updated in previous step when # using CPU time trigger - usemetis 0 # Use serial METIS when ParMETIS is also available. - adaptive 1 # Use adaptive repartition when ParMETIS is available, otherwise simple refinement. - itr 100 # When adaptive defines the ratio of inter node communication time to data redistribution time, in the range 0.00001 to 10000000.0. + usemetis: 0 # Use serial METIS when ParMETIS is also available. + adaptive: 1 # Use adaptive repartition when ParMETIS is available, otherwise simple refinement. + itr: 100 # When adaptive defines the ratio of inter node communication time to data redistribution time, in the range 0.00001 to 10000000.0. # Lower values give less data movement during redistributions, at the cost of global balance which may require more communication. # Parameters related to the equation of state ------------------------------------------ @@ -160,6 +175,7 @@ EoS: # Point mass external potentials PointMassPotential: + useabspos: 0 # 0 -> positions based on centre, 1 -> absolute positions position: [50.,50.0,50.] # location of external point mass (internal units) mass: 1e10 # mass of external point mass (internal units) timestep_mult: 0.03 # Dimensionless pre-factor for the time-step condition @@ -167,10 +183,29 @@ PointMassPotential: # Isothermal potential parameters IsothermalPotential: + useabspos: 0 # 0 -> positions based on centre, 1 -> absolute positions position: [100.,100.,100.] # Location of centre of isothermal potential with respect to centre of the box (internal units) vrot: 200. # Rotation speed of isothermal potential (internal units) timestep_mult: 0.03 # Dimensionless pre-factor for the time-step condition epsilon: 0.1 # Softening size (internal units) + +# Hernquist potential parameters +HernquistPotential: + useabspos: 0 # 0 -> positions based on centre, 1 -> absolute positions + position: [100.,100.,100.] # Location of centre of isothermal potential with respect to centre of the box (if 0) otherwise absolute (if 1) (internal units) + mass: 1e10 # Mass of the Hernquist potential + scalelength: 10.0 # Scale length of the potential + timestep_mult: 0.01 # Dimensionless pre-factor for the time-step condition, basically determines the fraction of the orbital time we use to do the time integration + epsilon: 0.1 # Softening size (internal units) + +# Isothermal potential parameters +NFWPotential: + useabspos: 0 + position: [0.0,0.0,0.0] # Location of centre of isothermal potential with respect to centre of the box (internal units) if useabspos=0 otherwise with respect to the 0,0,0, coordinates. + concentration: 8. # Concentration of the halo + M_200: 2.0e+12 # Mass of the halo (M_200 in internal units) + critical_density: 127.4 # Critical density (internal units). + timestep_mult: 0.01 # Dimensionless pre-factor for the time-step condition, basically determines fraction of orbital time we need to do an integration step # Disk-patch potential parameters DiscPatchPotential: @@ -198,11 +233,8 @@ ConstCooling: # Constant lambda cooling function LambdaCooling: - lambda: 2.0 # Cooling rate (in cgs units) - minimum_temperature: 1.0e4 # Minimal temperature (Kelvin) - mean_molecular_weight: 0.59 # Mean molecular weight - hydrogen_mass_abundance: 0.75 # Hydrogen mass abundance (dimensionless) - cooling_tstep_mult: 1.0 # Dimensionless pre-factor for the time-step condition + 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. # Cooling with Grackle 3.0 GrackleCooling: diff --git a/examples/plot_task_level.py b/examples/plot_task_level.py new file mode 100644 index 0000000000000000000000000000000000000000..2d51f4829692bc71826ec6c4b93c025f7106828f --- /dev/null +++ b/examples/plot_task_level.py @@ -0,0 +1,43 @@ +#!/usr/bin/python +""" +Usage: + ./plot_task_level.py task_level.txt + +Description: + Plot the number of tasks for each depth level and each type of task. +""" + + +import pandas as pd +import matplotlib.pyplot as plt +import sys + +# get filename +filename = sys.argv[-1] + +# Column names +names = ["type", "subtype", "depth", "count"] + +# read file +data = pd.read_csv(filename, sep=' ', comment="#", names=names) + +# generate color map +cmap = plt.get_cmap("hsv") +N = data["depth"].max() + 5 + +# plot data +for i in range(data["depth"].max()): + ind = data["depth"] == i + label = "depth = %i" % i + c = cmap(i / N) + plt.plot(data["type"][ind] + "_" + data["subtype"][ind], + data["count"][ind], ".", label=label, + color=c) + +# modify figure parameters and show it +plt.gca().set_yscale("log") +plt.xticks(rotation=45) +plt.ylabel("Number of Tasks") +plt.gcf().subplots_adjust(bottom=0.15) +plt.legend() +plt.show() diff --git a/examples/plot_tasks.py b/examples/plot_tasks.py index a8d8c49a7ca8676278ac1ab50c7b6cdf3755445c..76128ac66af21cd5f6d9a7ab0546ed813bde4536 100755 --- a/examples/plot_tasks.py +++ b/examples/plot_tasks.py @@ -112,7 +112,7 @@ pl.rcParams.update(PLOT_PARAMS) TASKTYPES = ["none", "sort", "self", "pair", "sub_self", "sub_pair", "init_grav", "init_grav_out", "ghost_in", "ghost", "ghost_out", "extra_ghost", "drift_part", "drift_gpart", "end_force", "kick1", "kick2", "timestep", "send", "recv", "grav_long_range", "grav_mm", "grav_down_in", - "grav_down", "grav_mesh", "cooling", "sourceterms", + "grav_down", "grav_mesh", "cooling", "star_formation", "sourceterms", "stars_ghost_in", "stars_ghost", "stars_ghost_out", "count"] @@ -157,11 +157,11 @@ for task in SUBTYPES: # For fiddling with colours... if args.verbose: - print "#Selected colours:" + print("#Selected colours:") for task in sorted(TASKCOLOURS.keys()): - print "# " + task + ": " + TASKCOLOURS[task] + print("# " + task + ": " + TASKCOLOURS[task]) for task in sorted(SUBCOLOURS.keys()): - print "# " + task + ": " + SUBCOLOURS[task] + print("# " + task + ": " + SUBCOLOURS[task]) # Read input. data = pl.loadtxt( infile ) @@ -169,11 +169,11 @@ data = pl.loadtxt( infile ) # Do we have an MPI file? full_step = data[0,:] if full_step.size == 13: - print "# MPI mode" + print("# MPI mode") mpimode = True if ranks == None: ranks = range(int(max(data[:,0])) + 1) - print "# Number of ranks:", len(ranks) + print("# Number of ranks:", len(ranks)) rankcol = 0 threadscol = 1 taskcol = 2 @@ -181,7 +181,7 @@ if full_step.size == 13: ticcol = 5 toccol = 6 else: - print "# non MPI mode" + print("# non MPI mode") ranks = [0] mpimode = False rankcol = -1 @@ -194,10 +194,10 @@ else: # Get CPU_CLOCK to convert ticks into milliseconds. CPU_CLOCK = float(full_step[-1]) / 1000.0 if args.verbose: - print "# CPU frequency:", CPU_CLOCK * 1000.0 + print("# CPU frequency:", CPU_CLOCK * 1000.0) nthread = int(max(data[:,threadscol])) + 1 -print "# Number of threads:", nthread +print("# Number of threads:", nthread) # Avoid start and end times of zero. sdata = data[data[:,ticcol] != 0] @@ -224,28 +224,31 @@ if delta_t == 0: dt = toc_step - tic_step if dt > delta_t: delta_t = dt - print "# Data range: ", delta_t / CPU_CLOCK, "ms" + print("# Data range: ", delta_t / CPU_CLOCK, "ms") # Once more doing the real gather and plots this time. for rank in ranks: - print "# Processing rank: ", rank + print("# Processing rank: ", rank) if mpimode: data = sdata[sdata[:,rankcol] == rank] full_step = data[0,:] tic_step = int(full_step[ticcol]) toc_step = int(full_step[toccol]) - print "# Min tic = ", tic_step + print("# Min tic = ", tic_step) data = data[1:,:] typesseen = [] nethread = 0 # Dummy image for ranks that have no tasks. if data.size == 0: - print "# Rank ", rank, " has no tasks" + print("# Rank ", rank, " has no tasks") fig = pl.figure() ax = fig.add_subplot(1,1,1) ax.set_xlim(-delta_t * 0.01 / CPU_CLOCK, delta_t * 1.01 / CPU_CLOCK) - ax.set_ylim(0, nthread*expand) + if nthread == 0: + ax.set_ylim(0, expand) + else: + ax.set_ylim(0, nthread*expand) if mintic < 0: start_t = tic_step else: @@ -305,7 +308,7 @@ for rank in ranks: fig = pl.figure() ax = fig.add_subplot(1,1,1) ax.set_xlim(-delta_t * 0.01 / CPU_CLOCK, delta_t * 1.01 / CPU_CLOCK) - ax.set_ylim(0, nethread) + ax.set_ylim(0.5, nethread+1.0) for i in range(nethread): # Collect ranges and colours into arrays. @@ -327,19 +330,16 @@ for rank in ranks: typesseen.append(qtask) # Now plot. - ax.broken_barh(tictocs, [i+0.05,0.90], facecolors = colours, linewidth=0) + ax.broken_barh(tictocs, [i+0.55,0.9], facecolors = colours, linewidth=0) # Legend and room for it. - nrow = len(typesseen) / 5 - ax.fill_between([0, 0], nethread+0.5, nethread + nrow + 0.5, facecolor="white") - ax.set_ylim(0, nethread + 0.5) + nrow = len(typesseen) / 8 + ax.fill_between([0, 0], nethread, nethread + nrow, facecolor="white") if data.size > 0 and not args.nolegend: - ax.fill_between([0, 0], nethread+0.5, nethread + nrow + 0.5, facecolor="white") - ax.set_ylim(0, nethread + 0.5) - ax.legend(loc=1, shadow=True, bbox_to_anchor=(0., 1.05 ,1., 0.2), mode="expand", ncol=5) - box = ax.get_position() - ax.set_position([box.x0, box.y0, box.width, box.height*0.8]) + ax.fill_between([0, 0], nethread, nethread + nrow, facecolor="white") + ax.legend(loc="lower left", shadow=True, + bbox_to_anchor=(0., 1.0, 1., 0.2), mode="expand", ncol=8) # Start and end of time-step if mintic < 0: @@ -366,7 +366,7 @@ for rank in ranks: outpng = outbase + str(rank) + ".png" else: outpng = outbase + ".png" - pl.savefig(outpng) - print "Graphics done, output written to", outpng + pl.savefig(outpng, bbox_inches="tight") + print("Graphics done, output written to", outpng) sys.exit(0) diff --git a/examples/process_plot_tasks_MPI b/examples/process_plot_tasks_MPI index 22c9a106f52ca28244f9fef60839b1125474f14c..736aad05b98aea619f79e2b2114815c8e0fbaa1c 100755 --- a/examples/process_plot_tasks_MPI +++ b/examples/process_plot_tasks_MPI @@ -87,10 +87,22 @@ echo $list | xargs -n 3 | while read f s g; do <ul style="list-style-type:none"> <li> EOF + + cat <<EOF3 > step${s}r.html +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<html> +<body> +EOF3 + for i in $(seq 0 $nrank); do - cat <<EOF2 >> index.html -<a href="step${s}r${i}.html"><img src="step${s}r${i}.png" width=400px/></a> -EOF2 + + cat <<EOF >> index.html +<a href="step${s}r.html"><img src="step${s}r${i}.png" width=400px/></a> +EOF + cat <<EOF3 >> step${s}r.html +<a href="step${s}r${i}.html"><img src="step${s}r${i}.png"/></a> +EOF3 + cat <<EOF2 > step${s}r${i}.html <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> @@ -104,7 +116,14 @@ cat <<EOF2 >> step${s}r${i}.html </body> </html> EOF2 + done + +cat <<EOF3 >> step${s}r.html +</body> +</html> +EOF3 + cat <<EOF >> index.html </li> </ul> diff --git a/m4/ax_gcc_archflag.m4 b/m4/ax_gcc_archflag.m4 index b91c9e8f4003ce7ee70a3f587b89df754f7302d5..ef8e7c199da1622354a029ec142386b7f1f9e442 100644 --- a/m4/ax_gcc_archflag.m4 +++ b/m4/ax_gcc_archflag.m4 @@ -65,7 +65,7 @@ # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. -#serial 21 (modified for SWIFT) +#serial 22 (modified for SWIFT) AC_DEFUN([AX_GCC_ARCHFLAG], [AC_REQUIRE([AC_PROG_CC]) @@ -109,7 +109,7 @@ case $host_cpu in *3?6[[ae]]?:*:*:*) ax_gcc_arch="ivybridge core-avx-i corei7-avx corei7 core2 pentium-m pentium3 pentiumpro" ;; *3?6[[cf]]?:*:*:*|*4?6[[56]]?:*:*:*) ax_gcc_arch="haswell core-avx2 core-avx-i corei7-avx corei7 core2 pentium-m pentium3 pentiumpro" ;; *3?6d?:*:*:*|*4?6[[7f]]?:*:*:*|*5?66?:*:*:*) ax_gcc_arch="broadwell core-avx2 core-avx-i corei7-avx corei7 core2 pentium-m pentium3 pentiumpro" ;; - *4?6[[de]]?:*:*:*) ax_gcc_arch="skylake haswell sandybridge core-avx2 core-avx-i corei7-avx corei7 core2 pentium-m pentium3 pentiumpro" ;; + *4?6[[de]]?:*:*:*|*5?6[[de]]?:*:*:*) ax_gcc_arch="skylake haswell sandybridge core-avx2 core-avx-i corei7-avx corei7 core2 pentium-m pentium3 pentiumpro" ;; *5?6[[56]]?:*:*:*) ax_gcc_arch="skylake-avx512 skylake haswell sandybridge core-avx2 core-avx-i corei7-avx corei7 core2 pentium-m pentium3 pentiumpro" ;; *8?6[[de]]?:*:*:*|*9?6[[de]]?:*:*:*) ax_gcc_arch="kabylake skylake broadwell haswell sandybridge core-avx2 core-avx-i corei7-avx corei7 core2 pentium-m pentium3 pentiumpro" ;; *1?6c?:*:*:*|*2?6[[67]]?:*:*:*|*3?6[[56]]?:*:*:*) ax_gcc_arch="bonnell atom core2 pentium-m pentium3 pentiumpro" ;; @@ -201,6 +201,10 @@ case $host_cpu in *POWER4*|*power4*|*gq*) ax_gcc_arch="power4 970";; *POWER5*|*power5*|*gr*|*gs*) ax_gcc_arch="power5 power4 970";; 603ev|8240) ax_gcc_arch="$cputype 603e 603";; + *POWER7*) ax_gcc_arch="power7";; + *POWER8*) ax_gcc_arch="power8";; + *POWER9*) ax_gcc_arch="power9";; + *POWER10*) ax_gcc_arch="power10";; *) ax_gcc_arch=$cputype ;; esac ax_gcc_arch="$ax_gcc_arch powerpc" diff --git a/src/Makefile.am b/src/Makefile.am index 5f486c93122cf593312119041c99d476b0dc3629..839ad42a724195896da0a5fea8d05141d6656f59 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) +AM_CFLAGS = $(HDF5_CPPFLAGS) $(GSL_INCS) $(FFTW_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_LIB) $(GSL_LIBS) +EXTRA_LIBS = $(HDF5_LIBS) $(FFTW_LIBS) $(PROFILER_LIBS) $(TCMALLOC_LIBS) $(JEMALLOC_LIBS) $(TBBMALLOC_LIBS) $(GRACKLE_LIBS) $(GSL_LIBS) # MPI libraries. MPI_LIBS = $(PARMETIS_LIBS) $(METIS_LIBS) $(MPI_THREAD_LIBS) @@ -48,11 +48,12 @@ include_HEADERS = space.h runner.h queue.h task.h lock.h cell.h part.h const.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 fof.h + mesh_gravity.h cbrt.h velociraptor_interface.h swift_velociraptor_part.h outputlist.h fof.h \ + logger_io.h # Common source files -AM_SOURCES = space.c runner.c queue.c task.c cell.c engine.c \ - serial_io.c timers.c debug.c scheduler.c proxy.c parallel_io.c \ +AM_SOURCES = space.c runner.c queue.c task.c cell.c engine.c engine_maketasks.c \ + engine_marktasks.c serial_io.c timers.c debug.c scheduler.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 \ @@ -61,13 +62,14 @@ AM_SOURCES = space.c runner.c queue.c task.c cell.c engine.c \ part_type.c xmf.c gravity_properties.c gravity.c \ collectgroup.c hydro_space.c equation_of_state.c \ chemistry.c cosmology.c restart.c mesh_gravity.c velociraptor_interface.c \ - outputlist.c fof.c + outputlist.c velociraptor_dummy.c logger_io.c fof.c # Include files for distribution, not installation. nobase_noinst_HEADERS = align.h approx_math.h atomic.h barrier.h cycle.h error.h inline.h kernel_hydro.h kernel_gravity.h \ gravity_iact.h kernel_long_gravity.h vector.h cache.h runner_doiact.h runner_doiact_vec.h runner_doiact_grav.h \ runner_doiact_nosort.h runner_doiact_stars.h units.h intrinsics.h minmax.h kick.h timestep.h drift.h \ adiabatic_index.h io_properties.h dimension.h part_type.h periodic.h memswap.h dump.h logger.h sign.h \ + logger_io.h \ gravity.h gravity_io.h gravity_cache.h \ gravity/Default/gravity.h gravity/Default/gravity_iact.h gravity/Default/gravity_io.h \ gravity/Default/gravity_debug.h gravity/Default/gravity_part.h \ @@ -133,6 +135,8 @@ nobase_noinst_HEADERS = align.h approx_math.h atomic.h barrier.h cycle.h error.h potential/sine_wave/potential.h \ cooling/none/cooling.h cooling/none/cooling_struct.h \ cooling/none/cooling_io.h \ + cooling/Compton/cooling.h cooling/Compton/cooling_struct.h \ + cooling/Compton/cooling_io.h \ cooling/const_du/cooling.h cooling/const_du/cooling_struct.h \ cooling/const_du/cooling_io.h \ cooling/const_lambda/cooling.h cooling/const_lambda/cooling_struct.h \ diff --git a/src/active.h b/src/active.h index 5b8c2684822ebbc1d1c86b6ebb0d7d6a869959a4..a3d2d5ad90c93b06bbd4853a2633d087304ee570 100644 --- a/src/active.h +++ b/src/active.h @@ -39,15 +39,16 @@ __attribute__((always_inline)) INLINE static int cell_are_part_drifted( const struct cell *c, const struct engine *e) { #ifdef SWIFT_DEBUG_CHECKS - if (c->ti_old_part > e->ti_current) + if (c->hydro.ti_old_part > e->ti_current) error( - "Cell has been drifted too far forward in time! c->ti_old=%lld (t=%e) " + "Cell has been drifted too far forward in time! c->ti_old_part=%lld " + "(t=%e) " "and e->ti_current=%lld (t=%e, a=%e)", - c->ti_old_part, c->ti_old_part * e->time_base, e->ti_current, - e->ti_current * e->time_base, e->cosmology->a); + c->hydro.ti_old_part, c->hydro.ti_old_part * e->time_base, + e->ti_current, e->ti_current * e->time_base, e->cosmology->a); #endif - return (c->ti_old_part == e->ti_current); + return (c->hydro.ti_old_part == e->ti_current); } /** @@ -62,15 +63,15 @@ __attribute__((always_inline)) INLINE static int cell_are_gpart_drifted( const struct cell *c, const struct engine *e) { #ifdef SWIFT_DEBUG_CHECKS - if (c->ti_old_gpart > e->ti_current) + if (c->grav.ti_old_part > e->ti_current) error( "Cell has been drifted too far forward in time! c->ti_old=%lld (t=%e) " "and e->ti_current=%lld (t=%e)", - c->ti_old_gpart, c->ti_old_gpart * e->time_base, e->ti_current, + c->grav.ti_old_part, c->grav.ti_old_part * e->time_base, e->ti_current, e->ti_current * e->time_base); #endif - return (c->ti_old_gpart == e->ti_current); + return (c->grav.ti_old_part == e->ti_current); } /* Are cells / particles active for regular tasks ? */ @@ -86,15 +87,15 @@ __attribute__((always_inline)) INLINE static int cell_is_active_hydro( const struct cell *c, const struct engine *e) { #ifdef SWIFT_DEBUG_CHECKS - if (c->ti_hydro_end_min < e->ti_current) + if (c->hydro.ti_end_min < e->ti_current) error( "cell in an impossible time-zone! c->ti_end_min=%lld (t=%e) and " "e->ti_current=%lld (t=%e, a=%e)", - c->ti_hydro_end_min, c->ti_hydro_end_min * e->time_base, e->ti_current, + c->hydro.ti_end_min, c->hydro.ti_end_min * e->time_base, e->ti_current, e->ti_current * e->time_base, e->cosmology->a); #endif - return (c->ti_hydro_end_min == e->ti_current); + return (c->hydro.ti_end_min == e->ti_current); } /** @@ -108,14 +109,14 @@ __attribute__((always_inline)) INLINE static int cell_is_all_active_hydro( const struct cell *c, const struct engine *e) { #ifdef SWIFT_DEBUG_CHECKS - if (c->ti_hydro_end_max < e->ti_current) + if (c->hydro.ti_end_max < e->ti_current) error( "cell in an impossible time-zone! c->ti_end_max=%lld " "e->ti_current=%lld", - c->ti_hydro_end_max, e->ti_current); + c->hydro.ti_end_max, e->ti_current); #endif - return (c->ti_hydro_end_max == e->ti_current); + return (c->hydro.ti_end_max == e->ti_current); } /** @@ -129,15 +130,15 @@ __attribute__((always_inline)) INLINE static int cell_is_active_gravity( const struct cell *c, const struct engine *e) { #ifdef SWIFT_DEBUG_CHECKS - if (c->ti_gravity_end_min < e->ti_current) + if (c->grav.ti_end_min < e->ti_current) error( "cell in an impossible time-zone! c->ti_end_min=%lld (t=%e) and " "e->ti_current=%lld (t=%e, a=%e)", - c->ti_gravity_end_min, c->ti_gravity_end_min * e->time_base, - e->ti_current, e->ti_current * e->time_base, e->cosmology->a); + c->grav.ti_end_min, c->grav.ti_end_min * e->time_base, e->ti_current, + e->ti_current * e->time_base, e->cosmology->a); #endif - return (c->ti_gravity_end_min == e->ti_current); + return (c->grav.ti_end_min == e->ti_current); } /** @@ -150,7 +151,7 @@ __attribute__((always_inline)) INLINE static int cell_is_active_gravity( __attribute__((always_inline)) INLINE static int cell_is_active_gravity_mm( const struct cell *c, const struct engine *e) { - return (c->ti_gravity_end_min == e->ti_current); + return (c->grav.ti_end_min == e->ti_current); } /** @@ -164,14 +165,14 @@ __attribute__((always_inline)) INLINE static int cell_is_all_active_gravity( const struct cell *c, const struct engine *e) { #ifdef SWIFT_DEBUG_CHECKS - if (c->ti_gravity_end_max < e->ti_current) + if (c->grav.ti_end_max < e->ti_current) error( "cell in an impossible time-zone! c->ti_end_max=%lld " "e->ti_current=%lld", - c->ti_gravity_end_max, e->ti_current); + c->grav.ti_end_max, e->ti_current); #endif - return (c->ti_gravity_end_max == e->ti_current); + return (c->grav.ti_end_max == e->ti_current); } /** @@ -277,6 +278,42 @@ __attribute__((always_inline)) INLINE static int spart_is_active( return (spart_bin <= max_active_bin); } +/** + * @brief Has this particle been inhibited? + * + * @param p The #part. + * @param e The #engine containing information about the current time. + * @return 1 if the #part is inhibited, 0 otherwise. + */ +__attribute__((always_inline)) INLINE static int part_is_inhibited( + const struct part *p, const struct engine *e) { + return p->time_bin == time_bin_inhibited; +} + +/** + * @brief Has this gravity particle been inhibited? + * + * @param gp The #gpart. + * @param e The #engine containing information about the current time. + * @return 1 if the #part is inhibited, 0 otherwise. + */ +__attribute__((always_inline)) INLINE static int gpart_is_inhibited( + const struct gpart *gp, const struct engine *e) { + return gp->time_bin == time_bin_inhibited; +} + +/** + * @brief Has this star particle been inhibited? + * + * @param sp The #spart. + * @param e The #engine containing information about the current time. + * @return 1 if the #part is inhibited, 0 otherwise. + */ +__attribute__((always_inline)) INLINE static int spart_is_inhibited( + const struct spart *sp, const struct engine *e) { + return sp->time_bin == time_bin_inhibited; +} + /* Are cells / particles active for kick1 tasks ? */ /** @@ -290,15 +327,15 @@ __attribute__((always_inline)) INLINE static int cell_is_starting_hydro( const struct cell *c, const struct engine *e) { #ifdef SWIFT_DEBUG_CHECKS - if (c->ti_hydro_beg_max > e->ti_current) + if (c->hydro.ti_beg_max > e->ti_current) error( "cell in an impossible time-zone! c->ti_beg_max=%lld (t=%e) and " "e->ti_current=%lld (t=%e, a=%e)", - c->ti_hydro_beg_max, c->ti_hydro_beg_max * e->time_base, e->ti_current, + c->hydro.ti_beg_max, c->hydro.ti_beg_max * e->time_base, e->ti_current, e->ti_current * e->time_base, e->cosmology->a); #endif - return (c->ti_hydro_beg_max == e->ti_current); + return (c->hydro.ti_beg_max == e->ti_current); } /** @@ -312,15 +349,15 @@ __attribute__((always_inline)) INLINE static int cell_is_starting_gravity( const struct cell *c, const struct engine *e) { #ifdef SWIFT_DEBUG_CHECKS - if (c->ti_gravity_beg_max > e->ti_current) + if (c->grav.ti_beg_max > e->ti_current) error( "cell in an impossible time-zone! c->ti_beg_max=%lld (t=%e) and " "e->ti_current=%lld (t=%e, a=%e)", - c->ti_gravity_beg_max, c->ti_gravity_beg_max * e->time_base, - e->ti_current, e->ti_current * e->time_base, e->cosmology->a); + c->grav.ti_beg_max, c->grav.ti_beg_max * e->time_base, e->ti_current, + e->ti_current * e->time_base, e->cosmology->a); #endif - return (c->ti_gravity_beg_max == e->ti_current); + return (c->grav.ti_beg_max == e->ti_current); } /** @@ -406,4 +443,5 @@ __attribute__((always_inline)) INLINE static int spart_is_starting( return (spart_bin <= max_active_bin); } + #endif /* SWIFT_ACTIVE_H */ diff --git a/src/cache.h b/src/cache.h index c41e11c34246ef0de93bb1ae7500277aab555b9e..5dd8164b1dc80795a8593cc2af42c2c9e7e68885 100644 --- a/src/cache.h +++ b/src/cache.h @@ -197,12 +197,12 @@ __attribute__((always_inline)) INLINE void cache_read_particles( swift_declare_aligned_ptr(float, vy, ci_cache->vy, SWIFT_CACHE_ALIGNMENT); swift_declare_aligned_ptr(float, vz, ci_cache->vz, SWIFT_CACHE_ALIGNMENT); - const struct part *restrict parts = ci->parts; + const struct part *restrict parts = ci->hydro.parts; const double loc[3] = {ci->loc[0], ci->loc[1], ci->loc[2]}; /* Shift the particles positions to a local frame so single precision can be * used instead of double precision. */ - for (int i = 0; i < ci->count; i++) { + for (int i = 0; i < ci->hydro.count; i++) { x[i] = (float)(parts[i].x[0] - loc[0]); y[i] = (float)(parts[i].x[1] - loc[1]); z[i] = (float)(parts[i].x[2] - loc[2]); @@ -248,7 +248,7 @@ __attribute__((always_inline)) INLINE void cache_read_particles_subset( swift_declare_aligned_ptr(float, vy, ci_cache->vy, SWIFT_CACHE_ALIGNMENT); swift_declare_aligned_ptr(float, vz, ci_cache->vz, SWIFT_CACHE_ALIGNMENT); - const struct part *restrict parts = ci->parts; + const struct part *restrict parts = ci->hydro.parts; /* The cell is on the right so read the particles * into the cache from the start of the cell. */ @@ -258,7 +258,7 @@ __attribute__((always_inline)) INLINE void cache_read_particles_subset( const int pad = VEC_SIZE - rem; /* Increase last_pi if there are particles in the cell left to read. */ - if (*last_pi + pad < ci->count) *last_pi += pad; + if (*last_pi + pad < ci->hydro.count) *last_pi += pad; } /* Shift the particles positions to a local frame so single precision can be @@ -278,11 +278,11 @@ __attribute__((always_inline)) INLINE void cache_read_particles_subset( /* Pad cache with fake particles that exist outside the cell so will not * interact. We use values of the same magnitude (but negative!) as the real * particles to avoid overflow problems. */ - const double max_dx = ci->dx_max_part; + const double max_dx = ci->hydro.dx_max_part; const float pos_padded[3] = {-(2. * ci->width[0] + max_dx), -(2. * ci->width[1] + max_dx), -(2. * ci->width[2] + max_dx)}; - const float h_padded = ci->parts[0].h; + const float h_padded = ci->hydro.parts[0].h; for (int i = *last_pi; i < *last_pi + VEC_SIZE; i++) { x[i] = pos_padded[0]; @@ -299,7 +299,7 @@ __attribute__((always_inline)) INLINE void cache_read_particles_subset( /* The cell is on the left so read the particles * into the cache from the end of the cell. */ else { - const int rem = (ci->count - *first_pi) % VEC_SIZE; + const int rem = (ci->hydro.count - *first_pi) % VEC_SIZE; if (rem != 0) { const int pad = VEC_SIZE - rem; @@ -307,7 +307,7 @@ __attribute__((always_inline)) INLINE void cache_read_particles_subset( if (*first_pi - pad >= 0) *first_pi -= pad; } - const int ci_cache_count = ci->count - *first_pi; + const int ci_cache_count = ci->hydro.count - *first_pi; /* Shift the particles positions to a local frame so single precision can be * used instead of double precision. */ @@ -326,14 +326,14 @@ __attribute__((always_inline)) INLINE void cache_read_particles_subset( /* Pad cache with fake particles that exist outside the cell so will not * interact. We use values of the same magnitude (but negative!) as the real * particles to avoid overflow problems. */ - const double max_dx = ci->dx_max_part; + const double max_dx = ci->hydro.dx_max_part; const float pos_padded[3] = {-(2. * ci->width[0] + max_dx), -(2. * ci->width[1] + max_dx), -(2. * ci->width[2] + max_dx)}; - const float h_padded = ci->parts[0].h; + const float h_padded = ci->hydro.parts[0].h; - for (int i = ci->count - *first_pi; i < ci->count - *first_pi + VEC_SIZE; - i++) { + for (int i = ci->hydro.count - *first_pi; + i < ci->hydro.count - *first_pi + VEC_SIZE; i++) { x[i] = pos_padded[0]; y[i] = pos_padded[1]; z[i] = pos_padded[2]; @@ -382,12 +382,12 @@ __attribute__((always_inline)) INLINE void cache_read_force_particles( swift_declare_aligned_ptr(float, soundspeed, ci_cache->soundspeed, SWIFT_CACHE_ALIGNMENT); - const struct part *restrict parts = ci->parts; + const struct part *restrict parts = ci->hydro.parts; const double loc[3] = {ci->loc[0], ci->loc[1], ci->loc[2]}; /* Shift the particles positions to a local frame so single precision can be * used instead of double precision. */ - for (int i = 0; i < ci->count; i++) { + for (int i = 0; i < ci->hydro.count; i++) { x[i] = (float)(parts[i].x[0] - loc[0]); y[i] = (float)(parts[i].x[1] - loc[1]); z[i] = (float)(parts[i].x[2] - loc[2]); @@ -433,7 +433,7 @@ __attribute__((always_inline)) INLINE void cache_read_two_partial_cells_sorted( * cache. */ /* Is the number of particles to read a multiple of the vector size? */ - int rem = (ci->count - *first_pi) % VEC_SIZE; + int rem = (ci->hydro.count - *first_pi) % VEC_SIZE; if (rem != 0) { int pad = VEC_SIZE - rem; @@ -446,14 +446,14 @@ __attribute__((always_inline)) INLINE void cache_read_two_partial_cells_sorted( int pad = VEC_SIZE - rem; /* Increase last_pj if there are particles in the cell left to read. */ - if (*last_pj + pad < cj->count) *last_pj += pad; + if (*last_pj + pad < cj->hydro.count) *last_pj += pad; } /* Get some local pointers */ const int first_pi_align = *first_pi; const int last_pj_align = *last_pj; - const struct part *restrict parts_i = ci->parts; - const struct part *restrict parts_j = cj->parts; + const struct part *restrict parts_i = ci->hydro.parts; + const struct part *restrict parts_j = cj->hydro.parts; /* Shift particles to the local frame and account for boundary conditions.*/ const double total_ci_shift[3] = { @@ -471,7 +471,7 @@ __attribute__((always_inline)) INLINE void cache_read_two_partial_cells_sorted( swift_declare_aligned_ptr(float, vy, ci_cache->vy, SWIFT_CACHE_ALIGNMENT); swift_declare_aligned_ptr(float, vz, ci_cache->vz, SWIFT_CACHE_ALIGNMENT); - int ci_cache_count = ci->count - first_pi_align; + int ci_cache_count = ci->hydro.count - first_pi_align; /* Shift the particles positions to a local frame (ci frame) so single * precision can be used instead of double precision. */ @@ -491,11 +491,14 @@ __attribute__((always_inline)) INLINE void cache_read_two_partial_cells_sorted( #ifdef SWIFT_DEBUG_CHECKS const float shift_threshold_x = - 2. * ci->width[0] + 2. * max(ci->dx_max_part, cj->dx_max_part); + 2. * ci->width[0] + + 2. * max(ci->hydro.dx_max_part, cj->hydro.dx_max_part); const float shift_threshold_y = - 2. * ci->width[1] + 2. * max(ci->dx_max_part, cj->dx_max_part); + 2. * ci->width[1] + + 2. * max(ci->hydro.dx_max_part, cj->hydro.dx_max_part); const float shift_threshold_z = - 2. * ci->width[2] + 2. * max(ci->dx_max_part, cj->dx_max_part); + 2. * ci->width[2] + + 2. * max(ci->hydro.dx_max_part, cj->hydro.dx_max_part); /* Make sure that particle positions have been shifted correctly. */ for (int i = 0; i < ci_cache_count; i++) { @@ -529,14 +532,14 @@ __attribute__((always_inline)) INLINE void cache_read_two_partial_cells_sorted( /* Pad cache with fake particles that exist outside the cell so will not * interact. We use values of the same magnitude (but negative!) as the real * particles to avoid overflow problems. */ - const double max_dx = max(ci->dx_max_part, cj->dx_max_part); + const double max_dx = max(ci->hydro.dx_max_part, cj->hydro.dx_max_part); const float pos_padded[3] = {-(2. * ci->width[0] + max_dx), -(2. * ci->width[1] + max_dx), -(2. * ci->width[2] + max_dx)}; - const float h_padded = ci->parts[0].h; + const float h_padded = ci->hydro.parts[0].h; - for (int i = ci->count - first_pi_align; - i < ci->count - first_pi_align + VEC_SIZE; i++) { + for (int i = ci->hydro.count - first_pi_align; + i < ci->hydro.count - first_pi_align + VEC_SIZE; i++) { x[i] = pos_padded[0]; y[i] = pos_padded[1]; z[i] = pos_padded[2]; @@ -609,7 +612,7 @@ __attribute__((always_inline)) INLINE void cache_read_two_partial_cells_sorted( const float pos_padded_j[3] = {-(2. * cj->width[0] + max_dx), -(2. * cj->width[1] + max_dx), -(2. * cj->width[2] + max_dx)}; - const float h_padded_j = cj->parts[0].h; + const float h_padded_j = cj->hydro.parts[0].h; for (int i = last_pj_align + 1; i < last_pj_align + 1 + VEC_SIZE; i++) { xj[i] = pos_padded_j[0]; @@ -650,7 +653,7 @@ cache_read_two_partial_cells_sorted_force( * cache. */ /* Is the number of particles to read a multiple of the vector size? */ - int rem = (ci->count - *first_pi) % VEC_SIZE; + int rem = (ci->hydro.count - *first_pi) % VEC_SIZE; if (rem != 0) { int pad = VEC_SIZE - rem; @@ -663,14 +666,14 @@ cache_read_two_partial_cells_sorted_force( int pad = VEC_SIZE - rem; /* Increase last_pj if there are particles in the cell left to read. */ - if (*last_pj + pad < cj->count) *last_pj += pad; + if (*last_pj + pad < cj->hydro.count) *last_pj += pad; } /* Get some local pointers */ const int first_pi_align = *first_pi; const int last_pj_align = *last_pj; - const struct part *restrict parts_i = ci->parts; - const struct part *restrict parts_j = cj->parts; + const struct part *restrict parts_i = ci->hydro.parts; + const struct part *restrict parts_j = cj->hydro.parts; /* Shift particles to the local frame and account for boundary conditions.*/ const double total_ci_shift[3] = { @@ -697,7 +700,7 @@ cache_read_two_partial_cells_sorted_force( swift_declare_aligned_ptr(float, soundspeed, ci_cache->soundspeed, SWIFT_CACHE_ALIGNMENT); - int ci_cache_count = ci->count - first_pi_align; + int ci_cache_count = ci->hydro.count - first_pi_align; /* Shift the particles positions to a local frame (ci frame) so single * precision can be used instead of double precision. */ for (int i = 0; i < ci_cache_count; i++) { @@ -723,14 +726,14 @@ cache_read_two_partial_cells_sorted_force( /* Pad cache with fake particles that exist outside the cell so will not * interact. We use values of the same magnitude (but negative!) as the real * particles to avoid overflow problems. */ - const double max_dx = max(ci->dx_max_part, cj->dx_max_part); + const double max_dx = max(ci->hydro.dx_max_part, cj->hydro.dx_max_part); const float pos_padded[3] = {-(2. * ci->width[0] + max_dx), -(2. * ci->width[1] + max_dx), -(2. * ci->width[2] + max_dx)}; - const float h_padded = ci->parts[0].h; + const float h_padded = ci->hydro.parts[0].h; - for (int i = ci->count - first_pi_align; - i < ci->count - first_pi_align + VEC_SIZE; i++) { + for (int i = ci->hydro.count - first_pi_align; + i < ci->hydro.count - first_pi_align + VEC_SIZE; i++) { x[i] = pos_padded[0]; y[i] = pos_padded[1]; z[i] = pos_padded[2]; @@ -791,7 +794,7 @@ cache_read_two_partial_cells_sorted_force( const float pos_padded_j[3] = {-(2. * cj->width[0] + max_dx), -(2. * cj->width[1] + max_dx), -(2. * cj->width[2] + max_dx)}; - const float h_padded_j = cj->parts[0].h; + const float h_padded_j = cj->hydro.parts[0].h; for (int i = last_pj_align + 1; i < last_pj_align + 1 + VEC_SIZE; i++) { xj[i] = pos_padded_j[0]; @@ -831,6 +834,7 @@ static INLINE void cache_clean(struct cache *c) { free(c->balsara); free(c->soundspeed); } + c->count = 0; } #endif /* WITH_VECTORIZATION */ diff --git a/src/cell.c b/src/cell.c index 8ecaf74711434dbbfa2b0c39b8a90bdf4ccc3155..37b7be42f3aa04d79496d2913d30654af93ea45e 100644 --- a/src/cell.c +++ b/src/cell.c @@ -97,7 +97,7 @@ int cell_getsize(struct cell *c) { */ int cell_link_parts(struct cell *c, struct part *parts) { - c->parts = parts; + c->hydro.parts = parts; /* Fill the progeny recursively, depth-first. */ if (c->split) { @@ -109,7 +109,7 @@ int cell_link_parts(struct cell *c, struct part *parts) { } /* Return the total number of linked particles. */ - return c->count; + return c->hydro.count; } /** @@ -122,7 +122,7 @@ int cell_link_parts(struct cell *c, struct part *parts) { */ int cell_link_gparts(struct cell *c, struct gpart *gparts) { - c->gparts = gparts; + c->grav.parts = gparts; /* Fill the progeny recursively, depth-first. */ if (c->split) { @@ -134,7 +134,7 @@ int cell_link_gparts(struct cell *c, struct gpart *gparts) { } /* Return the total number of linked particles. */ - return c->gcount; + return c->grav.count; } /** @@ -147,7 +147,7 @@ int cell_link_gparts(struct cell *c, struct gpart *gparts) { */ int cell_link_sparts(struct cell *c, struct spart *sparts) { - c->sparts = sparts; + c->stars.parts = sparts; /* Fill the progeny recursively, depth-first. */ if (c->split) { @@ -159,7 +159,7 @@ int cell_link_sparts(struct cell *c, struct spart *sparts) { } /* Return the total number of linked particles. */ - return c->scount; + return c->stars.count; } /** @@ -179,31 +179,31 @@ int cell_pack(struct cell *restrict c, struct pcell *restrict pc, #ifdef WITH_MPI /* Start by packing the data of the current cell. */ - pc->h_max = c->h_max; - pc->ti_hydro_end_min = c->ti_hydro_end_min; - pc->ti_hydro_end_max = c->ti_hydro_end_max; - pc->ti_gravity_end_min = c->ti_gravity_end_min; - pc->ti_gravity_end_max = c->ti_gravity_end_max; - pc->ti_old_part = c->ti_old_part; - pc->ti_old_gpart = c->ti_old_gpart; - pc->ti_old_multipole = c->ti_old_multipole; - pc->count = c->count; - pc->gcount = c->gcount; - pc->scount = c->scount; + pc->hydro.h_max = c->hydro.h_max; + pc->hydro.ti_end_min = c->hydro.ti_end_min; + pc->hydro.ti_end_max = c->hydro.ti_end_max; + pc->grav.ti_end_min = c->grav.ti_end_min; + pc->grav.ti_end_max = c->grav.ti_end_max; + pc->hydro.ti_old_part = c->hydro.ti_old_part; + pc->grav.ti_old_part = c->grav.ti_old_part; + pc->grav.ti_old_multipole = c->grav.ti_old_multipole; + pc->hydro.count = c->hydro.count; + pc->grav.count = c->grav.count; + pc->stars.count = c->stars.count; /* Copy the Multipole related information */ if (with_gravity) { - const struct gravity_tensors *mp = c->multipole; + const struct gravity_tensors *mp = c->grav.multipole; - pc->m_pole = mp->m_pole; - pc->CoM[0] = mp->CoM[0]; - pc->CoM[1] = mp->CoM[1]; - pc->CoM[2] = mp->CoM[2]; - pc->CoM_rebuild[0] = mp->CoM_rebuild[0]; - pc->CoM_rebuild[1] = mp->CoM_rebuild[1]; - pc->CoM_rebuild[2] = mp->CoM_rebuild[2]; - pc->r_max = mp->r_max; - pc->r_max_rebuild = mp->r_max_rebuild; + pc->grav.m_pole = mp->m_pole; + pc->grav.CoM[0] = mp->CoM[0]; + pc->grav.CoM[1] = mp->CoM[1]; + pc->grav.CoM[2] = mp->CoM[2]; + pc->grav.CoM_rebuild[0] = mp->CoM_rebuild[0]; + pc->grav.CoM_rebuild[1] = mp->CoM_rebuild[1]; + pc->grav.CoM_rebuild[2] = mp->CoM_rebuild[2]; + pc->grav.r_max = mp->r_max; + pc->grav.r_max_rebuild = mp->r_max_rebuild; } #ifdef SWIFT_DEBUG_CHECKS @@ -221,7 +221,7 @@ int cell_pack(struct cell *restrict c, struct pcell *restrict pc, } /* Return the number of packed cells used. */ - c->pcell_size = count; + c->mpi.pcell_size = count; return count; #else @@ -243,7 +243,7 @@ int cell_pack_tags(const struct cell *c, int *tags) { #ifdef WITH_MPI /* Start by packing the data of the current cell. */ - tags[0] = c->tag; + tags[0] = c->mpi.tag; /* Fill in the progeny, depth-first recursion. */ int count = 1; @@ -252,7 +252,7 @@ int cell_pack_tags(const struct cell *c, int *tags) { count += cell_pack_tags(c->progeny[k], &tags[count]); #ifdef SWIFT_DEBUG_CHECKS - if (c->pcell_size != count) error("Inconsistent tag and pcell count!"); + if (c->mpi.pcell_size != count) error("Inconsistent tag and pcell count!"); #endif // SWIFT_DEBUG_CHECKS /* Return the number of packed tags used. */ @@ -281,17 +281,17 @@ int cell_unpack(struct pcell *restrict pc, struct cell *restrict c, #ifdef WITH_MPI /* Unpack the current pcell. */ - c->h_max = pc->h_max; - c->ti_hydro_end_min = pc->ti_hydro_end_min; - c->ti_hydro_end_max = pc->ti_hydro_end_max; - c->ti_gravity_end_min = pc->ti_gravity_end_min; - c->ti_gravity_end_max = pc->ti_gravity_end_max; - c->ti_old_part = pc->ti_old_part; - c->ti_old_gpart = pc->ti_old_gpart; - c->ti_old_multipole = pc->ti_old_multipole; - c->count = pc->count; - c->gcount = pc->gcount; - c->scount = pc->scount; + c->hydro.h_max = pc->hydro.h_max; + c->hydro.ti_end_min = pc->hydro.ti_end_min; + c->hydro.ti_end_max = pc->hydro.ti_end_max; + c->grav.ti_end_min = pc->grav.ti_end_min; + c->grav.ti_end_max = pc->grav.ti_end_max; + c->hydro.ti_old_part = pc->hydro.ti_old_part; + c->grav.ti_old_part = pc->grav.ti_old_part; + c->grav.ti_old_multipole = pc->grav.ti_old_multipole; + c->hydro.count = pc->hydro.count; + c->grav.count = pc->grav.count; + c->stars.count = pc->stars.count; #ifdef SWIFT_DEBUG_CHECKS c->cellID = pc->cellID; #endif @@ -299,30 +299,31 @@ int cell_unpack(struct pcell *restrict pc, struct cell *restrict c, /* Copy the Multipole related information */ if (with_gravity) { - struct gravity_tensors *mp = c->multipole; + struct gravity_tensors *mp = c->grav.multipole; - mp->m_pole = pc->m_pole; - mp->CoM[0] = pc->CoM[0]; - mp->CoM[1] = pc->CoM[1]; - mp->CoM[2] = pc->CoM[2]; - mp->CoM_rebuild[0] = pc->CoM_rebuild[0]; - mp->CoM_rebuild[1] = pc->CoM_rebuild[1]; - mp->CoM_rebuild[2] = pc->CoM_rebuild[2]; - mp->r_max = pc->r_max; - mp->r_max_rebuild = pc->r_max_rebuild; + mp->m_pole = pc->grav.m_pole; + mp->CoM[0] = pc->grav.CoM[0]; + mp->CoM[1] = pc->grav.CoM[1]; + mp->CoM[2] = pc->grav.CoM[2]; + mp->CoM_rebuild[0] = pc->grav.CoM_rebuild[0]; + mp->CoM_rebuild[1] = pc->grav.CoM_rebuild[1]; + mp->CoM_rebuild[2] = pc->grav.CoM_rebuild[2]; + mp->r_max = pc->grav.r_max; + mp->r_max_rebuild = pc->grav.r_max_rebuild; } /* Number of new cells created. */ int count = 1; /* Fill the progeny recursively, depth-first. */ + c->split = 0; for (int k = 0; k < 8; k++) if (pc->progeny[k] >= 0) { struct cell *temp; space_getcells(s, 1, &temp); - temp->count = 0; - temp->gcount = 0; - temp->scount = 0; + temp->hydro.count = 0; + temp->grav.count = 0; + temp->stars.count = 0; temp->loc[0] = c->loc[0]; temp->loc[1] = c->loc[1]; temp->loc[2] = c->loc[2]; @@ -335,8 +336,9 @@ int cell_unpack(struct pcell *restrict pc, struct cell *restrict c, if (k & 1) temp->loc[2] += temp->width[2]; temp->depth = c->depth + 1; temp->split = 0; - temp->dx_max_part = 0.f; - temp->dx_max_sort = 0.f; + temp->hydro.dx_max_part = 0.f; + temp->hydro.dx_max_sort = 0.f; + temp->stars.dx_max_part = 0.f; temp->nodeID = c->nodeID; temp->parent = c; c->progeny[k] = temp; @@ -345,7 +347,7 @@ int cell_unpack(struct pcell *restrict pc, struct cell *restrict c, } /* Return the total number of unpacked cells. */ - c->pcell_size = count; + c->mpi.pcell_size = count; return count; #else @@ -367,7 +369,7 @@ int cell_unpack_tags(const int *tags, struct cell *restrict c) { #ifdef WITH_MPI /* Unpack the current pcell. */ - c->tag = tags[0]; + c->mpi.tag = tags[0]; /* Number of new cells created. */ int count = 1; @@ -379,7 +381,7 @@ int cell_unpack_tags(const int *tags, struct cell *restrict c) { } #ifdef SWIFT_DEBUG_CHECKS - if (c->pcell_size != count) error("Inconsistent tag and pcell count!"); + if (c->mpi.pcell_size != count) error("Inconsistent tag and pcell count!"); #endif // SWIFT_DEBUG_CHECKS /* Return the total number of unpacked tags. */ @@ -405,11 +407,12 @@ int cell_pack_end_step(struct cell *restrict c, #ifdef WITH_MPI /* Pack this cell's data. */ - pcells[0].ti_hydro_end_min = c->ti_hydro_end_min; - pcells[0].ti_hydro_end_max = c->ti_hydro_end_max; - pcells[0].ti_gravity_end_min = c->ti_gravity_end_min; - pcells[0].ti_gravity_end_max = c->ti_gravity_end_max; - pcells[0].dx_max_part = c->dx_max_part; + pcells[0].hydro.ti_end_min = c->hydro.ti_end_min; + pcells[0].hydro.ti_end_max = c->hydro.ti_end_max; + pcells[0].grav.ti_end_min = c->grav.ti_end_min; + pcells[0].grav.ti_end_max = c->grav.ti_end_max; + pcells[0].hydro.dx_max_part = c->hydro.dx_max_part; + pcells[0].stars.dx_max_part = c->stars.dx_max_part; /* Fill in the progeny, depth-first recursion. */ int count = 1; @@ -441,11 +444,12 @@ int cell_unpack_end_step(struct cell *restrict c, #ifdef WITH_MPI /* Unpack this cell's data. */ - c->ti_hydro_end_min = pcells[0].ti_hydro_end_min; - c->ti_hydro_end_max = pcells[0].ti_hydro_end_max; - c->ti_gravity_end_min = pcells[0].ti_gravity_end_min; - c->ti_gravity_end_max = pcells[0].ti_gravity_end_max; - c->dx_max_part = pcells[0].dx_max_part; + c->hydro.ti_end_min = pcells[0].hydro.ti_end_min; + c->hydro.ti_end_max = pcells[0].hydro.ti_end_max; + c->grav.ti_end_min = pcells[0].grav.ti_end_min; + c->grav.ti_end_max = pcells[0].grav.ti_end_max; + c->hydro.dx_max_part = pcells[0].hydro.dx_max_part; + c->stars.dx_max_part = pcells[0].stars.dx_max_part; /* Fill in the progeny, depth-first recursion. */ int count = 1; @@ -478,7 +482,7 @@ int cell_pack_multipoles(struct cell *restrict c, #ifdef WITH_MPI /* Pack this cell's data. */ - pcells[0] = *c->multipole; + pcells[0] = *c->grav.multipole; /* Fill in the progeny, depth-first recursion. */ int count = 1; @@ -510,7 +514,7 @@ int cell_unpack_multipoles(struct cell *restrict c, #ifdef WITH_MPI /* Unpack this cell's data. */ - *c->multipole = pcells[0]; + *c->grav.multipole = pcells[0]; /* Fill in the progeny, depth-first recursion. */ int count = 1; @@ -539,16 +543,16 @@ int cell_locktree(struct cell *c) { TIMER_TIC /* First of all, try to lock this cell. */ - if (c->hold || lock_trylock(&c->lock) != 0) { + if (c->hydro.hold || lock_trylock(&c->hydro.lock) != 0) { TIMER_TOC(timer_locktree); return 1; } /* Did somebody hold this cell in the meantime? */ - if (c->hold) { + if (c->hydro.hold) { /* Unlock this cell. */ - if (lock_unlock(&c->lock) != 0) error("Failed to unlock cell."); + if (lock_unlock(&c->hydro.lock) != 0) error("Failed to unlock cell."); /* Admit defeat. */ TIMER_TOC(timer_locktree); @@ -560,13 +564,13 @@ int cell_locktree(struct cell *c) { for (finger = c->parent; finger != NULL; finger = finger->parent) { /* Lock this cell. */ - if (lock_trylock(&finger->lock) != 0) break; + if (lock_trylock(&finger->hydro.lock) != 0) break; /* Increment the hold. */ - atomic_inc(&finger->hold); + atomic_inc(&finger->hydro.hold); /* Unlock the cell. */ - if (lock_unlock(&finger->lock) != 0) error("Failed to unlock cell."); + if (lock_unlock(&finger->hydro.lock) != 0) error("Failed to unlock cell."); } /* If we reached the top of the tree, we're done. */ @@ -581,10 +585,10 @@ int cell_locktree(struct cell *c) { /* Undo the holds up to finger. */ for (struct cell *finger2 = c->parent; finger2 != finger; finger2 = finger2->parent) - atomic_dec(&finger2->hold); + atomic_dec(&finger2->hydro.hold); /* Unlock this cell. */ - if (lock_unlock(&c->lock) != 0) error("Failed to unlock cell."); + if (lock_unlock(&c->hydro.lock) != 0) error("Failed to unlock cell."); /* Admit defeat. */ TIMER_TOC(timer_locktree); @@ -603,16 +607,16 @@ int cell_glocktree(struct cell *c) { TIMER_TIC /* First of all, try to lock this cell. */ - if (c->ghold || lock_trylock(&c->glock) != 0) { + if (c->grav.phold || lock_trylock(&c->grav.plock) != 0) { TIMER_TOC(timer_locktree); return 1; } /* Did somebody hold this cell in the meantime? */ - if (c->ghold) { + if (c->grav.phold) { /* Unlock this cell. */ - if (lock_unlock(&c->glock) != 0) error("Failed to unlock cell."); + if (lock_unlock(&c->grav.plock) != 0) error("Failed to unlock cell."); /* Admit defeat. */ TIMER_TOC(timer_locktree); @@ -624,13 +628,13 @@ int cell_glocktree(struct cell *c) { for (finger = c->parent; finger != NULL; finger = finger->parent) { /* Lock this cell. */ - if (lock_trylock(&finger->glock) != 0) break; + if (lock_trylock(&finger->grav.plock) != 0) break; /* Increment the hold. */ - atomic_inc(&finger->ghold); + atomic_inc(&finger->grav.phold); /* Unlock the cell. */ - if (lock_unlock(&finger->glock) != 0) error("Failed to unlock cell."); + if (lock_unlock(&finger->grav.plock) != 0) error("Failed to unlock cell."); } /* If we reached the top of the tree, we're done. */ @@ -645,10 +649,10 @@ int cell_glocktree(struct cell *c) { /* Undo the holds up to finger. */ for (struct cell *finger2 = c->parent; finger2 != finger; finger2 = finger2->parent) - atomic_dec(&finger2->ghold); + atomic_dec(&finger2->grav.phold); /* Unlock this cell. */ - if (lock_unlock(&c->glock) != 0) error("Failed to unlock cell."); + if (lock_unlock(&c->grav.plock) != 0) error("Failed to unlock cell."); /* Admit defeat. */ TIMER_TOC(timer_locktree); @@ -667,16 +671,16 @@ int cell_mlocktree(struct cell *c) { TIMER_TIC /* First of all, try to lock this cell. */ - if (c->mhold || lock_trylock(&c->mlock) != 0) { + if (c->grav.mhold || lock_trylock(&c->grav.mlock) != 0) { TIMER_TOC(timer_locktree); return 1; } /* Did somebody hold this cell in the meantime? */ - if (c->mhold) { + if (c->grav.mhold) { /* Unlock this cell. */ - if (lock_unlock(&c->mlock) != 0) error("Failed to unlock cell."); + if (lock_unlock(&c->grav.mlock) != 0) error("Failed to unlock cell."); /* Admit defeat. */ TIMER_TOC(timer_locktree); @@ -688,13 +692,13 @@ int cell_mlocktree(struct cell *c) { for (finger = c->parent; finger != NULL; finger = finger->parent) { /* Lock this cell. */ - if (lock_trylock(&finger->mlock) != 0) break; + if (lock_trylock(&finger->grav.mlock) != 0) break; /* Increment the hold. */ - atomic_inc(&finger->mhold); + atomic_inc(&finger->grav.mhold); /* Unlock the cell. */ - if (lock_unlock(&finger->mlock) != 0) error("Failed to unlock cell."); + if (lock_unlock(&finger->grav.mlock) != 0) error("Failed to unlock cell."); } /* If we reached the top of the tree, we're done. */ @@ -709,10 +713,10 @@ int cell_mlocktree(struct cell *c) { /* Undo the holds up to finger. */ for (struct cell *finger2 = c->parent; finger2 != finger; finger2 = finger2->parent) - atomic_dec(&finger2->mhold); + atomic_dec(&finger2->grav.mhold); /* Unlock this cell. */ - if (lock_unlock(&c->mlock) != 0) error("Failed to unlock cell."); + if (lock_unlock(&c->grav.mlock) != 0) error("Failed to unlock cell."); /* Admit defeat. */ TIMER_TOC(timer_locktree); @@ -731,16 +735,16 @@ int cell_slocktree(struct cell *c) { TIMER_TIC /* First of all, try to lock this cell. */ - if (c->shold || lock_trylock(&c->slock) != 0) { + if (c->stars.hold || lock_trylock(&c->stars.lock) != 0) { TIMER_TOC(timer_locktree); return 1; } /* Did somebody hold this cell in the meantime? */ - if (c->shold) { + if (c->stars.hold) { /* Unlock this cell. */ - if (lock_unlock(&c->slock) != 0) error("Failed to unlock cell."); + if (lock_unlock(&c->stars.lock) != 0) error("Failed to unlock cell."); /* Admit defeat. */ TIMER_TOC(timer_locktree); @@ -752,13 +756,13 @@ int cell_slocktree(struct cell *c) { for (finger = c->parent; finger != NULL; finger = finger->parent) { /* Lock this cell. */ - if (lock_trylock(&finger->slock) != 0) break; + if (lock_trylock(&finger->stars.lock) != 0) break; /* Increment the hold. */ - atomic_inc(&finger->shold); + atomic_inc(&finger->stars.hold); /* Unlock the cell. */ - if (lock_unlock(&finger->slock) != 0) error("Failed to unlock cell."); + if (lock_unlock(&finger->stars.lock) != 0) error("Failed to unlock cell."); } /* If we reached the top of the tree, we're done. */ @@ -773,10 +777,10 @@ int cell_slocktree(struct cell *c) { /* Undo the holds up to finger. */ for (struct cell *finger2 = c->parent; finger2 != finger; finger2 = finger2->parent) - atomic_dec(&finger2->shold); + atomic_dec(&finger2->stars.hold); /* Unlock this cell. */ - if (lock_unlock(&c->slock) != 0) error("Failed to unlock cell."); + if (lock_unlock(&c->stars.lock) != 0) error("Failed to unlock cell."); /* Admit defeat. */ TIMER_TOC(timer_locktree); @@ -794,11 +798,11 @@ void cell_unlocktree(struct cell *c) { TIMER_TIC /* First of all, try to unlock this cell. */ - if (lock_unlock(&c->lock) != 0) error("Failed to unlock cell."); + if (lock_unlock(&c->hydro.lock) != 0) error("Failed to unlock cell."); /* Climb up the tree and unhold the parents. */ for (struct cell *finger = c->parent; finger != NULL; finger = finger->parent) - atomic_dec(&finger->hold); + atomic_dec(&finger->hydro.hold); TIMER_TOC(timer_locktree); } @@ -813,11 +817,11 @@ void cell_gunlocktree(struct cell *c) { TIMER_TIC /* First of all, try to unlock this cell. */ - if (lock_unlock(&c->glock) != 0) error("Failed to unlock cell."); + if (lock_unlock(&c->grav.plock) != 0) error("Failed to unlock cell."); /* Climb up the tree and unhold the parents. */ for (struct cell *finger = c->parent; finger != NULL; finger = finger->parent) - atomic_dec(&finger->ghold); + atomic_dec(&finger->grav.phold); TIMER_TOC(timer_locktree); } @@ -832,11 +836,11 @@ void cell_munlocktree(struct cell *c) { TIMER_TIC /* First of all, try to unlock this cell. */ - if (lock_unlock(&c->mlock) != 0) error("Failed to unlock cell."); + if (lock_unlock(&c->grav.mlock) != 0) error("Failed to unlock cell."); /* Climb up the tree and unhold the parents. */ for (struct cell *finger = c->parent; finger != NULL; finger = finger->parent) - atomic_dec(&finger->mhold); + atomic_dec(&finger->grav.mhold); TIMER_TOC(timer_locktree); } @@ -851,11 +855,11 @@ void cell_sunlocktree(struct cell *c) { TIMER_TIC /* First of all, try to unlock this cell. */ - if (lock_unlock(&c->slock) != 0) error("Failed to unlock cell."); + if (lock_unlock(&c->stars.lock) != 0) error("Failed to unlock cell."); /* Climb up the tree and unhold the parents. */ for (struct cell *finger = c->parent; finger != NULL; finger = finger->parent) - atomic_dec(&finger->shold); + atomic_dec(&finger->stars.hold); TIMER_TOC(timer_locktree); } @@ -865,25 +869,26 @@ void cell_sunlocktree(struct cell *c) { * * @param c The #cell array to be sorted. * @param parts_offset Offset of the cell parts array relative to the - * space's parts array, i.e. c->parts - s->parts. + * space's parts array, i.e. c->hydro.parts - s->parts. * @param sparts_offset Offset of the cell sparts array relative to the - * space's sparts array, i.e. c->sparts - s->sparts. - * @param buff A buffer with at least max(c->count, c->gcount) entries, - * used for sorting indices. - * @param sbuff A buffer with at least max(c->scount, c->gcount) entries, - * used for sorting indices for the sparts. - * @param gbuff A buffer with at least max(c->count, c->gcount) entries, - * used for sorting indices for the gparts. + * space's sparts array, i.e. c->stars.parts - s->stars.parts. + * @param buff A buffer with at least max(c->hydro.count, c->grav.count) + * entries, used for sorting indices. + * @param sbuff A buffer with at least max(c->stars.count, c->grav.count) + * entries, used for sorting indices for the sparts. + * @param gbuff A buffer with at least max(c->hydro.count, c->grav.count) + * entries, used for sorting indices for the gparts. */ void cell_split(struct cell *c, ptrdiff_t parts_offset, ptrdiff_t sparts_offset, struct cell_buff *buff, struct cell_buff *sbuff, struct cell_buff *gbuff) { - const int count = c->count, gcount = c->gcount, scount = c->scount; - struct part *parts = c->parts; - struct xpart *xparts = c->xparts; - struct gpart *gparts = c->gparts; - struct spart *sparts = c->sparts; + const int count = c->hydro.count, gcount = c->grav.count, + scount = c->stars.count; + struct part *parts = c->hydro.parts; + struct xpart *xparts = c->hydro.xparts; + struct gpart *gparts = c->grav.parts; + struct spart *sparts = c->stars.parts; const double pivot[3] = {c->loc[0] + c->width[0] / 2, c->loc[1] + c->width[1] / 2, c->loc[2] + c->width[2] / 2}; @@ -958,9 +963,9 @@ 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]->count = bucket_count[k]; - c->progeny[k]->parts = &c->parts[bucket_offset[k]]; - c->progeny[k]->xparts = &c->xparts[bucket_offset[k]]; + c->progeny[k]->hydro.count = bucket_count[k]; + c->progeny[k]->hydro.parts = &c->hydro.parts[bucket_offset[k]]; + c->progeny[k]->hydro.xparts = &c->hydro.xparts[bucket_offset[k]]; } #ifdef SWIFT_DEBUG_CHECKS @@ -974,54 +979,55 @@ void cell_split(struct cell *c, ptrdiff_t parts_offset, ptrdiff_t sparts_offset, /* Verify that _all_ the parts have been assigned to a cell. */ for (int k = 1; k < 8; k++) - if (&c->progeny[k - 1]->parts[c->progeny[k - 1]->count] != - c->progeny[k]->parts) + if (&c->progeny[k - 1]->hydro.parts[c->progeny[k - 1]->hydro.count] != + c->progeny[k]->hydro.parts) error("Particle sorting failed (internal consistency)."); - if (c->progeny[0]->parts != c->parts) + if (c->progeny[0]->hydro.parts != c->hydro.parts) error("Particle sorting failed (left edge)."); - if (&c->progeny[7]->parts[c->progeny[7]->count] != &c->parts[count]) + if (&c->progeny[7]->hydro.parts[c->progeny[7]->hydro.count] != + &c->hydro.parts[count]) error("Particle sorting failed (right edge)."); /* Verify a few sub-cells. */ - for (int k = 0; k < c->progeny[0]->count; k++) - if (c->progeny[0]->parts[k].x[0] >= pivot[0] || - c->progeny[0]->parts[k].x[1] >= pivot[1] || - c->progeny[0]->parts[k].x[2] >= pivot[2]) + for (int k = 0; k < c->progeny[0]->hydro.count; k++) + if (c->progeny[0]->hydro.parts[k].x[0] >= pivot[0] || + c->progeny[0]->hydro.parts[k].x[1] >= pivot[1] || + c->progeny[0]->hydro.parts[k].x[2] >= pivot[2]) error("Sorting failed (progeny=0)."); - for (int k = 0; k < c->progeny[1]->count; k++) - if (c->progeny[1]->parts[k].x[0] >= pivot[0] || - c->progeny[1]->parts[k].x[1] >= pivot[1] || - c->progeny[1]->parts[k].x[2] < pivot[2]) + for (int k = 0; k < c->progeny[1]->hydro.count; k++) + if (c->progeny[1]->hydro.parts[k].x[0] >= pivot[0] || + c->progeny[1]->hydro.parts[k].x[1] >= pivot[1] || + c->progeny[1]->hydro.parts[k].x[2] < pivot[2]) error("Sorting failed (progeny=1)."); - for (int k = 0; k < c->progeny[2]->count; k++) - if (c->progeny[2]->parts[k].x[0] >= pivot[0] || - c->progeny[2]->parts[k].x[1] < pivot[1] || - c->progeny[2]->parts[k].x[2] >= pivot[2]) + for (int k = 0; k < c->progeny[2]->hydro.count; k++) + if (c->progeny[2]->hydro.parts[k].x[0] >= pivot[0] || + c->progeny[2]->hydro.parts[k].x[1] < pivot[1] || + c->progeny[2]->hydro.parts[k].x[2] >= pivot[2]) error("Sorting failed (progeny=2)."); - for (int k = 0; k < c->progeny[3]->count; k++) - if (c->progeny[3]->parts[k].x[0] >= pivot[0] || - c->progeny[3]->parts[k].x[1] < pivot[1] || - c->progeny[3]->parts[k].x[2] < pivot[2]) + for (int k = 0; k < c->progeny[3]->hydro.count; k++) + if (c->progeny[3]->hydro.parts[k].x[0] >= pivot[0] || + c->progeny[3]->hydro.parts[k].x[1] < pivot[1] || + c->progeny[3]->hydro.parts[k].x[2] < pivot[2]) error("Sorting failed (progeny=3)."); - for (int k = 0; k < c->progeny[4]->count; k++) - if (c->progeny[4]->parts[k].x[0] < pivot[0] || - c->progeny[4]->parts[k].x[1] >= pivot[1] || - c->progeny[4]->parts[k].x[2] >= pivot[2]) + for (int k = 0; k < c->progeny[4]->hydro.count; k++) + if (c->progeny[4]->hydro.parts[k].x[0] < pivot[0] || + c->progeny[4]->hydro.parts[k].x[1] >= pivot[1] || + c->progeny[4]->hydro.parts[k].x[2] >= pivot[2]) error("Sorting failed (progeny=4)."); - for (int k = 0; k < c->progeny[5]->count; k++) - if (c->progeny[5]->parts[k].x[0] < pivot[0] || - c->progeny[5]->parts[k].x[1] >= pivot[1] || - c->progeny[5]->parts[k].x[2] < pivot[2]) + for (int k = 0; k < c->progeny[5]->hydro.count; k++) + if (c->progeny[5]->hydro.parts[k].x[0] < pivot[0] || + c->progeny[5]->hydro.parts[k].x[1] >= pivot[1] || + c->progeny[5]->hydro.parts[k].x[2] < pivot[2]) error("Sorting failed (progeny=5)."); - for (int k = 0; k < c->progeny[6]->count; k++) - if (c->progeny[6]->parts[k].x[0] < pivot[0] || - c->progeny[6]->parts[k].x[1] < pivot[1] || - c->progeny[6]->parts[k].x[2] >= pivot[2]) + for (int k = 0; k < c->progeny[6]->hydro.count; k++) + if (c->progeny[6]->hydro.parts[k].x[0] < pivot[0] || + c->progeny[6]->hydro.parts[k].x[1] < pivot[1] || + c->progeny[6]->hydro.parts[k].x[2] >= pivot[2]) error("Sorting failed (progeny=6)."); - for (int k = 0; k < c->progeny[7]->count; k++) - if (c->progeny[7]->parts[k].x[0] < pivot[0] || - c->progeny[7]->parts[k].x[1] < pivot[1] || - c->progeny[7]->parts[k].x[2] < pivot[2]) + for (int k = 0; k < c->progeny[7]->hydro.count; k++) + if (c->progeny[7]->hydro.parts[k].x[0] < pivot[0] || + c->progeny[7]->hydro.parts[k].x[1] < pivot[1] || + c->progeny[7]->hydro.parts[k].x[2] < pivot[2]) error("Sorting failed (progeny=7)."); #endif @@ -1074,8 +1080,8 @@ 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]->scount = bucket_count[k]; - c->progeny[k]->sparts = &c->sparts[bucket_offset[k]]; + c->progeny[k]->stars.count = bucket_count[k]; + c->progeny[k]->stars.parts = &c->stars.parts[bucket_offset[k]]; } /* Finally, do the same song and dance for the gparts. */ @@ -1136,8 +1142,8 @@ 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]->gcount = bucket_count[k]; - c->progeny[k]->gparts = &c->gparts[bucket_offset[k]]; + c->progeny[k]->grav.count = bucket_count[k]; + c->progeny[k]->grav.parts = &c->grav.parts[bucket_offset[k]]; } } @@ -1153,9 +1159,12 @@ void cell_split(struct cell *c, ptrdiff_t parts_offset, ptrdiff_t sparts_offset, */ void cell_sanitize(struct cell *c, int treated) { - const int count = c->count; - struct part *parts = c->parts; + const int count = c->hydro.count; + const int scount = c->stars.count; + struct part *parts = c->hydro.parts; + struct spart *sparts = c->stars.parts; float h_max = 0.f; + float stars_h_max = 0.f; /* Treat cells will <1000 particles */ if (count < 1000 && !treated) { @@ -1168,6 +1177,10 @@ void cell_sanitize(struct cell *c, int treated) { if (parts[i].h == 0.f || parts[i].h > upper_h_max) parts[i].h = upper_h_max; } + for (int i = 0; i < scount; ++i) { + if (sparts[i].h == 0.f || sparts[i].h > upper_h_max) + sparts[i].h = upper_h_max; + } } /* Recurse and gather the new h_max values */ @@ -1180,17 +1193,21 @@ void cell_sanitize(struct cell *c, int treated) { cell_sanitize(c->progeny[k], (count < 1000)); /* And collect */ - h_max = max(h_max, c->progeny[k]->h_max); + h_max = max(h_max, c->progeny[k]->hydro.h_max); + stars_h_max = max(stars_h_max, c->progeny[k]->stars.h_max); } } } else { /* Get the new value of h_max */ for (int i = 0; i < count; ++i) h_max = max(h_max, parts[i].h); + for (int i = 0; i < scount; ++i) + stars_h_max = max(stars_h_max, sparts[i].h); } /* Record the change */ - c->h_max = h_max; + c->hydro.h_max = h_max; + c->stars.h_max = stars_h_max; } /** @@ -1200,11 +1217,11 @@ void cell_sanitize(struct cell *c, int treated) { * @param data Unused parameter */ void cell_clean_links(struct cell *c, void *data) { - c->density = NULL; - c->gradient = NULL; - c->force = NULL; - c->grav = NULL; - c->grav_mm = NULL; + c->hydro.density = NULL; + c->hydro.gradient = NULL; + c->hydro.force = NULL; + c->grav.grav = NULL; + c->grav.mm = NULL; } /** @@ -1225,14 +1242,18 @@ void cell_check_part_drift_point(struct cell *c, void *data) { /* Only check local cells */ if (c->nodeID != engine_rank) return; - if (c->ti_old_part != ti_drift) - error("Cell in an incorrect time-zone! c->ti_old_part=%lld ti_drift=%lld", - c->ti_old_part, ti_drift); + /* Only check cells with content */ + if (c->hydro.count == 0) return; + + if (c->hydro.ti_old_part != ti_drift) + error("Cell in an incorrect time-zone! c->hydro.ti_old=%lld ti_drift=%lld", + c->hydro.ti_old_part, ti_drift); - for (int i = 0; i < c->count; ++i) - if (c->parts[i].ti_drift != ti_drift) + for (int i = 0; i < c->hydro.count; ++i) + if (c->hydro.parts[i].ti_drift != ti_drift && + c->hydro.parts[i].time_bin != time_bin_inhibited) error("part in an incorrect time-zone! p->ti_drift=%lld ti_drift=%lld", - c->parts[i].ti_drift, ti_drift); + c->hydro.parts[i].ti_drift, ti_drift); #else error("Calling debugging code without debugging flag activated."); #endif @@ -1256,19 +1277,26 @@ void cell_check_gpart_drift_point(struct cell *c, void *data) { /* Only check local cells */ if (c->nodeID != engine_rank) return; - if (c->ti_old_gpart != ti_drift) - error("Cell in an incorrect time-zone! c->ti_old_gpart=%lld ti_drift=%lld", - c->ti_old_gpart, ti_drift); + /* Only check cells with content */ + if (c->grav.count == 0) return; + + if (c->grav.ti_old_part != ti_drift) + error( + "Cell in an incorrect time-zone! c->grav.ti_old_part=%lld " + "ti_drift=%lld", + c->grav.ti_old_part, ti_drift); - for (int i = 0; i < c->gcount; ++i) - if (c->gparts[i].ti_drift != ti_drift) + for (int i = 0; i < c->grav.count; ++i) + if (c->grav.parts[i].ti_drift != ti_drift && + c->grav.parts[i].time_bin != time_bin_inhibited) error("g-part in an incorrect time-zone! gp->ti_drift=%lld ti_drift=%lld", - c->gparts[i].ti_drift, ti_drift); + c->grav.parts[i].ti_drift, ti_drift); - for (int i = 0; i < c->scount; ++i) - if (c->sparts[i].ti_drift != ti_drift) + for (int i = 0; i < c->stars.count; ++i) + if (c->stars.parts[i].ti_drift != ti_drift && + c->stars.parts[i].time_bin != time_bin_inhibited) error("s-part in an incorrect time-zone! sp->ti_drift=%lld ti_drift=%lld", - c->sparts[i].ti_drift, ti_drift); + c->stars.parts[i].ti_drift, ti_drift); #else error("Calling debugging code without debugging flag activated."); #endif @@ -1288,11 +1316,18 @@ void cell_check_multipole_drift_point(struct cell *c, void *data) { const integertime_t ti_drift = *(integertime_t *)data; - if (c->ti_old_multipole != ti_drift) + /* Only check local cells */ + if (c->nodeID != engine_rank) return; + + /* Only check cells with content */ + if (c->grav.count == 0) return; + + if (c->grav.ti_old_multipole != ti_drift) error( - "Cell multipole in an incorrect time-zone! c->ti_old_multipole=%lld " - "ti_drift=%lld (depth=%d)", - c->ti_old_multipole, ti_drift, c->depth); + "Cell multipole in an incorrect time-zone! " + "c->grav.ti_old_multipole=%lld " + "ti_drift=%lld (depth=%d, node=%d)", + c->grav.ti_old_multipole, ti_drift, c->depth, c->nodeID); #else error("Calling debugging code without debugging flag activated."); @@ -1325,7 +1360,7 @@ void cell_reset_task_counters(struct cell *c) { void cell_make_multipoles(struct cell *c, integertime_t ti_current) { /* Reset everything */ - gravity_reset(c->multipole); + gravity_reset(c->grav.multipole); if (c->split) { @@ -1341,7 +1376,7 @@ void cell_make_multipoles(struct cell *c, integertime_t ti_current) { for (int k = 0; k < 8; ++k) { if (c->progeny[k] != NULL) { - const struct gravity_tensors *m = c->progeny[k]->multipole; + const struct gravity_tensors *m = c->progeny[k]->grav.multipole; CoM[0] += m->CoM[0] * m->m_pole.M_000; CoM[1] += m->CoM[1] * m->m_pole.M_000; CoM[2] += m->CoM[2] * m->m_pole.M_000; @@ -1350,9 +1385,9 @@ void cell_make_multipoles(struct cell *c, integertime_t ti_current) { } const double mass_inv = 1. / mass; - c->multipole->CoM[0] = CoM[0] * mass_inv; - c->multipole->CoM[1] = CoM[1] * mass_inv; - c->multipole->CoM[2] = CoM[2] * mass_inv; + c->grav.multipole->CoM[0] = CoM[0] * mass_inv; + c->grav.multipole->CoM[1] = CoM[1] * mass_inv; + c->grav.multipole->CoM[2] = CoM[2] * mass_inv; /* Now shift progeny multipoles and add them up */ struct multipole temp; @@ -1360,64 +1395,70 @@ void cell_make_multipoles(struct cell *c, integertime_t ti_current) { for (int k = 0; k < 8; ++k) { if (c->progeny[k] != NULL) { const struct cell *cp = c->progeny[k]; - const struct multipole *m = &cp->multipole->m_pole; + const struct multipole *m = &cp->grav.multipole->m_pole; /* Contribution to multipole */ - gravity_M2M(&temp, m, c->multipole->CoM, cp->multipole->CoM); - gravity_multipole_add(&c->multipole->m_pole, &temp); + gravity_M2M(&temp, m, c->grav.multipole->CoM, cp->grav.multipole->CoM); + gravity_multipole_add(&c->grav.multipole->m_pole, &temp); /* Upper limit of max CoM<->gpart distance */ - const double dx = c->multipole->CoM[0] - cp->multipole->CoM[0]; - const double dy = c->multipole->CoM[1] - cp->multipole->CoM[1]; - const double dz = c->multipole->CoM[2] - cp->multipole->CoM[2]; + const double dx = + c->grav.multipole->CoM[0] - cp->grav.multipole->CoM[0]; + const double dy = + c->grav.multipole->CoM[1] - cp->grav.multipole->CoM[1]; + const double dz = + c->grav.multipole->CoM[2] - cp->grav.multipole->CoM[2]; const double r2 = dx * dx + dy * dy + dz * dz; - r_max = max(r_max, cp->multipole->r_max + sqrt(r2)); + r_max = max(r_max, cp->grav.multipole->r_max + sqrt(r2)); } } /* Alternative upper limit of max CoM<->gpart distance */ - const double dx = c->multipole->CoM[0] > c->loc[0] + c->width[0] * 0.5 - ? c->multipole->CoM[0] - c->loc[0] - : c->loc[0] + c->width[0] - c->multipole->CoM[0]; - const double dy = c->multipole->CoM[1] > c->loc[1] + c->width[1] * 0.5 - ? c->multipole->CoM[1] - c->loc[1] - : c->loc[1] + c->width[1] - c->multipole->CoM[1]; - const double dz = c->multipole->CoM[2] > c->loc[2] + c->width[2] * 0.5 - ? c->multipole->CoM[2] - c->loc[2] - : c->loc[2] + c->width[2] - c->multipole->CoM[2]; + const double dx = c->grav.multipole->CoM[0] > c->loc[0] + c->width[0] * 0.5 + ? c->grav.multipole->CoM[0] - c->loc[0] + : c->loc[0] + c->width[0] - c->grav.multipole->CoM[0]; + const double dy = c->grav.multipole->CoM[1] > c->loc[1] + c->width[1] * 0.5 + ? c->grav.multipole->CoM[1] - c->loc[1] + : c->loc[1] + c->width[1] - c->grav.multipole->CoM[1]; + const double dz = c->grav.multipole->CoM[2] > c->loc[2] + c->width[2] * 0.5 + ? c->grav.multipole->CoM[2] - c->loc[2] + : c->loc[2] + c->width[2] - c->grav.multipole->CoM[2]; /* Take minimum of both limits */ - c->multipole->r_max = min(r_max, sqrt(dx * dx + dy * dy + dz * dz)); + c->grav.multipole->r_max = min(r_max, sqrt(dx * dx + dy * dy + dz * dz)); } else { - if (c->gcount > 0) { - gravity_P2M(c->multipole, c->gparts, c->gcount); - const double dx = c->multipole->CoM[0] > c->loc[0] + c->width[0] * 0.5 - ? c->multipole->CoM[0] - c->loc[0] - : c->loc[0] + c->width[0] - c->multipole->CoM[0]; - const double dy = c->multipole->CoM[1] > c->loc[1] + c->width[1] * 0.5 - ? c->multipole->CoM[1] - c->loc[1] - : c->loc[1] + c->width[1] - c->multipole->CoM[1]; - const double dz = c->multipole->CoM[2] > c->loc[2] + c->width[2] * 0.5 - ? c->multipole->CoM[2] - c->loc[2] - : c->loc[2] + c->width[2] - c->multipole->CoM[2]; - c->multipole->r_max = sqrt(dx * dx + dy * dy + dz * dz); + if (c->grav.count > 0) { + gravity_P2M(c->grav.multipole, c->grav.parts, c->grav.count); + const double dx = + c->grav.multipole->CoM[0] > c->loc[0] + c->width[0] * 0.5 + ? c->grav.multipole->CoM[0] - c->loc[0] + : c->loc[0] + c->width[0] - c->grav.multipole->CoM[0]; + const double dy = + c->grav.multipole->CoM[1] > c->loc[1] + c->width[1] * 0.5 + ? c->grav.multipole->CoM[1] - c->loc[1] + : c->loc[1] + c->width[1] - c->grav.multipole->CoM[1]; + const double dz = + c->grav.multipole->CoM[2] > c->loc[2] + c->width[2] * 0.5 + ? c->grav.multipole->CoM[2] - c->loc[2] + : c->loc[2] + c->width[2] - c->grav.multipole->CoM[2]; + c->grav.multipole->r_max = sqrt(dx * dx + dy * dy + dz * dz); } else { - gravity_multipole_init(&c->multipole->m_pole); - c->multipole->CoM[0] = c->loc[0] + c->width[0] * 0.5; - c->multipole->CoM[1] = c->loc[1] + c->width[1] * 0.5; - c->multipole->CoM[2] = c->loc[2] + c->width[2] * 0.5; - c->multipole->r_max = 0.; + gravity_multipole_init(&c->grav.multipole->m_pole); + c->grav.multipole->CoM[0] = c->loc[0] + c->width[0] * 0.5; + c->grav.multipole->CoM[1] = c->loc[1] + c->width[1] * 0.5; + c->grav.multipole->CoM[2] = c->loc[2] + c->width[2] * 0.5; + c->grav.multipole->r_max = 0.; } } /* Also update the values at rebuild time */ - c->multipole->r_max_rebuild = c->multipole->r_max; - c->multipole->CoM_rebuild[0] = c->multipole->CoM[0]; - c->multipole->CoM_rebuild[1] = c->multipole->CoM[1]; - c->multipole->CoM_rebuild[2] = c->multipole->CoM[2]; + c->grav.multipole->r_max_rebuild = c->grav.multipole->r_max; + c->grav.multipole->CoM_rebuild[0] = c->grav.multipole->CoM[0]; + c->grav.multipole->CoM_rebuild[1] = c->grav.multipole->CoM[1]; + c->grav.multipole->CoM_rebuild[2] = c->grav.multipole->CoM[2]; - c->ti_old_multipole = ti_current; + c->grav.ti_old_multipole = ti_current; } /** @@ -1443,17 +1484,17 @@ void cell_check_foreign_multipole(const struct cell *c) { if (cp != NULL) { /* Check the mass */ - M_000 += cp->multipole->m_pole.M_000; + M_000 += cp->grav.multipole->m_pole.M_000; /* Check the number of particles */ - num_gpart += cp->multipole->m_pole.num_gpart; + num_gpart += cp->grav.multipole->m_pole.num_gpart; /* Now recurse */ cell_check_foreign_multipole(cp); } } - if (num_gpart != c->multipole->m_pole.num_gpart) + if (num_gpart != c->grav.multipole->m_pole.num_gpart) error("Sum of particles in progenies does not match"); } @@ -1479,29 +1520,29 @@ void cell_check_multipole(struct cell *c) { for (int k = 0; k < 8; k++) if (c->progeny[k] != NULL) cell_check_multipole(c->progeny[k]); - if (c->gcount > 0) { + if (c->grav.count > 0) { /* Brute-force calculation */ - gravity_P2M(&ma, c->gparts, c->gcount); + gravity_P2M(&ma, c->grav.parts, c->grav.count); /* Now compare the multipole expansion */ - if (!gravity_multipole_equal(&ma, c->multipole, tolerance)) { + if (!gravity_multipole_equal(&ma, c->grav.multipole, tolerance)) { message("Multipoles are not equal at depth=%d! tol=%f", c->depth, tolerance); message("Correct answer:"); gravity_multipole_print(&ma.m_pole); message("Recursive multipole:"); - gravity_multipole_print(&c->multipole->m_pole); + gravity_multipole_print(&c->grav.multipole->m_pole); error("Aborting"); } /* Check that the upper limit of r_max is good enough */ - if (!(1.1 * c->multipole->r_max >= ma.r_max)) { + if (!(1.1 * c->grav.multipole->r_max >= ma.r_max)) { error("Upper-limit r_max=%e too small. Should be >=%e.", - c->multipole->r_max, ma.r_max); - } else if (c->multipole->r_max * c->multipole->r_max > + c->grav.multipole->r_max, ma.r_max); + } else if (c->grav.multipole->r_max * c->grav.multipole->r_max > 3. * c->width[0] * c->width[0]) { - error("r_max=%e larger than cell diagonal %e.", c->multipole->r_max, + error("r_max=%e larger than cell diagonal %e.", c->grav.multipole->r_max, sqrt(3. * c->width[0] * c->width[0])); } } @@ -1518,9 +1559,9 @@ void cell_check_multipole(struct cell *c) { void cell_clean(struct cell *c) { for (int i = 0; i < 13; i++) - if (c->sort[i] != NULL) { - free(c->sort[i]); - c->sort[i] = NULL; + if (c->hydro.sort[i] != NULL) { + free(c->hydro.sort[i]); + c->hydro.sort[i] = NULL; } /* Recurse */ @@ -1532,10 +1573,10 @@ void cell_clean(struct cell *c) { * @brief Clear the drift flags on the given cell. */ void cell_clear_drift_flags(struct cell *c, void *data) { - c->do_drift = 0; - c->do_sub_drift = 0; - c->do_grav_drift = 0; - c->do_grav_sub_drift = 0; + c->hydro.do_drift = 0; + c->hydro.do_sub_drift = 0; + c->grav.do_drift = 0; + c->grav.do_sub_drift = 0; } /** @@ -1544,29 +1585,30 @@ void cell_clear_drift_flags(struct cell *c, void *data) { void cell_activate_drift_part(struct cell *c, struct scheduler *s) { /* If this cell is already marked for drift, quit early. */ - if (c->do_drift) return; + if (c->hydro.do_drift) return; /* Mark this cell for drifting. */ - c->do_drift = 1; + c->hydro.do_drift = 1; /* Set the do_sub_drifts all the way up and activate the super drift if this has not yet been done. */ - if (c == c->super_hydro) { + if (c == c->hydro.super) { #ifdef SWIFT_DEBUG_CHECKS - if (c->drift_part == NULL) - error("Trying to activate un-existing c->drift_part"); + if (c->hydro.drift == NULL) + error("Trying to activate un-existing c->hydro.drift"); #endif - scheduler_activate(s, c->drift_part); + scheduler_activate(s, c->hydro.drift); } else { for (struct cell *parent = c->parent; - parent != NULL && !parent->do_sub_drift; parent = parent->parent) { - parent->do_sub_drift = 1; - if (parent == c->super_hydro) { + parent != NULL && !parent->hydro.do_sub_drift; + parent = parent->parent) { + parent->hydro.do_sub_drift = 1; + if (parent == c->hydro.super) { #ifdef SWIFT_DEBUG_CHECKS - if (parent->drift_part == NULL) - error("Trying to activate un-existing parent->drift_part"); + if (parent->hydro.drift == NULL) + error("Trying to activate un-existing parent->hydro.drift"); #endif - scheduler_activate(s, parent->drift_part); + scheduler_activate(s, parent->hydro.drift); break; } } @@ -1579,58 +1621,67 @@ void cell_activate_drift_part(struct cell *c, struct scheduler *s) { void cell_activate_drift_gpart(struct cell *c, struct scheduler *s) { /* If this cell is already marked for drift, quit early. */ - if (c->do_grav_drift) return; + if (c->grav.do_drift) return; /* Mark this cell for drifting. */ - c->do_grav_drift = 1; + c->grav.do_drift = 1; /* Set the do_grav_sub_drifts all the way up and activate the super drift if this has not yet been done. */ - if (c == c->super_gravity) { + if (c == c->grav.super) { #ifdef SWIFT_DEBUG_CHECKS - if (c->drift_gpart == NULL) - error("Trying to activate un-existing c->drift_gpart"); + if (c->grav.drift == NULL) + error("Trying to activate un-existing c->grav.drift"); #endif - scheduler_activate(s, c->drift_gpart); + scheduler_activate(s, c->grav.drift); } else { for (struct cell *parent = c->parent; - parent != NULL && !parent->do_grav_sub_drift; + parent != NULL && !parent->grav.do_sub_drift; parent = parent->parent) { - parent->do_grav_sub_drift = 1; - if (parent == c->super_gravity) { + parent->grav.do_sub_drift = 1; + if (parent == c->grav.super) { #ifdef SWIFT_DEBUG_CHECKS - if (parent->drift_gpart == NULL) - error("Trying to activate un-existing parent->drift_gpart"); + if (parent->grav.drift == NULL) + error("Trying to activate un-existing parent->grav.drift"); #endif - scheduler_activate(s, parent->drift_gpart); + scheduler_activate(s, parent->grav.drift); break; } } } } +/** + * @brief Activate the #spart drifts on the given cell. + */ +void cell_activate_drift_spart(struct cell *c, struct scheduler *s) { + cell_activate_drift_gpart(c, s); +} + /** * @brief Activate the sorts up a cell hierarchy. */ void cell_activate_sorts_up(struct cell *c, struct scheduler *s) { - if (c == c->super_hydro) { + if (c == c->hydro.super) { #ifdef SWIFT_DEBUG_CHECKS - if (c->sorts == NULL) error("Trying to activate un-existing c->sorts"); + if (c->hydro.sorts == NULL) + error("Trying to activate un-existing c->hydro.sorts"); #endif - scheduler_activate(s, c->sorts); + scheduler_activate(s, c->hydro.sorts); if (c->nodeID == engine_rank) cell_activate_drift_part(c, s); } else { for (struct cell *parent = c->parent; - parent != NULL && !parent->do_sub_sort; parent = parent->parent) { - parent->do_sub_sort = 1; - if (parent == c->super_hydro) { + parent != NULL && !parent->hydro.do_sub_sort; + parent = parent->parent) { + parent->hydro.do_sub_sort = 1; + if (parent == c->hydro.super) { #ifdef SWIFT_DEBUG_CHECKS - if (parent->sorts == NULL) - error("Trying to activate un-existing parents->sorts"); + if (parent->hydro.sorts == NULL) + error("Trying to activate un-existing parents->hydro.sorts"); #endif - scheduler_activate(s, parent->sorts); + scheduler_activate(s, parent->hydro.sorts); if (parent->nodeID == engine_rank) cell_activate_drift_part(parent, s); break; } @@ -1644,21 +1695,21 @@ void cell_activate_sorts_up(struct cell *c, struct scheduler *s) { void cell_activate_sorts(struct cell *c, int sid, struct scheduler *s) { /* Do we need to re-sort? */ - if (c->dx_max_sort > space_maxreldx * c->dmin) { + if (c->hydro.dx_max_sort > space_maxreldx * c->dmin) { /* Climb up the tree to active the sorts in that direction */ for (struct cell *finger = c; finger != NULL; finger = finger->parent) { - if (finger->requires_sorts) { - atomic_or(&finger->do_sort, finger->requires_sorts); + if (finger->hydro.requires_sorts) { + atomic_or(&finger->hydro.do_sort, finger->hydro.requires_sorts); cell_activate_sorts_up(finger, s); } - finger->sorted = 0; + finger->hydro.sorted = 0; } } /* Has this cell been sorted at all for the given sid? */ - if (!(c->sorted & (1 << sid)) || c->nodeID != engine_rank) { - atomic_or(&c->do_sort, (1 << sid)); + if (!(c->hydro.sorted & (1 << sid)) || c->nodeID != engine_rank) { + atomic_or(&c->hydro.do_sort, (1 << sid)); cell_activate_sorts_up(c, s); } } @@ -1676,18 +1727,19 @@ void cell_activate_subcell_hydro_tasks(struct cell *ci, struct cell *cj, const struct engine *e = s->space->e; /* Store the current dx_max and h_max values. */ - ci->dx_max_old = ci->dx_max_part; - ci->h_max_old = ci->h_max; + ci->hydro.dx_max_part_old = ci->hydro.dx_max_part; + ci->hydro.h_max_old = ci->hydro.h_max; + if (cj != NULL) { - cj->dx_max_old = cj->dx_max_part; - cj->h_max_old = cj->h_max; + cj->hydro.dx_max_part_old = cj->hydro.dx_max_part; + cj->hydro.h_max_old = cj->hydro.h_max; } /* Self interaction? */ if (cj == NULL) { /* Do anything? */ - if (ci->count == 0 || !cell_is_active_hydro(ci, e)) return; + if (ci->hydro.count == 0 || !cell_is_active_hydro(ci, e)) return; /* Recurse? */ if (cell_can_recurse_in_self_hydro_task(ci)) { @@ -1714,7 +1766,7 @@ void cell_activate_subcell_hydro_tasks(struct cell *ci, struct cell *cj, /* Should we even bother? */ if (!cell_is_active_hydro(ci, e) && !cell_is_active_hydro(cj, e)) return; - if (ci->count == 0 || cj->count == 0) return; + if (ci->hydro.count == 0 || cj->hydro.count == 0) return; /* Get the orientation of the pair. */ double shift[3]; @@ -2002,10 +2054,10 @@ void cell_activate_subcell_hydro_tasks(struct cell *ci, struct cell *cj, else if (cell_is_active_hydro(ci, e) || cell_is_active_hydro(cj, e)) { /* We are going to interact this pair, so store some values. */ - atomic_or(&ci->requires_sorts, 1 << sid); - atomic_or(&cj->requires_sorts, 1 << sid); - ci->dx_max_sort_old = ci->dx_max_sort; - cj->dx_max_sort_old = cj->dx_max_sort; + atomic_or(&ci->hydro.requires_sorts, 1 << sid); + atomic_or(&cj->hydro.requires_sorts, 1 << sid); + ci->hydro.dx_max_sort_old = ci->hydro.dx_max_sort; + cj->hydro.dx_max_sort_old = cj->hydro.dx_max_sort; /* Activate the drifts if the cells are local. */ if (ci->nodeID == engine_rank) cell_activate_drift_part(ci, s); @@ -2028,7 +2080,353 @@ void cell_activate_subcell_hydro_tasks(struct cell *ci, struct cell *cj, */ void cell_activate_subcell_stars_tasks(struct cell *ci, struct cell *cj, struct scheduler *s) { - // LOIC: to implement + const struct engine *e = s->space->e; + + /* Store the current dx_max and h_max values. */ + ci->stars.dx_max_part_old = ci->stars.dx_max_part; + ci->stars.h_max_old = ci->stars.h_max; + + if (cj != NULL) { + cj->stars.dx_max_part_old = cj->stars.dx_max_part; + cj->stars.h_max_old = cj->stars.h_max; + } + + /* Self interaction? */ + if (cj == NULL) { + + /* Do anything? */ + if (ci->stars.count == 0 || !cell_is_active_stars(ci, e)) return; + + /* Recurse? */ + if (cell_can_recurse_in_self_stars_task(ci)) { + + /* Loop over all progenies and pairs of progenies */ + for (int j = 0; j < 8; j++) { + if (ci->progeny[j] != NULL) { + cell_activate_subcell_stars_tasks(ci->progeny[j], NULL, s); + for (int k = j + 1; k < 8; k++) + if (ci->progeny[k] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[j], ci->progeny[k], + s); + } + } + } else { + + /* We have reached the bottom of the tree: activate drift */ + cell_activate_drift_spart(ci, s); + cell_activate_drift_part(ci, s); + } + } + + /* Otherwise, pair interation */ + else { + + /* Should we even bother? */ + if (!cell_is_active_stars(ci, e) && !cell_is_active_stars(cj, e)) return; + if (ci->stars.count == 0 || cj->stars.count == 0) return; + + /* Get the orientation of the pair. */ + double shift[3]; + int sid = space_getsid(s->space, &ci, &cj, shift); + + /* recurse? */ + if (cell_can_recurse_in_pair_stars_task(ci) && + cell_can_recurse_in_pair_stars_task(cj)) { + + /* Different types of flags. */ + switch (sid) { + + /* Regular sub-cell interactions of a single cell. */ + case 0: /* ( 1 , 1 , 1 ) */ + if (ci->progeny[7] != NULL && cj->progeny[0] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[7], cj->progeny[0], + s); + break; + + case 1: /* ( 1 , 1 , 0 ) */ + if (ci->progeny[6] != NULL && cj->progeny[0] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[6], cj->progeny[0], + s); + if (ci->progeny[6] != NULL && cj->progeny[1] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[6], cj->progeny[1], + s); + if (ci->progeny[7] != NULL && cj->progeny[0] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[7], cj->progeny[0], + s); + if (ci->progeny[7] != NULL && cj->progeny[1] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[7], cj->progeny[1], + s); + break; + + case 2: /* ( 1 , 1 , -1 ) */ + if (ci->progeny[6] != NULL && cj->progeny[1] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[6], cj->progeny[1], + s); + break; + + case 3: /* ( 1 , 0 , 1 ) */ + if (ci->progeny[5] != NULL && cj->progeny[0] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[5], cj->progeny[0], + s); + if (ci->progeny[5] != NULL && cj->progeny[2] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[5], cj->progeny[2], + s); + if (ci->progeny[7] != NULL && cj->progeny[0] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[7], cj->progeny[0], + s); + if (ci->progeny[7] != NULL && cj->progeny[2] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[7], cj->progeny[2], + s); + break; + + case 4: /* ( 1 , 0 , 0 ) */ + if (ci->progeny[4] != NULL && cj->progeny[0] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[4], cj->progeny[0], + s); + if (ci->progeny[4] != NULL && cj->progeny[1] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[4], cj->progeny[1], + s); + if (ci->progeny[4] != NULL && cj->progeny[2] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[4], cj->progeny[2], + s); + if (ci->progeny[4] != NULL && cj->progeny[3] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[4], cj->progeny[3], + s); + if (ci->progeny[5] != NULL && cj->progeny[0] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[5], cj->progeny[0], + s); + if (ci->progeny[5] != NULL && cj->progeny[1] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[5], cj->progeny[1], + s); + if (ci->progeny[5] != NULL && cj->progeny[2] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[5], cj->progeny[2], + s); + if (ci->progeny[5] != NULL && cj->progeny[3] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[5], cj->progeny[3], + s); + if (ci->progeny[6] != NULL && cj->progeny[0] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[6], cj->progeny[0], + s); + if (ci->progeny[6] != NULL && cj->progeny[1] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[6], cj->progeny[1], + s); + if (ci->progeny[6] != NULL && cj->progeny[2] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[6], cj->progeny[2], + s); + if (ci->progeny[6] != NULL && cj->progeny[3] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[6], cj->progeny[3], + s); + if (ci->progeny[7] != NULL && cj->progeny[0] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[7], cj->progeny[0], + s); + if (ci->progeny[7] != NULL && cj->progeny[1] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[7], cj->progeny[1], + s); + if (ci->progeny[7] != NULL && cj->progeny[2] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[7], cj->progeny[2], + s); + if (ci->progeny[7] != NULL && cj->progeny[3] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[7], cj->progeny[3], + s); + break; + + case 5: /* ( 1 , 0 , -1 ) */ + if (ci->progeny[4] != NULL && cj->progeny[1] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[4], cj->progeny[1], + s); + if (ci->progeny[4] != NULL && cj->progeny[3] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[4], cj->progeny[3], + s); + if (ci->progeny[6] != NULL && cj->progeny[1] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[6], cj->progeny[1], + s); + if (ci->progeny[6] != NULL && cj->progeny[3] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[6], cj->progeny[3], + s); + break; + + case 6: /* ( 1 , -1 , 1 ) */ + if (ci->progeny[5] != NULL && cj->progeny[2] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[5], cj->progeny[2], + s); + break; + + case 7: /* ( 1 , -1 , 0 ) */ + if (ci->progeny[4] != NULL && cj->progeny[2] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[4], cj->progeny[2], + s); + if (ci->progeny[4] != NULL && cj->progeny[3] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[4], cj->progeny[3], + s); + if (ci->progeny[5] != NULL && cj->progeny[2] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[5], cj->progeny[2], + s); + if (ci->progeny[5] != NULL && cj->progeny[3] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[5], cj->progeny[3], + s); + break; + + case 8: /* ( 1 , -1 , -1 ) */ + if (ci->progeny[4] != NULL && cj->progeny[3] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[4], cj->progeny[3], + s); + break; + + case 9: /* ( 0 , 1 , 1 ) */ + if (ci->progeny[3] != NULL && cj->progeny[0] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[3], cj->progeny[0], + s); + if (ci->progeny[3] != NULL && cj->progeny[4] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[3], cj->progeny[4], + s); + if (ci->progeny[7] != NULL && cj->progeny[0] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[7], cj->progeny[0], + s); + if (ci->progeny[7] != NULL && cj->progeny[4] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[7], cj->progeny[4], + s); + break; + + case 10: /* ( 0 , 1 , 0 ) */ + if (ci->progeny[2] != NULL && cj->progeny[0] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[2], cj->progeny[0], + s); + if (ci->progeny[2] != NULL && cj->progeny[1] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[2], cj->progeny[1], + s); + if (ci->progeny[2] != NULL && cj->progeny[4] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[2], cj->progeny[4], + s); + if (ci->progeny[2] != NULL && cj->progeny[5] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[2], cj->progeny[5], + s); + if (ci->progeny[3] != NULL && cj->progeny[0] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[3], cj->progeny[0], + s); + if (ci->progeny[3] != NULL && cj->progeny[1] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[3], cj->progeny[1], + s); + if (ci->progeny[3] != NULL && cj->progeny[4] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[3], cj->progeny[4], + s); + if (ci->progeny[3] != NULL && cj->progeny[5] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[3], cj->progeny[5], + s); + if (ci->progeny[6] != NULL && cj->progeny[0] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[6], cj->progeny[0], + s); + if (ci->progeny[6] != NULL && cj->progeny[1] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[6], cj->progeny[1], + s); + if (ci->progeny[6] != NULL && cj->progeny[4] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[6], cj->progeny[4], + s); + if (ci->progeny[6] != NULL && cj->progeny[5] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[6], cj->progeny[5], + s); + if (ci->progeny[7] != NULL && cj->progeny[0] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[7], cj->progeny[0], + s); + if (ci->progeny[7] != NULL && cj->progeny[1] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[7], cj->progeny[1], + s); + if (ci->progeny[7] != NULL && cj->progeny[4] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[7], cj->progeny[4], + s); + if (ci->progeny[7] != NULL && cj->progeny[5] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[7], cj->progeny[5], + s); + break; + + case 11: /* ( 0 , 1 , -1 ) */ + if (ci->progeny[2] != NULL && cj->progeny[1] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[2], cj->progeny[1], + s); + if (ci->progeny[2] != NULL && cj->progeny[5] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[2], cj->progeny[5], + s); + if (ci->progeny[6] != NULL && cj->progeny[1] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[6], cj->progeny[1], + s); + if (ci->progeny[6] != NULL && cj->progeny[5] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[6], cj->progeny[5], + s); + break; + + case 12: /* ( 0 , 0 , 1 ) */ + if (ci->progeny[1] != NULL && cj->progeny[0] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[1], cj->progeny[0], + s); + if (ci->progeny[1] != NULL && cj->progeny[2] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[1], cj->progeny[2], + s); + if (ci->progeny[1] != NULL && cj->progeny[4] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[1], cj->progeny[4], + s); + if (ci->progeny[1] != NULL && cj->progeny[6] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[1], cj->progeny[6], + s); + if (ci->progeny[3] != NULL && cj->progeny[0] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[3], cj->progeny[0], + s); + if (ci->progeny[3] != NULL && cj->progeny[2] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[3], cj->progeny[2], + s); + if (ci->progeny[3] != NULL && cj->progeny[4] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[3], cj->progeny[4], + s); + if (ci->progeny[3] != NULL && cj->progeny[6] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[3], cj->progeny[6], + s); + if (ci->progeny[5] != NULL && cj->progeny[0] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[5], cj->progeny[0], + s); + if (ci->progeny[5] != NULL && cj->progeny[2] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[5], cj->progeny[2], + s); + if (ci->progeny[5] != NULL && cj->progeny[4] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[5], cj->progeny[4], + s); + if (ci->progeny[5] != NULL && cj->progeny[6] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[5], cj->progeny[6], + s); + if (ci->progeny[7] != NULL && cj->progeny[0] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[7], cj->progeny[0], + s); + if (ci->progeny[7] != NULL && cj->progeny[2] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[7], cj->progeny[2], + s); + if (ci->progeny[7] != NULL && cj->progeny[4] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[7], cj->progeny[4], + s); + if (ci->progeny[7] != NULL && cj->progeny[6] != NULL) + cell_activate_subcell_stars_tasks(ci->progeny[7], cj->progeny[6], + s); + break; + } + + } + + /* Otherwise, activate the sorts and drifts. */ + else if (cell_is_active_stars(ci, e) || cell_is_active_stars(cj, e)) { + + /* We are going to interact this pair, so store some values. */ + atomic_or(&ci->hydro.requires_sorts, 1 << sid); + atomic_or(&cj->hydro.requires_sorts, 1 << sid); + ci->hydro.dx_max_sort_old = ci->hydro.dx_max_sort; + cj->hydro.dx_max_sort_old = cj->hydro.dx_max_sort; + + /* Activate the drifts if the cells are local. */ + if (ci->nodeID == engine_rank) cell_activate_drift_part(ci, s); + if (ci->nodeID == engine_rank) cell_activate_drift_spart(ci, s); + if (cj->nodeID == engine_rank) cell_activate_drift_part(cj, s); + if (cj->nodeID == engine_rank) cell_activate_drift_spart(cj, s); + + /* Do we need to sort the cells? */ + cell_activate_sorts(ci, sid, s); + cell_activate_sorts(cj, sid, s); + } + } /* Otherwise, pair interation */ } /** @@ -2049,7 +2447,7 @@ void cell_activate_subcell_grav_tasks(struct cell *ci, struct cell *cj, if (cj == NULL) { /* Do anything? */ - if (ci->gcount == 0 || !cell_is_active_gravity(ci, e)) return; + if (ci->grav.count == 0 || !cell_is_active_gravity(ci, e)) return; /* Recurse? */ if (ci->split) { @@ -2077,17 +2475,17 @@ void cell_activate_subcell_grav_tasks(struct cell *ci, struct cell *cj, /* Anything to do here? */ if (!cell_is_active_gravity(ci, e) && !cell_is_active_gravity(cj, e)) return; - if (ci->gcount == 0 || cj->gcount == 0) return; + if (ci->grav.count == 0 || cj->grav.count == 0) return; /* Atomically drift the multipole in ci */ - lock_lock(&ci->mlock); - if (ci->ti_old_multipole < e->ti_current) cell_drift_multipole(ci, e); - if (lock_unlock(&ci->mlock) != 0) error("Impossible to unlock m-pole"); + lock_lock(&ci->grav.mlock); + if (ci->grav.ti_old_multipole < e->ti_current) cell_drift_multipole(ci, e); + if (lock_unlock(&ci->grav.mlock) != 0) error("Impossible to unlock m-pole"); /* Atomically drift the multipole in cj */ - lock_lock(&cj->mlock); - if (cj->ti_old_multipole < e->ti_current) cell_drift_multipole(cj, e); - if (lock_unlock(&cj->mlock) != 0) error("Impossible to unlock m-pole"); + lock_lock(&cj->grav.mlock); + if (cj->grav.ti_old_multipole < e->ti_current) cell_drift_multipole(cj, e); + if (lock_unlock(&cj->grav.mlock) != 0) error("Impossible to unlock m-pole"); /* Can we use multipoles ? */ if (cell_can_use_pair_mm(ci, cj, e, sp)) { @@ -2108,8 +2506,8 @@ void cell_activate_subcell_grav_tasks(struct cell *ci, struct cell *cj, else { /* Recover the multipole information */ - const struct gravity_tensors *const multi_i = ci->multipole; - const struct gravity_tensors *const multi_j = cj->multipole; + const struct gravity_tensors *const multi_i = ci->grav.multipole; + const struct gravity_tensors *const multi_j = cj->grav.multipole; const double ri_max = multi_i->r_max; const double rj_max = multi_j->r_max; @@ -2207,7 +2605,7 @@ int cell_unskip_hydro_tasks(struct cell *c, struct scheduler *s) { int rebuild = 0; /* Un-skip the density tasks involved with this cell. */ - for (struct link *l = c->density; l != NULL; l = l->next) { + for (struct link *l = c->hydro.density; l != NULL; l = l->next) { struct task *t = l->t; struct cell *ci = t->ci; struct cell *cj = t->cj; @@ -2234,10 +2632,10 @@ int cell_unskip_hydro_tasks(struct cell *c, struct scheduler *s) { /* Set the correct sorting flags and activate hydro drifts */ else if (t->type == task_type_pair) { /* Store some values. */ - atomic_or(&ci->requires_sorts, 1 << t->flags); - atomic_or(&cj->requires_sorts, 1 << t->flags); - ci->dx_max_sort_old = ci->dx_max_sort; - cj->dx_max_sort_old = cj->dx_max_sort; + atomic_or(&ci->hydro.requires_sorts, 1 << t->flags); + atomic_or(&cj->hydro.requires_sorts, 1 << t->flags); + ci->hydro.dx_max_sort_old = ci->hydro.dx_max_sort; + cj->hydro.dx_max_sort_old = cj->hydro.dx_max_sort; /* Activate the drift tasks. */ if (ci_nodeID == nodeID) cell_activate_drift_part(ci, s); @@ -2266,23 +2664,23 @@ int cell_unskip_hydro_tasks(struct cell *c, struct scheduler *s) { /* If the local cell is active, receive data from the foreign cell. */ if (cj_active) { - scheduler_activate(s, ci->recv_xv); + scheduler_activate(s, ci->mpi.hydro.recv_xv); if (ci_active) { - scheduler_activate(s, ci->recv_rho); + scheduler_activate(s, ci->mpi.hydro.recv_rho); #ifdef EXTRA_HYDRO_LOOP - scheduler_activate(s, ci->recv_gradient); + scheduler_activate(s, ci->mpi.hydro.recv_gradient); #endif } } /* If the foreign cell is active, we want its ti_end values. */ - if (ci_active) scheduler_activate(s, ci->recv_ti); + if (ci_active) scheduler_activate(s, ci->mpi.recv_ti); /* Is the foreign cell active and will need stuff from us? */ if (ci_active) { - scheduler_activate_send(s, cj->send_xv, ci_nodeID); + scheduler_activate_send(s, cj->mpi.hydro.send_xv, ci_nodeID); /* Drift the cell which will be sent; note that not all sent particles will be drifted, only those that are needed. */ @@ -2290,38 +2688,38 @@ int cell_unskip_hydro_tasks(struct cell *c, struct scheduler *s) { /* If the local cell is also active, more stuff will be needed. */ if (cj_active) { - scheduler_activate_send(s, cj->send_rho, ci_nodeID); + scheduler_activate_send(s, cj->mpi.hydro.send_rho, ci_nodeID); #ifdef EXTRA_HYDRO_LOOP - scheduler_activate_send(s, cj->send_gradient, ci_nodeID); + scheduler_activate_send(s, cj->mpi.hydro.send_gradient, ci_nodeID); #endif } } /* If the local cell is active, send its ti_end values. */ - if (cj_active) scheduler_activate_send(s, cj->send_ti, ci_nodeID); + if (cj_active) scheduler_activate_send(s, cj->mpi.send_ti, ci_nodeID); } else if (cj_nodeID != nodeID) { /* If the local cell is active, receive data from the foreign cell. */ if (ci_active) { - scheduler_activate(s, cj->recv_xv); + scheduler_activate(s, cj->mpi.hydro.recv_xv); if (cj_active) { - scheduler_activate(s, cj->recv_rho); + scheduler_activate(s, cj->mpi.hydro.recv_rho); #ifdef EXTRA_HYDRO_LOOP - scheduler_activate(s, cj->recv_gradient); + scheduler_activate(s, cj->mpi.hydro.recv_gradient); #endif } } /* If the foreign cell is active, we want its ti_end values. */ - if (cj_active) scheduler_activate(s, cj->recv_ti); + if (cj_active) scheduler_activate(s, cj->mpi.recv_ti); /* Is the foreign cell active and will need stuff from us? */ if (cj_active) { - scheduler_activate_send(s, ci->send_xv, cj_nodeID); + scheduler_activate_send(s, ci->mpi.hydro.send_xv, cj_nodeID); /* Drift the cell which will be sent; note that not all sent particles will be drifted, only those that are needed. */ @@ -2330,16 +2728,16 @@ int cell_unskip_hydro_tasks(struct cell *c, struct scheduler *s) { /* If the local cell is also active, more stuff will be needed. */ if (ci_active) { - scheduler_activate_send(s, ci->send_rho, cj_nodeID); + scheduler_activate_send(s, ci->mpi.hydro.send_rho, cj_nodeID); #ifdef EXTRA_HYDRO_LOOP - scheduler_activate_send(s, ci->send_gradient, cj_nodeID); + scheduler_activate_send(s, ci->mpi.hydro.send_gradient, cj_nodeID); #endif } } /* If the local cell is active, send its ti_end values. */ - if (ci_active) scheduler_activate_send(s, ci->send_ti, cj_nodeID); + if (ci_active) scheduler_activate_send(s, ci->mpi.send_ti, cj_nodeID); } #endif } @@ -2348,21 +2746,25 @@ int cell_unskip_hydro_tasks(struct cell *c, struct scheduler *s) { /* Unskip all the other task types. */ if (c->nodeID == nodeID && cell_is_active_hydro(c, e)) { - for (struct link *l = c->gradient; l != NULL; l = l->next) + for (struct link *l = c->hydro.gradient; l != NULL; l = l->next) scheduler_activate(s, l->t); - for (struct link *l = c->force; l != NULL; l = l->next) + for (struct link *l = c->hydro.force; l != NULL; l = l->next) scheduler_activate(s, l->t); - if (c->extra_ghost != NULL) scheduler_activate(s, c->extra_ghost); - if (c->ghost_in != NULL) scheduler_activate(s, c->ghost_in); - if (c->ghost_out != NULL) scheduler_activate(s, c->ghost_out); - if (c->ghost != NULL) scheduler_activate(s, c->ghost); + if (c->hydro.extra_ghost != NULL) + scheduler_activate(s, c->hydro.extra_ghost); + if (c->hydro.ghost_in != NULL) scheduler_activate(s, c->hydro.ghost_in); + if (c->hydro.ghost_out != NULL) scheduler_activate(s, c->hydro.ghost_out); + if (c->hydro.ghost != NULL) scheduler_activate(s, c->hydro.ghost); if (c->kick1 != NULL) scheduler_activate(s, c->kick1); if (c->kick2 != NULL) scheduler_activate(s, c->kick2); if (c->timestep != NULL) scheduler_activate(s, c->timestep); if (c->end_force != NULL) scheduler_activate(s, c->end_force); - if (c->cooling != NULL) scheduler_activate(s, c->cooling); + if (c->hydro.cooling != NULL) scheduler_activate(s, c->hydro.cooling); + if (c->hydro.star_formation != NULL) + scheduler_activate(s, c->hydro.star_formation); if (c->sourceterms != NULL) scheduler_activate(s, c->sourceterms); + if (c->logger != NULL) scheduler_activate(s, c->logger); } return rebuild; @@ -2384,7 +2786,7 @@ int cell_unskip_gravity_tasks(struct cell *c, struct scheduler *s) { int rebuild = 0; /* Un-skip the gravity tasks involved with this cell. */ - for (struct link *l = c->grav; l != NULL; l = l->next) { + for (struct link *l = c->grav.grav; l != NULL; l = l->next) { struct task *t = l->t; struct cell *ci = t->ci; struct cell *cj = t->cj; @@ -2426,15 +2828,15 @@ int cell_unskip_gravity_tasks(struct cell *c, struct scheduler *s) { if (ci_nodeID != nodeID) { /* If the local cell is active, receive data from the foreign cell. */ - if (cj_active) scheduler_activate(s, ci->recv_grav); + if (cj_active) scheduler_activate(s, ci->mpi.grav.recv); /* If the foreign cell is active, we want its ti_end values. */ - if (ci_active) scheduler_activate(s, ci->recv_ti); + if (ci_active) scheduler_activate(s, ci->mpi.recv_ti); /* Is the foreign cell active and will need stuff from us? */ if (ci_active) { - scheduler_activate_send(s, cj->send_grav, ci_nodeID); + scheduler_activate_send(s, cj->mpi.grav.send, ci_nodeID); /* Drift the cell which will be sent at the level at which it is sent, i.e. drift the cell specified in the send task (l->t) @@ -2443,20 +2845,20 @@ int cell_unskip_gravity_tasks(struct cell *c, struct scheduler *s) { } /* If the local cell is active, send its ti_end values. */ - if (cj_active) scheduler_activate_send(s, cj->send_ti, ci_nodeID); + if (cj_active) scheduler_activate_send(s, cj->mpi.send_ti, ci_nodeID); } else if (cj_nodeID != nodeID) { /* If the local cell is active, receive data from the foreign cell. */ - if (ci_active) scheduler_activate(s, cj->recv_grav); + if (ci_active) scheduler_activate(s, cj->mpi.grav.recv); /* If the foreign cell is active, we want its ti_end values. */ - if (cj_active) scheduler_activate(s, cj->recv_ti); + if (cj_active) scheduler_activate(s, cj->mpi.recv_ti); /* Is the foreign cell active and will need stuff from us? */ if (cj_active) { - scheduler_activate_send(s, ci->send_grav, cj_nodeID); + scheduler_activate_send(s, ci->mpi.grav.send, cj_nodeID); /* Drift the cell which will be sent at the level at which it is sent, i.e. drift the cell specified in the send task (l->t) @@ -2465,13 +2867,13 @@ int cell_unskip_gravity_tasks(struct cell *c, struct scheduler *s) { } /* If the local cell is active, send its ti_end values. */ - if (ci_active) scheduler_activate_send(s, ci->send_ti, cj_nodeID); + if (ci_active) scheduler_activate_send(s, ci->mpi.send_ti, cj_nodeID); } #endif } } - for (struct link *l = c->grav_mm; l != NULL; l = l->next) { + for (struct link *l = c->grav.mm; l != NULL; l = l->next) { struct task *t = l->t; struct cell *ci = t->ci; @@ -2501,18 +2903,22 @@ int cell_unskip_gravity_tasks(struct cell *c, struct scheduler *s) { /* Unskip all the other task types. */ if (c->nodeID == nodeID && cell_is_active_gravity(c, e)) { - if (c->init_grav != NULL) scheduler_activate(s, c->init_grav); - if (c->init_grav_out != NULL) scheduler_activate(s, c->init_grav_out); + if (c->grav.init != NULL) scheduler_activate(s, c->grav.init); + if (c->grav.init_out != NULL) scheduler_activate(s, c->grav.init_out); if (c->kick1 != NULL) scheduler_activate(s, c->kick1); if (c->kick2 != NULL) scheduler_activate(s, c->kick2); if (c->timestep != NULL) scheduler_activate(s, c->timestep); if (c->end_force != NULL) scheduler_activate(s, c->end_force); - if ((e->policy & engine_policy_cooling) && c->cooling != NULL) - scheduler_activate(s, c->cooling); - if (c->grav_down != NULL) scheduler_activate(s, c->grav_down); - if (c->grav_down_in != NULL) scheduler_activate(s, c->grav_down_in); - if (c->grav_mesh != NULL) scheduler_activate(s, c->grav_mesh); - if (c->grav_long_range != NULL) scheduler_activate(s, c->grav_long_range); + if ((e->policy & engine_policy_cooling) && c->hydro.cooling != NULL) + scheduler_activate(s, c->hydro.cooling); + if ((e->policy & engine_policy_star_formation) && + c->hydro.star_formation != NULL) + scheduler_activate(s, c->hydro.star_formation); + if (c->grav.down != NULL) scheduler_activate(s, c->grav.down); + if (c->grav.down_in != NULL) scheduler_activate(s, c->grav.down_in); + if (c->grav.mesh != NULL) scheduler_activate(s, c->grav.mesh); + if (c->grav.long_range != NULL) scheduler_activate(s, c->grav.long_range); + if (c->logger != NULL) scheduler_activate(s, c->logger); } return rebuild; @@ -2533,7 +2939,7 @@ int cell_unskip_stars_tasks(struct cell *c, struct scheduler *s) { int rebuild = 0; /* Un-skip the density tasks involved with this cell. */ - for (struct link *l = c->stars_density; l != NULL; l = l->next) { + for (struct link *l = c->stars.density; l != NULL; l = l->next) { struct task *t = l->t; struct cell *ci = t->ci; struct cell *cj = t->cj; @@ -2554,10 +2960,10 @@ int cell_unskip_stars_tasks(struct cell *c, struct scheduler *s) { /* Set the correct sorting flags and activate hydro drifts */ else if (t->type == task_type_pair) { /* Store some values. */ - atomic_or(&ci->requires_sorts, 1 << t->flags); - atomic_or(&cj->requires_sorts, 1 << t->flags); - ci->dx_max_sort_old = ci->dx_max_sort; - cj->dx_max_sort_old = cj->dx_max_sort; + atomic_or(&ci->hydro.requires_sorts, 1 << t->flags); + atomic_or(&cj->hydro.requires_sorts, 1 << t->flags); + ci->hydro.dx_max_sort_old = ci->hydro.dx_max_sort; + cj->hydro.dx_max_sort_old = cj->hydro.dx_max_sort; /* Activate the drift tasks. */ if (ci->nodeID == nodeID) cell_activate_drift_part(ci, s); @@ -2588,20 +2994,20 @@ int cell_unskip_stars_tasks(struct cell *c, struct scheduler *s) { /* /\* If the local cell is active, receive data from the foreign cell. * *\/ */ /* if (cj_active) { */ - /* scheduler_activate(s, ci->recv_xv); */ + /* scheduler_activate(s, ci->hydro.recv_xv); */ /* if (ci_active) { */ - /* scheduler_activate(s, ci->recv_rho); */ + /* scheduler_activate(s, ci->hydro.recv_rho); */ /* } */ /* } */ /* /\* If the foreign cell is active, we want its ti_end values. *\/ */ - /* if (ci_active) scheduler_activate(s, ci->recv_ti); */ + /* if (ci_active) scheduler_activate(s, ci->mpi.recv_ti); */ /* /\* Is the foreign cell active and will need stuff from us? *\/ */ /* if (ci_active) { */ - /* scheduler_activate_send(s, cj->send_xv, ci->nodeID); */ + /* scheduler_activate_send(s, cj->hydro.send_xv, ci->nodeID); */ /* /\* Drift the cell which will be sent; note that not all sent */ /* particles will be drifted, only those that are needed. *\/ */ @@ -2610,13 +3016,14 @@ int cell_unskip_stars_tasks(struct cell *c, struct scheduler *s) { /* /\* If the local cell is also active, more stuff will be needed. * *\/ */ /* if (cj_active) { */ - /* scheduler_activate_send(s, cj->send_rho, ci->nodeID); */ + /* scheduler_activate_send(s, cj->hydro.send_rho, ci->nodeID); */ /* } */ /* } */ /* /\* If the local cell is active, send its ti_end values. *\/ */ - /* if (cj_active) scheduler_activate_send(s, cj->send_ti, ci->nodeID); + /* if (cj_active) scheduler_activate_send(s, cj->mpi.send_ti, + * ci->nodeID); */ /* } else if (cj->nodeID != nodeID) { */ @@ -2624,20 +3031,20 @@ int cell_unskip_stars_tasks(struct cell *c, struct scheduler *s) { /* /\* If the local cell is active, receive data from the foreign cell. * *\/ */ /* if (ci_active) { */ - /* scheduler_activate(s, cj->recv_xv); */ + /* scheduler_activate(s, cj->hydro.recv_xv); */ /* if (cj_active) { */ - /* scheduler_activate(s, cj->recv_rho); */ + /* scheduler_activate(s, cj->hydro.recv_rho); */ /* } */ /* } */ /* /\* If the foreign cell is active, we want its ti_end values. *\/ */ - /* if (cj_active) scheduler_activate(s, cj->recv_ti); */ + /* if (cj_active) scheduler_activate(s, cj->mpi.recv_ti); */ /* /\* Is the foreign cell active and will need stuff from us? *\/ */ /* if (cj_active) { */ - /* scheduler_activate_send(s, ci->send_xv, cj->nodeID); */ + /* scheduler_activate_send(s, ci->hydro.send_xv, cj->nodeID); */ /* /\* Drift the cell which will be sent; note that not all sent */ /* particles will be drifted, only those that are needed. *\/ */ @@ -2647,13 +3054,14 @@ int cell_unskip_stars_tasks(struct cell *c, struct scheduler *s) { * *\/ */ /* if (ci_active) { */ - /* scheduler_activate_send(s, ci->send_rho, cj->nodeID); */ + /* scheduler_activate_send(s, ci->hydro.send_rho, cj->nodeID); */ /* } */ /* } */ /* /\* If the local cell is active, send its ti_end values. *\/ */ - /* if (ci_active) scheduler_activate_send(s, ci->send_ti, cj->nodeID); + /* if (ci_active) scheduler_activate_send(s, ci->mpi.send_ti, + * cj->nodeID); */ /* } */ #endif @@ -2663,9 +3071,10 @@ int cell_unskip_stars_tasks(struct cell *c, struct scheduler *s) { /* Unskip all the other task types. */ if (c->nodeID == nodeID && cell_is_active_stars(c, e)) { - if (c->stars_ghost_in != NULL) scheduler_activate(s, c->stars_ghost_in); - if (c->stars_ghost_out != NULL) scheduler_activate(s, c->stars_ghost_out); - if (c->stars_ghost != NULL) scheduler_activate(s, c->stars_ghost); + if (c->stars.ghost_in != NULL) scheduler_activate(s, c->stars.ghost_in); + if (c->stars.ghost_out != NULL) scheduler_activate(s, c->stars.ghost_out); + if (c->stars.ghost != NULL) scheduler_activate(s, c->stars.ghost); + if (c->logger != NULL) scheduler_activate(s, c->logger); } return rebuild; @@ -2680,7 +3089,7 @@ int cell_unskip_stars_tasks(struct cell *c, struct scheduler *s) { void cell_set_super(struct cell *c, struct cell *super) { /* Are we in a cell with some kind of self/pair task ? */ - if (super == NULL && (c->nr_tasks > 0 || c->nr_mm_tasks > 0)) super = c; + if (super == NULL && (c->nr_tasks > 0 || c->grav.nr_mm_tasks > 0)) super = c; /* Set the super-cell */ c->super = super; @@ -2701,10 +3110,10 @@ void cell_set_super(struct cell *c, struct cell *super) { void cell_set_super_hydro(struct cell *c, struct cell *super_hydro) { /* Are we in a cell with some kind of self/pair task ? */ - if (super_hydro == NULL && c->density != NULL) super_hydro = c; + if (super_hydro == NULL && c->hydro.density != NULL) super_hydro = c; /* Set the super-cell */ - c->super_hydro = super_hydro; + c->hydro.super = super_hydro; /* Recurse */ if (c->split) @@ -2723,11 +3132,11 @@ void cell_set_super_hydro(struct cell *c, struct cell *super_hydro) { void cell_set_super_gravity(struct cell *c, struct cell *super_gravity) { /* Are we in a cell with some kind of self/pair task ? */ - if (super_gravity == NULL && (c->grav != NULL || c->grav_mm != NULL)) + if (super_gravity == NULL && (c->grav.grav != NULL || c->grav.mm != NULL)) super_gravity = c; /* Set the super-cell */ - c->super_gravity = super_gravity; + c->grav.super = super_gravity; /* Recurse */ if (c->split) @@ -2752,7 +3161,7 @@ void cell_set_super_mapper(void *map_data, int num_elements, void *extra_data) { /* All top-level cells get an MPI tag. */ #ifdef WITH_MPI - if (c->tag < 0 && c->sendto) cell_tag(c); + if (c->mpi.tag < 0 && c->mpi.sendto) cell_tag(c); #endif /* Super-pointer for hydro */ @@ -2779,7 +3188,7 @@ void cell_set_super_mapper(void *map_data, int num_elements, void *extra_data) { int cell_has_tasks(struct cell *c) { #ifdef WITH_MPI - if (c->timestep != NULL || c->recv_ti != NULL) return 1; + if (c->timestep != NULL || c->mpi.recv_ti != NULL) return 1; #else if (c->timestep != NULL) return 1; #endif @@ -2804,17 +3213,17 @@ int cell_has_tasks(struct cell *c) { void cell_drift_part(struct cell *c, const struct engine *e, int force) { const float hydro_h_max = e->hydro_properties->h_max; - const integertime_t ti_old_part = c->ti_old_part; + const integertime_t ti_old_part = c->hydro.ti_old_part; const integertime_t ti_current = e->ti_current; - struct part *const parts = c->parts; - struct xpart *const xparts = c->xparts; + struct part *const parts = c->hydro.parts; + struct xpart *const xparts = c->hydro.xparts; float dx_max = 0.f, dx2_max = 0.f; float dx_max_sort = 0.0f, dx2_max_sort = 0.f; float cell_h_max = 0.f; /* Drift irrespective of cell flags? */ - force |= c->do_drift; + force |= c->hydro.do_drift; #ifdef SWIFT_DEBUG_CHECKS /* Check that we only drift local cells. */ @@ -2825,7 +3234,7 @@ void cell_drift_part(struct cell *c, const struct engine *e, int force) { #endif /* Are we not in a leaf ? */ - if (c->split && (force || c->do_sub_drift)) { + if (c->split && (force || c->hydro.do_sub_drift)) { /* Loop over the progeny and collect their data. */ for (int k = 0; k < 8; k++) { @@ -2836,19 +3245,19 @@ void cell_drift_part(struct cell *c, const struct engine *e, int force) { cell_drift_part(cp, e, force); /* Update */ - dx_max = max(dx_max, cp->dx_max_part); - dx_max_sort = max(dx_max_sort, cp->dx_max_sort); - cell_h_max = max(cell_h_max, cp->h_max); + dx_max = max(dx_max, cp->hydro.dx_max_part); + dx_max_sort = max(dx_max_sort, cp->hydro.dx_max_sort); + cell_h_max = max(cell_h_max, cp->hydro.h_max); } } /* Store the values */ - c->h_max = cell_h_max; - c->dx_max_part = dx_max; - c->dx_max_sort = dx_max_sort; + c->hydro.h_max = cell_h_max; + c->hydro.dx_max_part = dx_max; + c->hydro.dx_max_sort = dx_max_sort; /* Update the time of the last drift */ - c->ti_old_part = ti_current; + c->hydro.ti_old_part = ti_current; } else if (!c->split && force && ti_current > ti_old_part) { @@ -2871,13 +3280,16 @@ void cell_drift_part(struct cell *c, const struct engine *e, int force) { } /* Loop over all the gas particles in the cell */ - const size_t nr_parts = c->count; + const size_t nr_parts = c->hydro.count; for (size_t k = 0; k < nr_parts; k++) { /* Get a handle on the part. */ struct part *const p = &parts[k]; struct xpart *const xp = &xparts[k]; + /* Ignore inhibited particles */ + if (part_is_inhibited(p, e)) continue; + /* Drift... */ drift_part(p, xp, dt_drift, dt_kick_hydro, dt_kick_grav, dt_therm, ti_old_part, ti_current); @@ -2949,17 +3361,17 @@ void cell_drift_part(struct cell *c, const struct engine *e, int force) { dx_max_sort = sqrtf(dx2_max_sort); /* Store the values */ - c->h_max = cell_h_max; - c->dx_max_part = dx_max; - c->dx_max_sort = dx_max_sort; + c->hydro.h_max = cell_h_max; + c->hydro.dx_max_part = dx_max; + c->hydro.dx_max_sort = dx_max_sort; /* Update the time of the last drift */ - c->ti_old_part = ti_current; + c->hydro.ti_old_part = ti_current; } /* Clear the drift flags. */ - c->do_drift = 0; - c->do_sub_drift = 0; + c->hydro.do_drift = 0; + c->hydro.do_sub_drift = 0; } /** @@ -2971,13 +3383,17 @@ void cell_drift_part(struct cell *c, const struct engine *e, int force) { */ void cell_drift_gpart(struct cell *c, const struct engine *e, int force) { - const integertime_t ti_old_gpart = c->ti_old_gpart; + const float stars_h_max = e->stars_properties->h_max; + const integertime_t ti_old_gpart = c->grav.ti_old_part; const integertime_t ti_current = e->ti_current; - struct gpart *const gparts = c->gparts; - struct spart *const sparts = c->sparts; + struct gpart *const gparts = c->grav.parts; + struct spart *const sparts = c->stars.parts; + + float dx_max = 0.f, dx2_max = 0.f; + float cell_h_max = 0.f; /* Drift irrespective of cell flags? */ - force |= c->do_grav_drift; + force |= c->grav.do_drift; #ifdef SWIFT_DEBUG_CHECKS /* Check that we only drift local cells. */ @@ -2988,7 +3404,7 @@ void cell_drift_gpart(struct cell *c, const struct engine *e, int force) { #endif /* Are we not in a leaf ? */ - if (c->split && (force || c->do_grav_sub_drift)) { + if (c->split && (force || c->grav.do_sub_drift)) { /* Loop over the progeny and collect their data. */ for (int k = 0; k < 8; k++) { @@ -2997,11 +3413,19 @@ void cell_drift_gpart(struct cell *c, const struct engine *e, int force) { /* Recurse */ cell_drift_gpart(cp, e, force); + + /* Update */ + dx_max = max(dx_max, cp->stars.dx_max_part); + cell_h_max = max(cell_h_max, cp->stars.h_max); } } + /* Store the values */ + c->stars.h_max = cell_h_max; + c->stars.dx_max_part = dx_max; + /* Update the time of the last drift */ - c->ti_old_gpart = ti_current; + c->grav.ti_old_part = ti_current; } else if (!c->split && force && ti_current > ti_old_gpart) { @@ -3014,12 +3438,15 @@ void cell_drift_gpart(struct cell *c, const struct engine *e, int force) { dt_drift = (ti_current - ti_old_gpart) * e->time_base; /* Loop over all the g-particles in the cell */ - const size_t nr_gparts = c->gcount; + const size_t nr_gparts = c->grav.count; for (size_t k = 0; k < nr_gparts; k++) { /* Get a handle on the gpart. */ struct gpart *const gp = &gparts[k]; + /* Ignore inhibited particles */ + if (gpart_is_inhibited(gp, e)) continue; + /* Drift... */ drift_gpart(gp, dt_drift, ti_old_gpart, ti_current); @@ -3059,12 +3486,15 @@ void cell_drift_gpart(struct cell *c, const struct engine *e, int force) { } /* Loop over all the star particles in the cell */ - const size_t nr_sparts = c->scount; + const size_t nr_sparts = c->stars.count; for (size_t k = 0; k < nr_sparts; k++) { /* Get a handle on the spart. */ struct spart *const sp = &sparts[k]; + /* Ignore inhibited particles */ + if (spart_is_inhibited(sp, e)) continue; + /* Drift... */ drift_spart(sp, dt_drift, ti_old_gpart, ti_current); @@ -3077,16 +3507,34 @@ void cell_drift_gpart(struct cell *c, const struct engine *e, int force) { } #endif - /* Note: no need to compute dx_max as all spart have a gpart */ - } + /* Limit h to within the allowed range */ + sp->h = min(sp->h, stars_h_max); + + /* Compute (square of) motion since last cell construction */ + const float dx2 = sp->x_diff[0] * sp->x_diff[0] + + sp->x_diff[1] * sp->x_diff[1] + + sp->x_diff[2] * sp->x_diff[2]; + dx2_max = max(dx2_max, dx2); + + /* Maximal smoothing length */ + cell_h_max = max(cell_h_max, sp->h); + + } /* Note: no need to compute dx_max as all spart have a gpart */ + + /* Now, get the maximal particle motion from its square */ + dx_max = sqrtf(dx2_max); + + /* Store the values */ + c->stars.h_max = cell_h_max; + c->stars.dx_max_part = dx_max; /* Update the time of the last drift */ - c->ti_old_gpart = ti_current; + c->grav.ti_old_part = ti_current; } /* Clear the drift flags. */ - c->do_grav_drift = 0; - c->do_grav_sub_drift = 0; + c->grav.do_drift = 0; + c->grav.do_sub_drift = 0; } /** @@ -3097,7 +3545,7 @@ void cell_drift_gpart(struct cell *c, const struct engine *e, int force) { */ void cell_drift_all_multipoles(struct cell *c, const struct engine *e) { - const integertime_t ti_old_multipole = c->ti_old_multipole; + const integertime_t ti_old_multipole = c->grav.ti_old_multipole; const integertime_t ti_current = e->ti_current; #ifdef SWIFT_DEBUG_CHECKS @@ -3114,7 +3562,7 @@ void cell_drift_all_multipoles(struct cell *c, const struct engine *e) { dt_drift = (ti_current - ti_old_multipole) * e->time_base; /* Drift the multipole */ - if (ti_current > ti_old_multipole) gravity_drift(c->multipole, dt_drift); + if (ti_current > ti_old_multipole) gravity_drift(c->grav.multipole, dt_drift); /* Are we not in a leaf ? */ if (c->split) { @@ -3125,7 +3573,7 @@ void cell_drift_all_multipoles(struct cell *c, const struct engine *e) { } /* Update the time of the last drift */ - c->ti_old_multipole = ti_current; + c->grav.ti_old_multipole = ti_current; } /** @@ -3139,7 +3587,7 @@ void cell_drift_all_multipoles(struct cell *c, const struct engine *e) { */ void cell_drift_multipole(struct cell *c, const struct engine *e) { - const integertime_t ti_old_multipole = c->ti_old_multipole; + const integertime_t ti_old_multipole = c->grav.ti_old_multipole; const integertime_t ti_current = e->ti_current; #ifdef SWIFT_DEBUG_CHECKS @@ -3155,10 +3603,10 @@ void cell_drift_multipole(struct cell *c, const struct engine *e) { else dt_drift = (ti_current - ti_old_multipole) * e->time_base; - if (ti_current > ti_old_multipole) gravity_drift(c->multipole, dt_drift); + if (ti_current > ti_old_multipole) gravity_drift(c->grav.multipole, dt_drift); /* Update the time of the last drift */ - c->ti_old_multipole = ti_current; + c->grav.ti_old_multipole = ti_current; } /** @@ -3167,7 +3615,7 @@ void cell_drift_multipole(struct cell *c, const struct engine *e) { void cell_check_timesteps(struct cell *c) { #ifdef SWIFT_DEBUG_CHECKS - if (c->ti_hydro_end_min == 0 && c->ti_gravity_end_min == 0 && c->nr_tasks > 0) + if (c->hydro.ti_end_min == 0 && c->grav.ti_end_min == 0 && c->nr_tasks > 0) error("Cell without assigned time-step"); if (c->split) { @@ -3176,8 +3624,8 @@ void cell_check_timesteps(struct cell *c) { } else { if (c->nodeID == engine_rank) - for (int i = 0; i < c->count; ++i) - if (c->parts[i].time_bin == 0) + for (int i = 0; i < c->hydro.count; ++i) + if (c->hydro.parts[i].time_bin == 0) error("Particle without assigned time-bin"); } #else @@ -3185,6 +3633,165 @@ void cell_check_timesteps(struct cell *c) { #endif } +/** + * @brief "Remove" a gas particle from the calculation. + * + * 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. + */ +void cell_remove_part(const 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."); + + /* Mark the particle as inhibited */ + p->time_bin = time_bin_inhibited; + + /* Mark the gpart as inhibited and stand-alone */ + if (p->gpart) { + p->gpart->time_bin = time_bin_inhibited; + p->gpart->id_or_neg_offset = p->id; + p->gpart->type = swift_type_dark_matter; + } + + /* Un-link the part */ + p->gpart = NULL; +} + +/** + * @brief "Remove" a gravity particle from the calculation. + * + * 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 gp The #gpart to remove. + */ +void cell_remove_gpart(const struct engine *e, struct cell *c, + struct gpart *gp) { + + /* Quick cross-check */ + if (c->nodeID != e->nodeID) + error("Can't remove a particle in a foreign cell."); + + if (gp->type != swift_type_dark_matter) + error("Trying to remove a non-dark matter gpart."); + + /* Mark the particle as inhibited */ + gp->time_bin = time_bin_inhibited; +} + +/** + * @brief "Remove" a star particle from the calculation. + * + * 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. + */ +void cell_remove_spart(const struct engine *e, struct cell *c, + struct spart *sp) { + + /* Quick cross-check */ + if (c->nodeID != e->nodeID) + error("Can't remove a particle in a foreign cell."); + + /* Mark the particle as inhibited and stand-alone */ + sp->time_bin = time_bin_inhibited; + if (sp->gpart) { + sp->gpart->time_bin = time_bin_inhibited; + sp->gpart->id_or_neg_offset = sp->id; + sp->gpart->type = swift_type_dark_matter; + } + + /* Un-link the spart */ + sp->gpart = NULL; +} + +/** + * @brief "Remove" a gas particle from the calculation and convert its gpart + * friend to a dark matter particle. + * + * 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. + */ +void 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) + error("Can't remove a particle in a foreign cell."); + + if (p->gpart == NULL) + error("Trying to convert part without gpart friend to dark matter!"); + + /* Get a handle */ + struct gpart *gp = p->gpart; + + /* Mark the particle as inhibited */ + p->time_bin = time_bin_inhibited; + + /* Un-link the part */ + p->gpart = NULL; + + /* Mark the gpart as dark matter */ + gp->type = swift_type_dark_matter; + gp->id_or_neg_offset = p->id; + +#ifdef SWIFT_DEBUG_CHECKS + gp->ti_kick = p->ti_kick; +#endif +} + +/** + * @brief "Remove" a spart particle from the calculation and convert its gpart + * friend to a dark matter particle. + * + * 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. + */ +void cell_convert_spart_to_gpart(const struct engine *e, struct cell *c, + struct spart *sp) { + + /* Quick cross-check */ + if (c->nodeID != e->nodeID) + error("Can't remove a particle in a foreign cell."); + + if (sp->gpart == NULL) + error("Trying to convert spart without gpart friend to dark matter!"); + + /* Get a handle */ + struct gpart *gp = sp->gpart; + + /* Mark the particle as inhibited */ + sp->time_bin = time_bin_inhibited; + + /* Un-link the spart */ + sp->gpart = NULL; + + /* Mark the gpart as dark matter */ + gp->type = swift_type_dark_matter; + gp->id_or_neg_offset = sp->id; + +#ifdef SWIFT_DEBUG_CHECKS + gp->ti_kick = sp->ti_kick; +#endif +} + /** * @brief Can we use the MM interactions fo a given pair of cells? * @@ -3201,8 +3808,8 @@ int cell_can_use_pair_mm(const struct cell *ci, const struct cell *cj, const double dim[3] = {s->dim[0], s->dim[1], s->dim[2]}; /* Recover the multipole information */ - const struct gravity_tensors *const multi_i = ci->multipole; - const struct gravity_tensors *const multi_j = cj->multipole; + const struct gravity_tensors *const multi_i = ci->grav.multipole; + const struct gravity_tensors *const multi_j = cj->grav.multipole; /* Get the distance between the CoMs */ double dx = multi_i->CoM[0] - multi_j->CoM[0]; @@ -3240,8 +3847,8 @@ int cell_can_use_pair_mm_rebuild(const struct cell *ci, const struct cell *cj, const double dim[3] = {s->dim[0], s->dim[1], s->dim[2]}; /* Recover the multipole information */ - const struct gravity_tensors *const multi_i = ci->multipole; - const struct gravity_tensors *const multi_j = cj->multipole; + const struct gravity_tensors *const multi_i = ci->grav.multipole; + const struct gravity_tensors *const multi_j = cj->grav.multipole; #ifdef SWIFT_DEBUG_CHECKS diff --git a/src/cell.h b/src/cell.h index 373a10b04a4a0e28a8735ea8089e86e022e725d2..89f7c954c29f23845cb9c876b93c6bb3d469fbe5 100644 --- a/src/cell.h +++ b/src/cell.h @@ -77,62 +77,80 @@ struct link { */ struct pcell { - /*! This cell's gravity-related tensors */ - struct multipole m_pole; + /*! Hydro variables */ + struct { - /*! Centre of mass. */ - double CoM[3]; + /*! Maximal smoothing length. */ + double h_max; - /*! Centre of mass at rebuild time. */ - double CoM_rebuild[3]; + /*! Minimal integer end-of-timestep in this cell for hydro tasks */ + integertime_t ti_end_min; - /*! Upper limit of the CoM<->gpart distance. */ - double r_max; + /*! Maximal integer end-of-timestep in this cell for hydro tasks */ + integertime_t ti_end_max; - /*! Upper limit of the CoM<->gpart distance at last rebuild. */ - double r_max_rebuild; + /*! Maximal integer beginning-of-timestep in this cell for hydro tasks */ + integertime_t ti_beg_max; - /*! Relative indices of the cell's progeny. */ - int progeny[8]; + /*! Integer time of the last drift of the #part in this cell */ + integertime_t ti_old_part; + + /*! Number of #part in this cell. */ + int count; + + } hydro; + + /*! Gravity variables */ + struct { + + /*! This cell's gravity-related tensors */ + struct multipole m_pole; + + /*! Centre of mass. */ + double CoM[3]; + + /*! Centre of mass at rebuild time. */ + double CoM_rebuild[3]; - /*! Maximal smoothing length. */ - double h_max; + /*! Upper limit of the CoM<->gpart distance. */ + double r_max; - /*! Minimal integer end-of-timestep in this cell for hydro tasks */ - integertime_t ti_hydro_end_min; + /*! Upper limit of the CoM<->gpart distance at last rebuild. */ + double r_max_rebuild; - /*! Maximal integer end-of-timestep in this cell for hydro tasks */ - integertime_t ti_hydro_end_max; + /*! Minimal integer end-of-timestep in this cell for gravity tasks */ + integertime_t ti_end_min; - /*! Maximal integer beginning-of-timestep in this cell for hydro tasks */ - integertime_t ti_hydro_beg_max; + /*! Maximal integer end-of-timestep in this cell for gravity tasks */ + integertime_t ti_end_max; - /*! Minimal integer end-of-timestep in this cell for gravity tasks */ - integertime_t ti_gravity_end_min; + /*! Maximal integer beginning-of-timestep in this cell for gravity tasks */ + integertime_t ti_beg_max; - /*! Maximal integer end-of-timestep in this cell for gravity tasks */ - integertime_t ti_gravity_end_max; + /*! Integer time of the last drift of the #gpart in this cell */ + integertime_t ti_old_part; - /*! Maximal integer beginning-of-timestep in this cell for gravity tasks */ - integertime_t ti_gravity_beg_max; + /*! Integer time of the last drift of the #multipole in this cell */ + integertime_t ti_old_multipole; - /*! Integer time of the last drift of the #part in this cell */ - integertime_t ti_old_part; + /*! Number of #gpart in this cell. */ + int count; - /*! Integer time of the last drift of the #gpart in this cell */ - integertime_t ti_old_gpart; + } grav; - /*! Integer time of the last drift of the #multipole in this cell */ - integertime_t ti_old_multipole; + /*! Stars variables */ + struct { - /*! Number of #part in this cell. */ - int count; + /*! Number of #spart in this cell. */ + int count; - /*! Number of #gpart in this cell. */ - int gcount; + /*! Maximal smoothing length. */ + double h_max; - /*! Number of #spart in this cell. */ - int scount; + } stars; + + /*! Relative indices of the cell's progeny. */ + int progeny[8]; #ifdef SWIFT_DEBUG_CHECKS /* Cell ID (for debugging) */ @@ -146,20 +164,38 @@ struct pcell { */ struct pcell_step { - /*! Minimal integer end-of-timestep in this cell (hydro) */ - integertime_t ti_hydro_end_min; + /*! Hydro variables */ + struct { + + /*! Minimal integer end-of-timestep in this cell (hydro) */ + integertime_t ti_end_min; + + /*! Minimal integer end-of-timestep in this cell (hydro) */ + integertime_t ti_end_max; + + /*! Maximal distance any #part has travelled since last rebuild */ + float dx_max_part; + + } hydro; + + /*! Grav variables */ + struct { - /*! Minimal integer end-of-timestep in this cell (hydro) */ - integertime_t ti_hydro_end_max; + /*! Minimal integer end-of-timestep in this cell (gravity) */ + integertime_t ti_end_min; - /*! Minimal integer end-of-timestep in this cell (gravity) */ - integertime_t ti_gravity_end_min; + /*! Minimal integer end-of-timestep in this cell (gravity) */ + integertime_t ti_end_max; - /*! Minimal integer end-of-timestep in this cell (gravity) */ - integertime_t ti_gravity_end_max; + } grav; - /*! Maximal distance any #part has travelled since last rebuild */ - float dx_max_part; + /*! Stars variables */ + struct { + + /*! Maximal distance any #part has travelled since last rebuild */ + float dx_max_part; + + } stars; }; /** @@ -175,30 +211,9 @@ struct cell { /*! The cell dimensions. */ double width[3]; - /*! Max smoothing length in this cell. */ - double h_max; - - /*! This cell's multipole. */ - struct gravity_tensors *multipole; - /*! Linking pointer for "memory management". */ struct cell *next; - /*! Pointer to the #part data. */ - struct part *parts; - - /*! Pointer to the #xpart data. */ - struct xpart *xparts; - - /*! Pointer to the #gpart data. */ - struct gpart *gparts; - - /*! Pointer to the #spart data. */ - struct spart *sparts; - - /*! Pointer for the sorted indices. */ - struct entry *sort[13]; - /*! Pointers to the next level of cells. */ struct cell *progeny[8]; @@ -208,253 +223,348 @@ struct cell { /*! Super cell, i.e. the highest-level parent cell with *any* task */ struct cell *super; - /*! Super cell, i.e. the highest-level parent cell that has a hydro pair/self - * tasks */ - struct cell *super_hydro; + /*! Hydro variables */ + struct { - /*! Super cell, i.e. the highest-level parent cell that has a grav pair/self - * tasks */ - struct cell *super_gravity; + /*! Pointer to the #part data. */ + struct part *parts; - /*! Linked list of the tasks computing this cell's hydro density. */ - struct link *density; + /*! Pointer to the #xpart data. */ + struct xpart *xparts; - /* Linked list of the tasks computing this cell's hydro gradients. */ - struct link *gradient; + /*! Pointer for the sorted indices. */ + struct entry *sort[13]; - /*! Linked list of the tasks computing this cell's hydro forces. */ - struct link *force; + /*! Super cell, i.e. the highest-level parent cell that has a hydro + * pair/self tasks */ + struct cell *super; - /*! Linked list of the tasks computing this cell's gravity forces. */ - struct link *grav; + /*! Last (integer) time the cell's part were drifted forward in time. */ + integertime_t ti_old_part; - /*! Linked list of the tasks computing this cell's gravity M-M forces. */ - struct link *grav_mm; + /*! Maximum part movement in this cell since last construction. */ + float dx_max_part; - /*! The task computing this cell's sorts. */ - struct task *sorts; + /*! Maximum particle movement in this cell since the last sort. */ + float dx_max_sort; - /*! The multipole initialistation task */ - struct task *init_grav; + /*! Max smoothing length in this cell. */ + double h_max; - /*! Implicit task for the gravity initialisation */ - struct task *init_grav_out; + /*! Minimum end of (integer) time step in this cell for hydro tasks. */ + integertime_t ti_end_min; - /*! Dependency implicit task for the ghost (in->ghost->out)*/ - struct task *ghost_in; + /*! Maximum end of (integer) time step in this cell for hydro tasks. */ + integertime_t ti_end_max; - /*! Dependency implicit task for the ghost (in->ghost->out)*/ - struct task *ghost_out; + /*! Maximum beginning of (integer) time step in this cell for hydro tasks. + */ + integertime_t ti_beg_max; - /*! The ghost task itself */ - struct task *ghost; + /*! Nr of #part in this cell. */ + int count; - /*! The extra ghost task for complex hydro schemes */ - struct task *extra_ghost; + /*! Spin lock for various uses (#part case). */ + swift_lock_type lock; - /*! The drift task for parts */ - struct task *drift_part; + /*! Number of #part updated in this cell. */ + int updated; - /*! The drift task for gparts */ - struct task *drift_gpart; + /*! Number of #part inhibited in this cell. */ + int inhibited; - /*! The first kick task */ - struct task *kick1; + /*! Is the #part data of this cell being used in a sub-cell? */ + int hold; - /*! The second kick task */ - struct task *kick2; + /*! Values of h_max before the drifts, used for sub-cell tasks. */ + float h_max_old; - /*! The task to end the force calculation */ - struct task *end_force; + /*! Values of dx_max before the drifts, used for sub-cell tasks. */ + float dx_max_part_old; - /*! The task to compute time-steps */ - struct task *timestep; + /*! Values of dx_max_sort before the drifts, used for sub-cell tasks. */ + float dx_max_sort_old; - /*! Task computing long range non-periodic gravity interactions */ - struct task *grav_long_range; + /*! Bit mask of sort directions that will be needed in the next timestep. */ + unsigned int requires_sorts; - /*! Implicit task for the down propagation */ - struct task *grav_down_in; + /*! Bit mask of sorts that need to be computed for this cell. */ + unsigned int do_sort; - /*! Task propagating the mesh forces to the particles */ - struct task *grav_mesh; + /*! Does this cell need to be drifted (hydro)? */ + char do_drift; - /*! Task propagating the multipole to the particles */ - struct task *grav_down; + /*! Do any of this cell's sub-cells need to be drifted (hydro)? */ + char do_sub_drift; - /*! Dependency implicit task for the star ghost (in->ghost->out)*/ - struct task *stars_ghost_in; + /*! Do any of this cell's sub-cells need to be sorted? */ + char do_sub_sort; - /*! Dependency implicit task for the star ghost (in->ghost->out)*/ - struct task *stars_ghost_out; + /*! Bit-mask indicating the sorted directions */ + unsigned int sorted; - /*! The star ghost task itself */ - struct task *stars_ghost; + /*! The task computing this cell's sorts. */ + struct task *sorts; - /*! Linked list of the tasks computing this cell's star density. */ - struct link *stars_density; + /*! The drift task for parts */ + struct task *drift; - /*! Task for cooling */ - struct task *cooling; + /*! Linked list of the tasks computing this cell's hydro density. */ + struct link *density; - /*! Task for source terms */ - struct task *sourceterms; + /* Linked list of the tasks computing this cell's hydro gradients. */ + struct link *gradient; -#ifdef WITH_MPI + /*! Linked list of the tasks computing this cell's hydro forces. */ + struct link *force; - /* Task receiving hydro data (positions). */ - struct task *recv_xv; + /*! Dependency implicit task for the ghost (in->ghost->out)*/ + struct task *ghost_in; - /* Task receiving hydro data (density). */ - struct task *recv_rho; + /*! Dependency implicit task for the ghost (in->ghost->out)*/ + struct task *ghost_out; - /* Task receiving hydro data (gradient). */ - struct task *recv_gradient; + /*! The ghost task itself */ + struct task *ghost; - /* Task receiving gpart data. */ - struct task *recv_grav; + /*! The extra ghost task for complex hydro schemes */ + struct task *extra_ghost; - /* Task receiving data (time-step). */ - struct task *recv_ti; + /*! Task for cooling */ + struct task *cooling; - /* Linked list for sending hydro data (positions). */ - struct link *send_xv; + /*! Task for star formation */ + struct task *star_formation; - /* Linked list for sending hydro data (density). */ - struct link *send_rho; +#ifdef SWIFT_DEBUG_CHECKS - /* Linked list for sending hydro data (gradient). */ - struct link *send_gradient; + /*! Last (integer) time the cell's sort arrays were updated. */ + integertime_t ti_sort; - /* Linked list for sending gpart data. */ - struct link *send_grav; +#endif - /* Linked list for sending data (time-step). */ - struct link *send_ti; + } hydro; - /*! Bit mask of the proxies this cell is registered with. */ - unsigned long long int sendto; + /*! Grav variables */ + struct { - /*! Pointer to this cell's packed representation. */ - struct pcell *pcell; + /*! Pointer to the #gpart data. */ + struct gpart *parts; - /*! Size of the packed representation */ - int pcell_size; + /*! This cell's multipole. */ + struct gravity_tensors *multipole; - /*! MPI tag associated with this cell */ - int tag; + /*! Super cell, i.e. the highest-level parent cell that has a grav pair/self + * tasks */ + struct cell *super; -#endif + /*! Minimum end of (integer) time step in this cell for gravity tasks. */ + integertime_t ti_end_min; - /*! Minimum end of (integer) time step in this cell for hydro tasks. */ - integertime_t ti_hydro_end_min; + /*! Maximum end of (integer) time step in this cell for gravity tasks. */ + integertime_t ti_end_max; - /*! Maximum end of (integer) time step in this cell for hydro tasks. */ - integertime_t ti_hydro_end_max; + /*! Maximum beginning of (integer) time step in this cell for gravity tasks. + */ + integertime_t ti_beg_max; - /*! Maximum beginning of (integer) time step in this cell for hydro tasks. */ - integertime_t ti_hydro_beg_max; + /*! Last (integer) time the cell's gpart were drifted forward in time. */ + integertime_t ti_old_part; - /*! Minimum end of (integer) time step in this cell for gravity tasks. */ - integertime_t ti_gravity_end_min; + /*! Last (integer) time the cell's multipole was drifted forward in time. */ + integertime_t ti_old_multipole; - /*! Maximum end of (integer) time step in this cell for gravity tasks. */ - integertime_t ti_gravity_end_max; + /*! Nr of #gpart in this cell. */ + int count; - /*! Maximum beginning of (integer) time step in this cell for gravity tasks. - */ - integertime_t ti_gravity_beg_max; + /*! Spin lock for various uses (#gpart case). */ + swift_lock_type plock; - /*! Last (integer) time the cell's part were drifted forward in time. */ - integertime_t ti_old_part; + /*! Spin lock for various uses (#multipole case). */ + swift_lock_type mlock; - /*! Last (integer) time the cell's gpart were drifted forward in time. */ - integertime_t ti_old_gpart; + /*! Number of #gpart updated in this cell. */ + int updated; - /*! Last (integer) time the cell's multipole was drifted forward in time. */ - integertime_t ti_old_multipole; + /*! Number of #gpart inhibited in this cell. */ + int inhibited; - /*! Minimum dimension, i.e. smallest edge of this cell (min(width)). */ - float dmin; + /*! Is the #gpart data of this cell being used in a sub-cell? */ + int phold; - /*! Maximum particle movement in this cell since the last sort. */ - float dx_max_sort; + /*! Is the #multipole data of this cell being used in a sub-cell? */ + int mhold; - /*! Maximum part movement in this cell since last construction. */ - float dx_max_part; + /*! Does this cell need to be drifted (gravity)? */ + char do_drift; - /*! Nr of #part in this cell. */ - int count; + /*! Do any of this cell's sub-cells need to be drifted (gravity)? */ + char do_sub_drift; - /*! Nr of #gpart in this cell. */ - int gcount; + /*! The drift task for gparts */ + struct task *drift; - /*! Nr of #spart in this cell. */ - int scount; + /*! Linked list of the tasks computing this cell's gravity forces. */ + struct link *grav; - /*! Bit-mask indicating the sorted directions */ - unsigned int sorted; + /*! Linked list of the tasks computing this cell's gravity M-M forces. */ + struct link *mm; - /*! Spin lock for various uses (#part case). */ - swift_lock_type lock; + /*! The multipole initialistation task */ + struct task *init; - /*! Spin lock for various uses (#gpart case). */ - swift_lock_type glock; + /*! Implicit task for the gravity initialisation */ + struct task *init_out; - /*! Spin lock for various uses (#multipole case). */ - swift_lock_type mlock; + /*! Task computing long range non-periodic gravity interactions */ + struct task *long_range; - /*! Spin lock for various uses (#spart case). */ - swift_lock_type slock; + /*! Implicit task for the down propagation */ + struct task *down_in; - /*! ID of the previous owner, e.g. runner. */ - int owner; + /*! Task propagating the mesh forces to the particles */ + struct task *mesh; - /*! Number of #part updated in this cell. */ - int updated; + /*! Task propagating the multipole to the particles */ + struct task *down; - /*! Number of #gpart updated in this cell. */ - int g_updated; + /*! Number of M-M tasks that are associated with this cell. */ + short int nr_mm_tasks; - /*! Number of #spart updated in this cell. */ - int s_updated; + } grav; - /*! ID of the node this cell lives on. */ - int nodeID; + /*! Stars variables */ + struct { + + /*! Pointer to the #spart data. */ + struct spart *parts; + + /*! Nr of #spart in this cell. */ + int count; + + /*! Max smoothing length in this cell. */ + double h_max; + + /*! Values of h_max before the drifts, used for sub-cell tasks. */ + float h_max_old; + + /*! Maximum part movement in this cell since last construction. */ + float dx_max_part; + + /*! Values of dx_max before the drifts, used for sub-cell tasks. */ + float dx_max_part_old; + + /*! 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; + + /*! Linked list of the tasks computing this cell's star density. */ + struct link *density; + + /*! Number of #spart updated in this cell. */ + int updated; + + /*! Number of #spart inhibited in this cell. */ + int inhibited; + + /*! 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; + + } stars; + +#ifdef WITH_MPI + /*! MPI variables */ + struct { - /*! Is the #part data of this cell being used in a sub-cell? */ - int hold; + struct { + /* Task receiving hydro data (positions). */ + struct task *recv_xv; - /*! Is the #gpart data of this cell being used in a sub-cell? */ - int ghold; + /* Task receiving hydro data (density). */ + struct task *recv_rho; - /*! Is the #multipole data of this cell being used in a sub-cell? */ - int mhold; + /* Task receiving hydro data (gradient). */ + struct task *recv_gradient; - /*! Is the #spart data of this cell being used in a sub-cell? */ - int shold; + /* Linked list for sending hydro data (positions). */ + struct link *send_xv; - /*! Values of dx_max before the drifts, used for sub-cell tasks. */ - float dx_max_old; + /* Linked list for sending hydro data (density). */ + struct link *send_rho; - /*! Values of h_max before the drifts, used for sub-cell tasks. */ - float h_max_old; + /* Linked list for sending hydro data (gradient). */ + struct link *send_gradient; - /*! Values of dx_max_sort before the drifts, used for sub-cell tasks. */ - float dx_max_sort_old; + } hydro; - /*! Bit mask of sort directions that will be needed in the next timestep. */ - unsigned int requires_sorts; + struct { - /*! Bit mask of sorts that need to be computed for this cell. */ - unsigned int do_sort; + /* Task receiving gpart data. */ + struct task *recv; + + /* Linked list for sending gpart data. */ + struct link *send; + } grav; + + /* Task receiving data (time-step). */ + struct task *recv_ti; + + /* Linked list for sending data (time-step). */ + struct link *send_ti; + + /*! Bit mask of the proxies this cell is registered with. */ + unsigned long long int sendto; + + /*! Pointer to this cell's packed representation. */ + struct pcell *pcell; + + /*! Size of the packed representation */ + int pcell_size; + + /*! MPI tag associated with this cell */ + int tag; + + } mpi; +#endif + + /*! The task to end the force calculation */ + struct task *end_force; + + /*! The first kick task */ + struct task *kick1; + + /*! The second kick task */ + struct task *kick2; + + /*! The task to compute time-steps */ + struct task *timestep; + + /*! Task for source terms */ + struct task *sourceterms; + + /*! The logger task */ + struct task *logger; + + /*! Minimum dimension, i.e. smallest edge of this cell (min(width)). */ + float dmin; + + /*! ID of the previous owner, e.g. runner. */ + int owner; + + /*! ID of the node this cell lives on. */ + int nodeID; /*! Number of tasks that are associated with this cell. */ short int nr_tasks; - /*! Number of M-M tasks that are associated with this cell. */ - short int nr_mm_tasks; - /*! The depth of this cell in the tree. */ char depth; @@ -464,28 +574,10 @@ struct cell { /*! The maximal depth of this cell and its progenies */ char maxdepth; - /*! Does this cell need to be drifted (hydro)? */ - char do_drift; - - /*! Do any of this cell's sub-cells need to be drifted (hydro)? */ - char do_sub_drift; - - /*! Does this cell need to be drifted (gravity)? */ - char do_grav_drift; - - /*! Do any of this cell's sub-cells need to be drifted (gravity)? */ - char do_grav_sub_drift; - - /*! Do any of this cell's sub-cells need to be sorted? */ - char do_sub_sort; - #ifdef SWIFT_DEBUG_CHECKS /* Cell ID (for debugging) */ int cellID; - /*! Last (integer) time the cell's sort arrays were updated. */ - integertime_t ti_sort; - /*! The list of tasks that have been executed on this cell */ char tasks_executed[64]; @@ -558,6 +650,16 @@ void cell_activate_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); int cell_has_tasks(struct cell *c); +void cell_remove_part(const struct engine *e, struct cell *c, struct part *p, + struct xpart *xp); +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); 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, @@ -578,8 +680,8 @@ cell_can_recurse_in_pair_hydro_task(const struct cell *c) { /* If so, is the cut-off radius plus the max distance the parts have moved */ /* smaller than the sub-cell sizes ? */ /* Note: We use the _old values as these might have been updated by a drift */ - return c->split && - ((kernel_gamma * c->h_max_old + c->dx_max_old) < 0.5f * c->dmin); + return c->split && ((kernel_gamma * c->hydro.h_max_old + + c->hydro.dx_max_part_old) < 0.5f * c->dmin); } /** @@ -592,7 +694,7 @@ __attribute__((always_inline)) INLINE static int cell_can_recurse_in_self_hydro_task(const struct cell *c) { /* Is the cell split and not smaller than the smoothing length? */ - return c->split && (kernel_gamma * c->h_max_old < 0.5f * c->dmin); + return c->split && (kernel_gamma * c->hydro.h_max_old < 0.5f * c->dmin); } /** @@ -604,8 +706,12 @@ cell_can_recurse_in_self_hydro_task(const struct cell *c) { __attribute__((always_inline)) INLINE static int cell_can_recurse_in_pair_stars_task(const struct cell *c) { - // LOIC: To implement - return 0; + /* Is the cell split ? */ + /* If so, is the cut-off radius plus the max distance the parts have moved */ + /* smaller than the sub-cell sizes ? */ + /* Note: We use the _old values as these might have been updated by a drift */ + return c->split && ((kernel_gamma * c->stars.h_max_old + + c->stars.dx_max_part_old) < 0.5f * c->dmin); } /** @@ -617,8 +723,8 @@ cell_can_recurse_in_pair_stars_task(const struct cell *c) { __attribute__((always_inline)) INLINE static int cell_can_recurse_in_self_stars_task(const struct cell *c) { - // LOIC: To implement - return 0; + /* Is the cell split and not smaller than the smoothing length? */ + return c->split && (kernel_gamma * c->stars.h_max_old < 0.5f * c->dmin); } /** @@ -635,7 +741,8 @@ __attribute__((always_inline)) INLINE static int cell_can_split_pair_hydro_task( /* the sub-cell sizes ? */ /* Note that since tasks are create after a rebuild no need to take */ /* into account any part motion (i.e. dx_max == 0 here) */ - return c->split && (space_stretch * kernel_gamma * c->h_max < 0.5f * c->dmin); + return c->split && + (space_stretch * kernel_gamma * c->hydro.h_max < 0.5f * c->dmin); } /** @@ -652,7 +759,8 @@ __attribute__((always_inline)) INLINE static int cell_can_split_self_hydro_task( /* the sub-cell sizes ? */ /* Note: No need for more checks here as all the sub-pairs and sub-self */ /* tasks will be created. So no need to check for h_max */ - return c->split && (space_stretch * kernel_gamma * c->h_max < 0.5f * c->dmin); + return c->split && + (space_stretch * kernel_gamma * c->hydro.h_max < 0.5f * c->dmin); } /** @@ -664,8 +772,13 @@ __attribute__((always_inline)) INLINE static int cell_can_split_self_hydro_task( __attribute__((always_inline)) INLINE static int cell_can_split_pair_stars_task( const struct cell *c) { - // LOIC: To implement - return 0; + /* Is the cell split ? */ + /* If so, is the cut-off radius with some leeway smaller than */ + /* the sub-cell sizes ? */ + /* Note that since tasks are create after a rebuild no need to take */ + /* into account any part motion (i.e. dx_max == 0 here) */ + return c->split && + (space_stretch * kernel_gamma * c->stars.h_max < 0.5f * c->dmin); } /** @@ -677,8 +790,13 @@ __attribute__((always_inline)) INLINE static int cell_can_split_pair_stars_task( __attribute__((always_inline)) INLINE static int cell_can_split_self_stars_task( const struct cell *c) { - // LOIC: To implement - return 0; + /* Is the cell split ? */ + /* If so, is the cut-off radius with some leeway smaller than */ + /* the sub-cell sizes ? */ + /* Note: No need for more checks here as all the sub-pairs and sub-self */ + /* tasks will be created. So no need to check for h_max */ + return c->split && + (space_stretch * kernel_gamma * c->stars.h_max < 0.5f * c->dmin); } /** @@ -720,8 +838,8 @@ __attribute__((always_inline)) INLINE static int cell_need_rebuild_for_pair( /* Is the cut-off radius plus the max distance the parts in both cells have */ /* moved larger than the cell size ? */ /* Note ci->dmin == cj->dmin */ - return (kernel_gamma * max(ci->h_max, cj->h_max) + ci->dx_max_part + - cj->dx_max_part > + return (kernel_gamma * max(ci->hydro.h_max, cj->hydro.h_max) + + ci->hydro.dx_max_part + cj->hydro.dx_max_part > cj->dmin); } @@ -734,10 +852,11 @@ __attribute__((always_inline)) INLINE static void cell_tag(struct cell *c) { #ifdef WITH_MPI #ifdef SWIFT_DEBUG_CHECKS - if (c->tag > 0) error("setting tag for already tagged cell"); + if (c->mpi.tag > 0) error("setting tag for already tagged cell"); #endif - if (c->tag < 0 && (c->tag = atomic_inc(&cell_next_tag)) > cell_max_tag) + if (c->mpi.tag < 0 && + (c->mpi.tag = atomic_inc(&cell_next_tag)) > cell_max_tag) error("Ran out of cell tags."); #else error("SWIFT was not compiled with MPI enabled."); diff --git a/src/clocks.c b/src/clocks.c index c64276bf83f8b52d6d09aa4950737af2a12aa4f6..49297f5db1cc10a3d9f4537c5900610dded7ffba 100644 --- a/src/clocks.c +++ b/src/clocks.c @@ -263,6 +263,17 @@ const char *clocks_get_timesincestart(void) { return buffer; } +/** + * Returns the wall-clock time since the start of execution in hours. + * + * Need to call clocks_set_cpufreq() to mark the start of execution. + * + * @result the time since the start of the execution + */ +double clocks_get_hours_since_start(void) { + return clocks_diff_ticks(getticks(), clocks_start) / (3600. * 1000.0); +} + /** * @brief return the cpu time used. * diff --git a/src/clocks.h b/src/clocks.h index d33e5a342a9b7024ee918a035547e8351b3dc726..ce08167bd504d47a76542870791057881c6d2f17 100644 --- a/src/clocks.h +++ b/src/clocks.h @@ -19,8 +19,13 @@ #ifndef SWIFT_CLOCKS_H #define SWIFT_CLOCKS_H +/* Config parameters. */ +#include "../config.h" + +/* System includes. */ #include <sys/times.h> -#include <time.h> + +/* Local includes */ #include "cycle.h" /* Struct to record a time for the clocks functions. */ @@ -42,6 +47,7 @@ double clocks_from_ticks(ticks tics); ticks clocks_to_ticks(double interval); double clocks_diff_ticks(ticks tic, ticks toc); const char *clocks_get_timesincestart(void); +double clocks_get_hours_since_start(void); double clocks_get_cputime_used(void); int clocks_random_seed(void); diff --git a/src/collectgroup.c b/src/collectgroup.c index c83d7bef3f03e672e8b5c9036e5daaab26b5d190..0b7b419b565612149fd2b295116b37aa65aa01e9 100644 --- a/src/collectgroup.c +++ b/src/collectgroup.c @@ -36,7 +36,8 @@ /* Local collections for MPI reduces. */ struct mpicollectgroup1 { - long long updates, g_updates, s_updates; + long long updated, g_updated, s_updated; + long long inhibited, g_inhibited, s_inhibited; integertime_t ti_hydro_end_min; integertime_t ti_gravity_end_min; int forcerebuild; @@ -85,9 +86,12 @@ void collectgroup1_apply(struct collectgroup1 *grp1, struct engine *e) { e->ti_end_min = min(e->ti_hydro_end_min, e->ti_gravity_end_min); e->ti_end_max = max(e->ti_hydro_end_max, e->ti_gravity_end_max); e->ti_beg_max = max(e->ti_hydro_beg_max, e->ti_gravity_beg_max); - e->updates = grp1->updates; - e->g_updates = grp1->g_updates; - e->s_updates = grp1->s_updates; + e->updates = grp1->updated; + e->g_updates = grp1->g_updated; + e->s_updates = grp1->s_updated; + e->nr_inhibited_parts = grp1->inhibited; + e->nr_inhibited_gparts = grp1->g_inhibited; + e->nr_inhibited_sparts = grp1->s_inhibited; e->forcerebuild = grp1->forcerebuild; } @@ -95,10 +99,16 @@ void collectgroup1_apply(struct collectgroup1 *grp1, struct engine *e) { * @brief Initialises a collectgroup1 struct ready for processing. * * @param grp1 The #collectgroup1 to initialise - * @param updates the number of updated hydro particles on this node this step. - * @param g_updates the number of updated gravity particles on this node this + * @param updated the number of updated hydro particles on this node this step. + * @param g_updated the number of updated gravity particles on this node this + * step. + * @param s_updated the number of updated star particles on this node this step. + * @param inhibited the number of inhibited hydro particles on this node this + * step. + * @param g_inhibited the number of inhibited gravity particles on this node + * this step. + * @param s_inhibited the number of inhibited star particles on this node this * step. - * @param s_updates the number of updated star particles on this node this step. * @param ti_hydro_end_min the minimum end time for next hydro time step after * this step. * @param ti_hydro_end_max the maximum end time for next hydro time step after @@ -113,17 +123,22 @@ void collectgroup1_apply(struct collectgroup1 *grp1, struct engine *e) { * after this step. * @param forcerebuild whether a rebuild is required after this step. */ -void collectgroup1_init(struct collectgroup1 *grp1, size_t updates, - size_t g_updates, size_t s_updates, +void collectgroup1_init(struct collectgroup1 *grp1, size_t updated, + size_t g_updated, size_t s_updated, size_t inhibited, + size_t g_inhibited, size_t s_inhibited, integertime_t ti_hydro_end_min, integertime_t ti_hydro_end_max, integertime_t ti_hydro_beg_max, integertime_t ti_gravity_end_min, integertime_t ti_gravity_end_max, integertime_t ti_gravity_beg_max, int forcerebuild) { - grp1->updates = updates; - grp1->g_updates = g_updates; - grp1->s_updates = s_updates; + + grp1->updated = updated; + grp1->g_updated = g_updated; + grp1->s_updated = s_updated; + grp1->inhibited = inhibited; + grp1->g_inhibited = g_inhibited; + grp1->s_inhibited = s_inhibited; grp1->ti_hydro_end_min = ti_hydro_end_min; grp1->ti_hydro_end_max = ti_hydro_end_max; grp1->ti_hydro_beg_max = ti_hydro_beg_max; @@ -147,9 +162,12 @@ void collectgroup1_reduce(struct collectgroup1 *grp1) { /* Populate an MPI group struct and reduce this across all nodes. */ struct mpicollectgroup1 mpigrp11; - mpigrp11.updates = grp1->updates; - mpigrp11.g_updates = grp1->g_updates; - mpigrp11.s_updates = grp1->s_updates; + mpigrp11.updated = grp1->updated; + mpigrp11.g_updated = grp1->g_updated; + mpigrp11.s_updated = grp1->s_updated; + mpigrp11.inhibited = grp1->inhibited; + mpigrp11.g_inhibited = grp1->g_inhibited; + mpigrp11.s_inhibited = grp1->s_inhibited; mpigrp11.ti_hydro_end_min = grp1->ti_hydro_end_min; mpigrp11.ti_gravity_end_min = grp1->ti_gravity_end_min; mpigrp11.forcerebuild = grp1->forcerebuild; @@ -160,9 +178,12 @@ void collectgroup1_reduce(struct collectgroup1 *grp1) { error("Failed to reduce mpicollection1."); /* And update. */ - grp1->updates = mpigrp12.updates; - grp1->g_updates = mpigrp12.g_updates; - grp1->s_updates = mpigrp12.s_updates; + grp1->updated = mpigrp12.updated; + grp1->g_updated = mpigrp12.g_updated; + grp1->s_updated = mpigrp12.s_updated; + grp1->inhibited = mpigrp12.inhibited; + grp1->g_inhibited = mpigrp12.g_inhibited; + grp1->s_inhibited = mpigrp12.s_inhibited; grp1->ti_hydro_end_min = mpigrp12.ti_hydro_end_min; grp1->ti_gravity_end_min = mpigrp12.ti_gravity_end_min; grp1->forcerebuild = mpigrp12.forcerebuild; @@ -182,9 +203,14 @@ static void doreduce1(struct mpicollectgroup1 *mpigrp11, /* Do what is needed for each part of the collection. */ /* Sum of updates. */ - mpigrp11->updates += mpigrp12->updates; - mpigrp11->g_updates += mpigrp12->g_updates; - mpigrp11->s_updates += mpigrp12->s_updates; + mpigrp11->updated += mpigrp12->updated; + mpigrp11->g_updated += mpigrp12->g_updated; + mpigrp11->s_updated += mpigrp12->s_updated; + + /* Sum of inhibited */ + mpigrp11->inhibited += mpigrp12->inhibited; + mpigrp11->g_inhibited += mpigrp12->g_inhibited; + mpigrp11->s_inhibited += mpigrp12->s_inhibited; /* Minimum end time. */ mpigrp11->ti_hydro_end_min = @@ -204,7 +230,7 @@ static void mpicollectgroup1_reduce(void *in, void *inout, int *len, MPI_Datatype *datatype) { for (int i = 0; i < *len; ++i) - doreduce1(&((struct mpicollectgroup1 *)inout)[0], + doreduce1(&((struct mpicollectgroup1 *)inout)[i], &((const struct mpicollectgroup1 *)in)[i]); } diff --git a/src/collectgroup.h b/src/collectgroup.h index 8bf8a9d1b75f9a5ddb3f19fa9cdb4103e044ea59..b6e8769ac993cc023ae402cdfc4b0169406f6181 100644 --- a/src/collectgroup.h +++ b/src/collectgroup.h @@ -35,7 +35,10 @@ struct engine; struct collectgroup1 { /* Number of particles updated */ - long long updates, g_updates, s_updates; + long long updated, g_updated, s_updated; + + /* Number of particles inhibited */ + long long inhibited, g_inhibited, s_inhibited; /* Times for the time-step */ integertime_t ti_hydro_end_min, ti_hydro_end_max, ti_hydro_beg_max; @@ -47,8 +50,9 @@ struct collectgroup1 { void collectgroup_init(void); void collectgroup1_apply(struct collectgroup1 *grp1, struct engine *e); -void collectgroup1_init(struct collectgroup1 *grp1, size_t updates, - size_t g_updates, size_t s_updates, +void collectgroup1_init(struct collectgroup1 *grp1, size_t updated, + size_t g_updated, size_t s_updated, size_t inhibited, + size_t g_inhibited, size_t s_inhibited, integertime_t ti_hydro_end_min, integertime_t ti_hydro_end_max, integertime_t ti_hydro_beg_max, diff --git a/src/common_io.c b/src/common_io.c index 5c8a234c124fb95c08a4bd59d903745e03c5d92c..5ea80f651989022307c255c3ee935f701edfe3c5 100644 --- a/src/common_io.c +++ b/src/common_io.c @@ -378,7 +378,7 @@ void io_write_engine_policy(hid_t h_file, const struct engine* e) { const hid_t h_grp = H5Gcreate1(h_file, "/Policy", 0); if (h_grp < 0) error("Error while creating policy group"); - for (int i = 1; i <= engine_maxpolicy; ++i) + for (int i = 1; i < engine_maxpolicy; ++i) if (e->policy & (1 << i)) io_write_attribute_i(h_grp, engine_policy_names[i + 1], 1); else @@ -634,9 +634,9 @@ void io_prepare_dm_gparts_mapper(void* restrict data, int Ndm, void* dummy) { /* Let's give all these gparts a negative id */ for (int i = 0; i < Ndm; ++i) { - /* 0 or negative ids are not allowed */ - if (gparts[i].id_or_neg_offset <= 0) - error("0 or negative ID for DM particle %i: ID=%lld", i, + /* Negative ids are not allowed */ + if (gparts[i].id_or_neg_offset < 0) + error("Negative ID for DM particle %i: ID=%lld", i, gparts[i].id_or_neg_offset); /* Set gpart type */ @@ -787,35 +787,109 @@ void io_duplicate_stars_gparts(struct threadpool* tp, } /** - * @brief Copy every DM #gpart into the dmparts array. + * @brief Copy every non-inhibited #part into the parts_written array. + * + * @param parts The array of #part containing all particles. + * @param xparts The array of #xpart containing all particles. + * @param parts_written The array of #part to fill with particles we want to + * write. + * @param xparts_written The array of #xpart to fill with particles we want to + * write. + * @param Nparts The total number of #part. + * @param Nparts_written The total number of #part to write. + */ +void io_collect_parts_to_write(const struct part* restrict parts, + const struct xpart* restrict xparts, + struct part* restrict parts_written, + struct xpart* restrict xparts_written, + const size_t Nparts, + const size_t Nparts_written) { + + size_t count = 0; + + /* Loop over all 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) { + + parts_written[count] = parts[i]; + xparts_written[count] = xparts[i]; + count++; + } + } + + /* Check that everything is fine */ + if (count != Nparts_written) + error("Collected the wrong number of particles (%zu vs. %zu expected)", + count, Nparts_written); +} + +/** + * @brief Copy every non-inhibited #spart into the sparts_written array. + * + * @param sparts The array of #spart containing all particles. + * @param sparts_written The array of #spart to fill with particles we want to + * write. + * @param Nsparts The total number of #part. + * @param Nsparts_written The total number of #part to write. + */ +void io_collect_sparts_to_write(const struct spart* restrict sparts, + struct spart* restrict sparts_written, + const size_t Nsparts, + const size_t Nsparts_written) { + + size_t count = 0; + + /* Loop over all parts */ + 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) { + + sparts_written[count] = sparts[i]; + count++; + } + } + + /* Check that everything is fine */ + if (count != Nsparts_written) + error("Collected the wrong number of s-particles (%zu vs. %zu expected)", + count, Nsparts_written); +} + +/** + * @brief Copy every non-inhibited DM #gpart into the gparts_written array. * * @param gparts The array of #gpart containing all particles. - * @param Ntot The number of #gpart. - * @param dmparts The array of #gpart containg DM particles to be filled. - * @param Ndm The number of DM particles. + * @param gparts_written The array of #gpart to fill with particles we want to + * write. + * @param Ngparts The total number of #part. + * @param Ngparts_written The total number of #part to write. */ -void io_collect_dm_gparts(const struct gpart* const gparts, size_t Ntot, - struct gpart* const dmparts, size_t Ndm) { +void io_collect_gparts_to_write(const struct gpart* restrict gparts, + struct gpart* restrict gparts_written, + const size_t Ngparts, + const size_t Ngparts_written) { size_t count = 0; - /* Loop over all gparts */ - for (size_t i = 0; i < Ntot; ++i) { + /* Loop over all parts */ + for (size_t i = 0; i < Ngparts; ++i) { - /* message("i=%zd count=%zd id=%lld part=%p", i, count, gparts[i].id, - * gparts[i].part); */ + /* And collect the ones that have not been removed */ + if ((gparts[i].time_bin != time_bin_inhibited) && + (gparts[i].type == swift_type_dark_matter)) { - /* And collect the DM ones */ - if (gparts[i].type == swift_type_dark_matter) { - dmparts[count] = gparts[i]; + gparts_written[count] = gparts[i]; count++; } } /* Check that everything is fine */ - if (count != Ndm) - error("Collected the wrong number of dm particles (%zu vs. %zu expected)", - count, Ndm); + if (count != Ngparts_written) + error("Collected the wrong number of s-particles (%zu vs. %zu expected)", + count, Ngparts_written); } /** diff --git a/src/common_io.h b/src/common_io.h index 7e0f1b74898f5cfdec5631c142231d30a0944f50..016c5138e18ae8636834c35d659e07d8fcd46e36 100644 --- a/src/common_io.h +++ b/src/common_io.h @@ -35,6 +35,7 @@ struct part; struct gpart; struct spart; +struct xpart; struct io_props; struct engine; struct threadpool; @@ -56,12 +57,6 @@ enum IO_DATA_TYPE { CHAR }; -/** - * @brief The different formats for when to run structure finding. - * - */ -enum io_stf_output_format { io_stf_steps = 0, io_stf_time }; - #if defined(HAVE_HDF5) hid_t io_hdf5_type(enum IO_DATA_TYPE type); @@ -97,8 +92,20 @@ void io_copy_temp_buffer(void* temp, const struct engine* e, size_t io_sizeof_type(enum IO_DATA_TYPE type); int io_is_double_precision(enum IO_DATA_TYPE type); -void io_collect_dm_gparts(const struct gpart* const gparts, size_t Ntot, - struct gpart* const dmparts, size_t Ndm); +void io_collect_parts_to_write(const struct part* restrict parts, + const struct xpart* restrict xparts, + struct part* restrict parts_written, + struct xpart* restrict xparts_written, + const size_t Nparts, + const size_t Nparts_written); +void io_collect_sparts_to_write(const struct spart* restrict sparts, + struct spart* restrict sparts_written, + const size_t Nsparts, + const size_t Nsparts_written); +void io_collect_gparts_to_write(const struct gpart* restrict gparts, + struct gpart* restrict gparts_written, + const size_t Ngparts, + const size_t Ngparts_written); void io_prepare_dm_gparts(struct threadpool* tp, struct gpart* const gparts, size_t Ndm); void io_duplicate_hydro_gparts(struct threadpool* tp, struct part* const parts, diff --git a/src/const.h b/src/const.h index 6c5b5299c08efb7935b046ecfd0b3d67b7dc4c7a..e417b8ca3827ef87396706c56df36bb9bd3aed75 100644 --- a/src/const.h +++ b/src/const.h @@ -21,13 +21,10 @@ #define SWIFT_CONST_H /* SPH Viscosity constants. */ -#define const_viscosity_alpha 0.8f -#define const_viscosity_alpha_min \ - 0.1f /* Values taken from (Price,2004), not used in legacy gadget mode */ -#define const_viscosity_alpha_max \ - 2.0f /* Values taken from (Price,2004), not used in legacy gadget mode */ -#define const_viscosity_length \ - 0.1f /* Values taken from (Price,2004), not used in legacy gadget mode */ +/* Cosmology default beta=3.0. Planetary default beta=4.0 + * Alpha can be set in the parameter file. + * Beta is defined as in e.g. Price (2010) Eqn (103) */ +#define const_viscosity_beta 3.0f /* SPH Thermal conductivity constants. */ #define const_conductivity_alpha \ diff --git a/src/cooling.h b/src/cooling.h index 0fb04b9e484d989e746a254fc1934dc20033fb09..ae0d06a4733b31f8c0a2fe4db5329df1494f4aa4 100644 --- a/src/cooling.h +++ b/src/cooling.h @@ -34,6 +34,8 @@ #include "./cooling/const_du/cooling.h" #elif defined(COOLING_CONST_LAMBDA) #include "./cooling/const_lambda/cooling.h" +#elif defined(COOLING_COMPTON) +#include "./cooling/Compton/cooling.h" #elif defined(COOLING_GRACKLE) #include "./cooling/grackle/cooling.h" #elif defined(COOLING_EAGLE) diff --git a/src/cooling/Compton/cooling.h b/src/cooling/Compton/cooling.h new file mode 100644 index 0000000000000000000000000000000000000000..da9225fe02fb6805f795938f86afd75ebdbef125 --- /dev/null +++ b/src/cooling/Compton/cooling.h @@ -0,0 +1,335 @@ +/******************************************************************************* + * 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_COOLING_COMPTON_H +#define SWIFT_COOLING_COMPTON_H + +/* Config parameters. */ +#include "../config.h" + +/* Some standard headers. */ +#include <float.h> +#include <math.h> + +/* Local includes. */ +#include "const.h" +#include "error.h" +#include "hydro.h" +#include "parser.h" +#include "part.h" +#include "physical_constants.h" +#include "units.h" + +/** + * @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 hydro_props The properties of the hydro scheme. + * @param cooling The #cooling_function_data used in the run. + * @param z The current redshift. + * @param u The current internal energy in internal units. + * @param p Pointer to the particle data. + * @return The change in energy per unit mass due to cooling for this particle + * 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 cooling_function_data* cooling, const double z, const double u, + const struct part* p) { + + /* Get particle density */ + const double rho = hydro_get_physical_density(p, cosmo); + const double rho_cgs = rho * cooling->conv_factor_density_to_cgs; + + /* Powers of (1 + z) */ + const double zp1 = z + 1.; + const double zp1p2 = zp1 * zp1; + const double zp1p4 = zp1p2 * zp1p2; /* (1 + z)^4 */ + + /* CMB temperature at this redshift */ + const double T_CMB = cooling->const_T_CMB_0 * zp1; + + /* Gas properties */ + const double H_mass_fraction = hydro_props->hydrogen_mass_fraction; + const double T_transition = hydro_props->hydrogen_ionization_temperature; + + /* 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. + + /* Electron abundance */ + double electron_abundance = 0.; // MATTHIEU: To do: compute X_e + + /* Temperature difference with the CMB */ + const double delta_T = T - T_CMB; + + /* Electron density */ + const double electron_density_cgs = + rho_cgs * electron_abundance * cooling->proton_mass_cgs_inv; + + /* Compton formula */ + return cooling->const_Compton_rate_cgs * delta_T * zp1p4 * + electron_density_cgs / rho_cgs; +} + +/** + * @brief Apply the cooling function to a particle. + * + * @param phys_const The physical constants in internal units. + * @param us The internal system of units. + * @param cosmo The current cosmological model. + * @param hydro_props The properties of the hydro scheme. + * @param cooling The #cooling_function_data used in the run. + * @param p Pointer to the particle data. + * @param xp Pointer to the particle' extended data. + * @param dt The time-step of this particle. + * @param dt_therm The time-step operator used for thermal quantities. + */ +__attribute__((always_inline)) INLINE static void cooling_cool_part( + const struct phys_const* restrict phys_const, + const struct unit_system* restrict us, + const struct cosmology* restrict cosmo, + const struct hydro_props* hydro_props, + const struct cooling_function_data* restrict cooling, + struct part* restrict p, struct xpart* restrict xp, const float dt, + const float dt_therm) { + + /* Nothing to do here? */ + if (dt == 0.) return; + + /* Internal energy floor */ + const float u_floor = hydro_props->minimal_internal_energy; + + /* Current energy */ + const float u_old = hydro_get_physical_internal_energy(p, xp, cosmo); + + /* Current du_dt in physical coordinates (internal units) */ + 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); + + /* Convert to internal units */ + float cooling_du_dt = + cooling_du_dt_cgs * cooling->conv_factor_energy_rate_from_cgs; + + /* Add cosmological term */ + cooling_du_dt *= cosmo->a * cosmo->a; + + float total_du_dt = hydro_du_dt + cooling_du_dt; + + /* We now need to check that we are not going to go below any of the limits */ + + /* First, check whether we may end up below the minimal energy after + * this step 1/2 kick + another 1/2 kick that could potentially be for + * a time-step twice as big. We hence check for 1.5 delta_t. */ + if (u_old + total_du_dt * 1.5 * dt_therm < u_floor) { + total_du_dt = (u_floor - u_old) / (1.5f * dt_therm); + } + + /* Second, check whether the energy used in the prediction could get negative. + * We need to check for the 1/2 dt kick followed by a full time-step drift + * that could potentially be for a time-step twice as big. We hence check + * for 2.5 delta_t but this time against 0 energy not the minimum */ + if (u_old + total_du_dt * 2.5 * dt_therm < 0.) { + total_du_dt = -u_old / ((2.5f + 0.0001f) * dt_therm); + } + + /* Update the internal energy time derivative */ + hydro_set_physical_internal_energy_dt(p, cosmo, total_du_dt); + + /* Store the radiated energy (assuming dt will not change) */ + xp->cooling_data.radiated_energy += + -hydro_get_mass(p) * (total_du_dt - hydro_du_dt) * dt_therm; +} + +/** + * @brief Computes the time-step due to cooling for this particle. + * + * We impose no time-step limit. + * + * @param cooling The #cooling_function_data used in the run. + * @param phys_const The physical constants in internal units. + * @param cosmo The current cosmological model. + * @param hydro_props The properties of the hydro scheme. + * @param us The internal system of units. + * @param p Pointer to the particle data. + * @param xp Pointer to the extended data of the particle. + */ +__attribute__((always_inline)) INLINE static float cooling_timestep( + const struct cooling_function_data* restrict cooling, + const struct phys_const* restrict phys_const, + const struct cosmology* restrict cosmo, + const struct unit_system* restrict us, + const struct hydro_props* hydro_props, const struct part* restrict p, + const struct xpart* restrict xp) { + + return FLT_MAX; +} + +/** + * @brief Sets the cooling properties of the (x-)particles to a valid start + * state. + * + * Nothing to do here. Just set the radiated energy counter to 0. + * + * @param phys_const The physical constants in internal units. + * @param cooling The properties of the cooling function. + * @param us The internal system of units. + * @param cosmo The current cosmological model. + * @param p Pointer to the particle data. + * @param xp Pointer to the extended particle data. + */ +__attribute__((always_inline)) INLINE static void cooling_first_init_part( + const struct phys_const* restrict phys_const, + const struct unit_system* restrict us, + const struct cosmology* restrict cosmo, + const struct cooling_function_data* restrict cooling, + const struct part* restrict p, struct xpart* restrict xp) { + + xp->cooling_data.radiated_energy = 0.f; +} + +/** + * @brief Returns the total radiated energy by this particle. + * + * @param xp The extended particle data + */ +__attribute__((always_inline)) INLINE static float cooling_get_radiated_energy( + const struct xpart* restrict xp) { + + return xp->cooling_data.radiated_energy; +} + +/** + * @brief Initialises the cooling properties. + * + * @param parameter_file The parsed parameter file. + * @param us The current internal system of units. + * @param phys_const The physical constants in internal units. + * @param cooling The cooling properties to initialize + */ +static INLINE void cooling_init_backend(struct swift_params* parameter_file, + const struct unit_system* us, + const struct phys_const* phys_const, + struct cooling_function_data* cooling) { + + /* Some useful conversion values */ + cooling->conv_factor_density_to_cgs = + units_cgs_conversion_factor(us, UNIT_CONV_DENSITY); + cooling->conv_factor_energy_to_cgs = + units_cgs_conversion_factor(us, UNIT_CONV_ENERGY_PER_UNIT_MASS); + cooling->conv_factor_energy_rate_from_cgs = + units_cgs_conversion_factor(us, UNIT_CONV_TIME) / + units_cgs_conversion_factor(us, UNIT_CONV_ENERGY_PER_UNIT_MASS); + + /* Useful constants */ + cooling->proton_mass_cgs_inv = + 1. / (phys_const->const_proton_mass * + units_cgs_conversion_factor(us, UNIT_CONV_MASS)); + + /* Temperature of the CMB in CGS */ + const double T_CMB_0 = phys_const->const_T_CMB_0 * + units_cgs_conversion_factor(us, UNIT_CONV_TEMPERATURE); + cooling->const_T_CMB_0 = T_CMB_0; /* [K] */ + + /* Compute the coefficient at the front of the Compton cooling expression */ + const double radiation_constant = + 4. * phys_const->const_stefan_boltzmann / phys_const->const_speed_light_c; + const double compton_coefficient = + 4. * radiation_constant * phys_const->const_thomson_cross_section * + phys_const->const_boltzmann_k / + (phys_const->const_electron_mass * phys_const->const_speed_light_c); + const float dimension_coefficient[5] = {1, 2, -3, 0, -5}; + + /* This should be ~1.0178085e-37 [g cm^2 s^-3 K^-5] */ + const double compton_coefficient_cgs = + compton_coefficient * + units_general_cgs_conversion_factor(us, dimension_coefficient); + + /* And now the Compton rate [g cm^2 s^-3 K^-1] == [erg s^-1 K^-1]*/ + cooling->const_Compton_rate_cgs = + compton_coefficient_cgs * T_CMB_0 * T_CMB_0 * T_CMB_0 * T_CMB_0; +} + +/** + * @brief Prints the properties of the cooling model to stdout. + * + * @param cooling The properties of the cooling function. + */ +static INLINE void cooling_print_backend( + const struct cooling_function_data* cooling) { + + message("Cooling function is 'Compton cooling'."); +} + +#endif /* SWIFT_COOLING_COMPTON_H */ diff --git a/src/cooling/Compton/cooling_io.h b/src/cooling/Compton/cooling_io.h new file mode 100644 index 0000000000000000000000000000000000000000..d020587c920f781450a5183954bc6c429e461512 --- /dev/null +++ b/src/cooling/Compton/cooling_io.h @@ -0,0 +1,62 @@ +/******************************************************************************* + * 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_COOLING_IO_COMPTON_H +#define SWIFT_COOLING_IO_COMPTON_H + +/* Config parameters. */ +#include "../config.h" + +/* Local includes */ +#include "io_properties.h" + +#ifdef HAVE_HDF5 + +/** + * @brief Writes the current model of cooling to the file + * @param h_grp The HDF5 group in which to write + * @param cooling the parameters of the cooling function. + */ +__attribute__((always_inline)) INLINE static void cooling_write_flavour( + hid_t h_grp, const struct cooling_function_data* cooling) { + + io_write_attribute_s(h_grp, "Cooling Model", "Compton cooling"); + io_write_attribute_d(h_grp, "Compton rate [erg s^-1 K^-1]", + cooling->const_Compton_rate_cgs); +} +#endif + +/** + * @brief Specifies which particle fields to write to a dataset + * + * Nothing to write for this scheme. + * + * @param xparts The extended particle array. + * @param list The list of i/o properties to write. + * @param cooling The #cooling_function_data + * + * @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 cooling_function_data* cooling) { + + return 0; +} + +#endif /* SWIFT_COOLING_IO_COMPTON_H */ diff --git a/src/cooling/Compton/cooling_struct.h b/src/cooling/Compton/cooling_struct.h new file mode 100644 index 0000000000000000000000000000000000000000..1e09d492b1c8f6eb92f9d4f5faa00998dc2daec9 --- /dev/null +++ b/src/cooling/Compton/cooling_struct.h @@ -0,0 +1,56 @@ +/******************************************************************************* + * 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_COOLING_STRUCT_COMPTON_H +#define SWIFT_COOLING_STRUCT_COMPTON_H + +/** + * @brief Properties of the cooling function. + */ +struct cooling_function_data { + + /*! Compton rate in cgs [g cm^2 s^-3 K^-1] */ + double const_Compton_rate_cgs; + + /*! Temperature of the CMB at redshift 0 in cgs [K] */ + double const_T_CMB_0; + + /*! Conversion factor from internal units to cgs for density */ + double conv_factor_density_to_cgs; + + /*! Conversion factor from internal units to cgs for internal energy */ + double conv_factor_energy_to_cgs; + + /*! Conversion factor from internal units from cgs for internal energy + * derivative */ + double conv_factor_energy_rate_from_cgs; + + /*! Inverse of the proton mass in cgs units [g^-1] */ + double proton_mass_cgs_inv; +}; + +/** + * @brief Properties of the cooling stored in the particle data. + */ +struct cooling_xpart_data { + + /*! Energy radiated away by this particle since the start of the run */ + float radiated_energy; +}; + +#endif /* SWIFT_COOLING_STRUCT_COMPTON_H */ diff --git a/src/cooling/EAGLE/cooling.h b/src/cooling/EAGLE/cooling.h index 1c56572856a88d763d5ef7ca77e14d378891a264..8d74222c78deab0e6790a06dca847033556833a7 100644 --- a/src/cooling/EAGLE/cooling.h +++ b/src/cooling/EAGLE/cooling.h @@ -54,8 +54,10 @@ __attribute__((always_inline)) INLINE static void cooling_cool_part( const struct phys_const* restrict phys_const, const struct unit_system* restrict us, const struct cosmology* restrict cosmo, + const struct hydro_props* hydro_props, const struct cooling_function_data* restrict cooling, - struct part* restrict p, struct xpart* restrict xp, float dt) {} + struct part* restrict p, struct xpart* restrict xp, const float dt, + const float dt_therm) {} /** * @brief Computes the cooling time-step. @@ -70,7 +72,9 @@ __attribute__((always_inline)) INLINE static float cooling_timestep( const struct cooling_function_data* restrict cooling, const struct phys_const* restrict phys_const, const struct cosmology* restrict cosmo, - const struct unit_system* restrict us, const struct part* restrict p) { + const struct unit_system* restrict us, + const struct hydro_props* hydro_props, const struct part* restrict p, + const struct xpart* restrict xp) { return FLT_MAX; } diff --git a/src/cooling/EAGLE/cooling_io.h b/src/cooling/EAGLE/cooling_io.h index f98539605de5c231a821758e9bd8fdb89bd19a59..b8f89717b450719a90c13e26ec07a51738b35f49 100644 --- a/src/cooling/EAGLE/cooling_io.h +++ b/src/cooling/EAGLE/cooling_io.h @@ -28,13 +28,13 @@ #ifdef HAVE_HDF5 /** - * @brief Writes the current model of SPH to the file - * @param h_grpsph The HDF5 group in which to write + * @brief Writes the current model of cooling to the file + * @param h_grp The HDF5 group in which to write */ __attribute__((always_inline)) INLINE static void cooling_write_flavour( - hid_t h_grpsph) { + hid_t h_grp, const struct cooling_function_data* cooling) { - io_write_attribute_s(h_grpsph, "Cooling Model", "EAGLE"); + io_write_attribute_s(h_grp, "Cooling Model", "EAGLE"); } #endif diff --git a/src/cooling/const_du/cooling.h b/src/cooling/const_du/cooling.h index b6fea7eea7b0fb208c4bffece425ec836d5df0c0..1c009886d2a08b62070162a80c4572aa43d35e3e 100644 --- a/src/cooling/const_du/cooling.h +++ b/src/cooling/const_du/cooling.h @@ -25,9 +25,9 @@ * @file src/cooling/const_du/cooling.h * @brief Routines related to the "constant cooling" cooling function. * - * This is the simplest possible cooling function. A constant cooling rate with - * a minimal energy floor is applied. Should be used as a template for more - * realistic functions. + * This is the simplest possible cooling function. A constant cooling rate + * (du/dt) with a minimal energy floor is applied. Should be used as a template + * for more realistic functions. */ /* Config parameters. */ @@ -54,26 +54,30 @@ * @param phys_const The physical constants in internal units. * @param us The internal system of units. * @param cosmo The current cosmological model. + * @param hydro_props The properties of the hydro scheme. * @param cooling The #cooling_function_data used in the run. * @param p Pointer to the particle data. * @param xp Pointer to the extended particle data. * @param dt The time-step of this particle. + * @param dt_therm The time-step operator used for thermal quantities. */ __attribute__((always_inline)) INLINE static void cooling_cool_part( const struct phys_const* restrict phys_const, const struct unit_system* restrict us, const struct cosmology* restrict cosmo, + const struct hydro_props* hydro_props, const struct cooling_function_data* restrict cooling, - struct part* restrict p, struct xpart* restrict xp, float dt) { + struct part* restrict p, struct xpart* restrict xp, const float dt, + const float dt_therm) { /* Internal energy floor */ const float u_floor = cooling->min_energy; /* Get current internal energy */ - const float u_old = hydro_get_physical_internal_energy(p, cosmo); + const float u_old = hydro_get_physical_internal_energy(p, xp, cosmo); /* Current du_dt */ - const float hydro_du_dt = hydro_get_internal_energy_dt(p); + const float hydro_du_dt = hydro_get_physical_internal_energy_dt(p, cosmo); /* Get cooling function properties */ float cooling_du_dt = -cooling->cooling_rate; @@ -86,7 +90,7 @@ __attribute__((always_inline)) INLINE static void cooling_cool_part( } /* Update the internal energy time derivative */ - hydro_set_internal_energy_dt(p, hydro_du_dt + cooling_du_dt); + hydro_set_physical_internal_energy_dt(p, cosmo, hydro_du_dt + cooling_du_dt); /* Store the radiated energy */ xp->cooling_data.radiated_energy += -hydro_get_mass(p) * cooling_du_dt * dt; @@ -103,16 +107,21 @@ __attribute__((always_inline)) INLINE static void cooling_cool_part( * @param phys_const The physical constants in internal units. * @param cosmo The current cosmological model. * @param us The internal system of units. + * @param hydro_props The properties of the hydro scheme. * @param p Pointer to the particle data. + * @param xp Pointer to the extedended particle data. */ __attribute__((always_inline)) INLINE static float cooling_timestep( const struct cooling_function_data* restrict cooling, const struct phys_const* restrict phys_const, const struct cosmology* restrict cosmo, - const struct unit_system* restrict us, const struct part* restrict p) { + const struct unit_system* restrict us, + const struct hydro_props* hydro_props, const struct part* restrict p, + const struct xpart* xp) { const float cooling_rate = cooling->cooling_rate; - const float internal_energy = hydro_get_physical_internal_energy(p, cosmo); + const float internal_energy = + hydro_get_physical_internal_energy(p, xp, cosmo); return cooling->cooling_tstep_mult * internal_energy / fabsf(cooling_rate); } @@ -126,7 +135,10 @@ __attribute__((always_inline)) INLINE static float cooling_timestep( * * @param p Pointer to the particle data. * @param xp Pointer to the extended particle data. + * @param phys_const The physical constants in internal units. * @param cooling The properties of the cooling function. + * @param us The internal system of units. + * @param cosmo The current cosmological model. */ __attribute__((always_inline)) INLINE static void cooling_first_init_part( const struct phys_const* restrict phys_const, diff --git a/src/cooling/const_du/cooling_io.h b/src/cooling/const_du/cooling_io.h index 52a943aca86e51665fd1841d7bcb8a100b046ed8..f4a327f14ec071bc62c4cf57bb118df71bab2b3e 100644 --- a/src/cooling/const_du/cooling_io.h +++ b/src/cooling/const_du/cooling_io.h @@ -21,6 +21,15 @@ #ifndef SWIFT_COOLING_CONST_DU_IO_H #define SWIFT_COOLING_CONST_DU_IO_H +/** + * @file src/cooling/const_du/cooling_io.h + * @brief i/o routines related to the "constant cooling" cooling function. + * + * This is the simplest possible cooling function. A constant cooling rate + * (du/dt) with a minimal energy floor is applied. Should be used as a template + * for more realistic functions. + */ + /* Config parameters. */ #include "../config.h" @@ -31,19 +40,20 @@ /** * @brief Writes the current model of SPH to the file - * @param h_grpsph The HDF5 group in which to write + * @param h_grp The HDF5 group in which to write + * @param cooling the parameters of the cooling function. */ __attribute__((always_inline)) INLINE static void cooling_write_flavour( - hid_t h_grpsph) { + hid_t h_grp, const struct cooling_function_data* cooling) { - io_write_attribute_s(h_grpsph, "Cooling Model", "Constant du/dt"); + io_write_attribute_s(h_grp, "Cooling Model", "Constant du/dt"); } #endif /** * @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 * diff --git a/src/cooling/const_du/cooling_struct.h b/src/cooling/const_du/cooling_struct.h index cc00b001cf6b576266de02dac885f87d089bd8e4..94db6b6542cacda6dbdc43c6db6b9c2cac7961d6 100644 --- a/src/cooling/const_du/cooling_struct.h +++ b/src/cooling/const_du/cooling_struct.h @@ -23,11 +23,11 @@ /** * @file src/cooling/const_du/cooling_struct.h - * @brief Structure related to the "constant cooling" cooling function. + * @brief Structures related to the "constant cooling" cooling function. * - * This is the simplest possible cooling function. A constant cooling rate with - * a minimal energy floor is applied. Should be used as a template for more - * realistic functions. + * This is the simplest possible cooling function. A constant cooling rate + * (du/dt) with a minimal energy floor is applied. Should be used as a template + * for more realistic functions. */ /** diff --git a/src/cooling/const_lambda/cooling.h b/src/cooling/const_lambda/cooling.h index f1a7abdbe14a39d98bbd01eb36ba870c8af0ee1a..83794edd0fd36c392cc64c14cad0c5e19b77f86a 100644 --- a/src/cooling/const_lambda/cooling.h +++ b/src/cooling/const_lambda/cooling.h @@ -1,8 +1,6 @@ /******************************************************************************* * This file is part of SWIFT. - * Copyright (c) 2016 Tom Theuns (tom.theuns@durham.ac.uk) - * Matthieu Schaller (matthieu.schaller@durham.ac.uk) - * Richard Bower (r.g.bower@durham.ac.uk) + * Copyright (c) 2018 Matthieu Schaller (matthieu.schaller@durham.ac.uk) * Stefan Arridge (stefan.arridge@durham.ac.uk) * * This program is free software: you can redistribute it and/or modify @@ -19,10 +17,17 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * ******************************************************************************/ - #ifndef SWIFT_COOLING_CONST_LAMBDA_H #define SWIFT_COOLING_CONST_LAMBDA_H +/** + * @file src/cooling/const_lambda/cooling.h + * @brief Routines related to the "constant lambda" cooling function. + * + * This model assumes a constant cooling rate Lambda irrespective of redshift + * or density. + */ + /* Config parameters. */ #include "../config.h" @@ -40,30 +45,39 @@ #include "units.h" /** - * @brief Calculates du/dt in code units for a particle. + * @brief Calculates du/dt in CGS units for a particle. + * + * The cooling rate is \f$\frac{du}{dt} = -\frac{\Lambda}{n_H^2} + * \frac{n_H^2}{\rho} \f$, where \f$ \frac{\Lambda}{n_H^2} \f$ is a constant in + * this model (lambda_nH2_cgs in #cooling_function_data). + * The returned value is in physical [erg * g^-1 * s^-1]. * - * @param phys_const The physical constants in internal units. - * @param us The internal system of units. * @param cosmo The current cosmological model. + * @param hydro_props The properties of the hydro scheme. * @param cooling The #cooling_function_data used in the run. - * @param p Pointer to the particle data.. + * @param p Pointer to the particle data. + * @return The change in energy per unit mass due to cooling for this particle + * in cgs units [erg * g^-1 * s^-1]. */ -__attribute__((always_inline)) INLINE static float cooling_rate( - const struct phys_const* const phys_const, const struct unit_system* us, - const struct cosmology* restrict cosmo, +__attribute__((always_inline)) INLINE static double cooling_rate_cgs( + const struct cosmology* cosmo, const struct hydro_props* hydro_props, const struct cooling_function_data* cooling, const struct part* p) { - /* Get particle density */ - const float rho = hydro_get_physical_density(p, cosmo); + /* Get particle density [g * cm^-3] */ + const double rho = hydro_get_physical_density(p, cosmo); + const double rho_cgs = rho * cooling->conv_factor_density_to_cgs; + + /* Get Hydrogen mass fraction */ + const double X_H = hydro_props->hydrogen_mass_fraction; - /* Get cooling function properties */ - const float X_H = cooling->hydrogen_mass_abundance; + /* Hydrogen number density (X_H * rho / m_p) [cm^-3] */ + const double n_H_cgs = X_H * rho_cgs * cooling->proton_mass_cgs_inv; - /* Calculate du_dt */ - const float du_dt = -cooling->lambda * - (X_H * rho / phys_const->const_proton_mass) * - (X_H * rho / phys_const->const_proton_mass) / rho; - return du_dt; + /* Calculate du_dt ((Lambda / n_H^2) * n_H^2 / rho) */ + const double du_dt_cgs = + -cooling->lambda_nH2_cgs * n_H_cgs * n_H_cgs / rho_cgs; + + return du_dt_cgs; } /** @@ -72,75 +86,125 @@ __attribute__((always_inline)) INLINE static float cooling_rate( * @param phys_const The physical constants in internal units. * @param us The internal system of units. * @param cosmo The current cosmological model. + * @param hydro_props The properties of the hydro scheme. * @param cooling The #cooling_function_data used in the run. * @param p Pointer to the particle data. + * @param xp Pointer to the particle' extended data. * @param dt The time-step of this particle. + * @param dt_therm The time-step operator used for thermal quantities. */ __attribute__((always_inline)) INLINE static void cooling_cool_part( const struct phys_const* restrict phys_const, const struct unit_system* restrict us, const struct cosmology* restrict cosmo, + const struct hydro_props* hydro_props, const struct cooling_function_data* restrict cooling, - struct part* restrict p, struct xpart* restrict xp, float dt) { + struct part* restrict p, struct xpart* restrict xp, const float dt, + const float dt_therm) { + + /* Nothing to do here? */ + if (dt == 0.) return; /* Internal energy floor */ - const float u_floor = cooling->min_energy; + const float u_floor = hydro_props->minimal_internal_energy; /* Current energy */ - const float u_old = hydro_get_physical_internal_energy(p, cosmo); + const float u_old = hydro_get_physical_internal_energy(p, xp, cosmo); + + /* Current du_dt in physical coordinates (internal units) */ + 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 = + cooling_rate_cgs(cosmo, hydro_props, cooling, p); + + /* Convert to internal units */ + float cooling_du_dt = + cooling_du_dt_cgs * cooling->conv_factor_energy_rate_from_cgs; + + /* Add cosmological term */ + cooling_du_dt *= cosmo->a * cosmo->a; - /* Current du_dt */ - const float hydro_du_dt = hydro_get_internal_energy_dt(p); + float total_du_dt = hydro_du_dt + cooling_du_dt; - /* Calculate cooling du_dt */ - float cooling_du_dt = cooling_rate(phys_const, us, cosmo, cooling, p); + /* We now need to check that we are not going to go below any of the limits */ - /* Integrate cooling equation to enforce energy floor */ - /* Factor of 1.5 included since timestep could potentially double */ - if (u_old + (hydro_du_dt + cooling_du_dt) * 1.5f * dt < u_floor) { - cooling_du_dt = -(u_old + 1.5f * dt * hydro_du_dt - u_floor) / (1.5f * dt); + /* First, check whether we may end up below the minimal energy after + * this step 1/2 kick + another 1/2 kick that could potentially be for + * a time-step twice as big. We hence check for 1.5 delta_t. */ + if (u_old + total_du_dt * 1.5 * dt_therm < u_floor) { + total_du_dt = (u_floor - u_old) / (1.5f * dt_therm); + } + + /* Second, check whether the energy used in the prediction could get negative. + * We need to check for the 1/2 dt kick followed by a full time-step drift + * that could potentially be for a time-step twice as big. We hence check + * for 2.5 delta_t but this time against 0 energy not the minimum */ + if (u_old + total_du_dt * 2.5 * dt_therm < 0.) { + total_du_dt = -u_old / ((2.5f + 0.0001f) * dt_therm); } /* Update the internal energy time derivative */ - hydro_set_internal_energy_dt(p, hydro_du_dt + cooling_du_dt); + hydro_set_physical_internal_energy_dt(p, cosmo, total_du_dt); - /* Store the radiated energy */ - xp->cooling_data.radiated_energy += -hydro_get_mass(p) * cooling_du_dt * dt; + /* Store the radiated energy (assuming dt will not change) */ + xp->cooling_data.radiated_energy += + -hydro_get_mass(p) * (total_du_dt - hydro_du_dt) * dt_therm; } /** - * @brief Computes the time-step due to cooling + * @brief Computes the time-step due to cooling for this particle. + * + * We compute a time-step \f$ \alpha \frac{u}{du/dt} \f$ in physical + * coordinates. \f$\alpha\f$ is a parameter of the cooling function. * * @param cooling The #cooling_function_data used in the run. * @param phys_const The physical constants in internal units. * @param cosmo The current cosmological model. + * @param hydro_props The properties of the hydro scheme. * @param us The internal system of units. * @param p Pointer to the particle data. + * @param xp Pointer to the extended data of the particle. */ __attribute__((always_inline)) INLINE static float cooling_timestep( const struct cooling_function_data* restrict cooling, const struct phys_const* restrict phys_const, const struct cosmology* restrict cosmo, - const struct unit_system* restrict us, const struct part* restrict p) { + const struct unit_system* restrict us, + const struct hydro_props* hydro_props, const struct part* restrict p, + const struct xpart* restrict xp) { - /* Get current internal energy */ - const float u = hydro_get_physical_internal_energy(p, cosmo); - const float du_dt = cooling_rate(phys_const, us, cosmo, cooling, p); + /* Start with the case where there is no limit */ + if (cooling->cooling_tstep_mult == FLT_MAX) return FLT_MAX; - /* If we are close to (or below) the energy floor, we ignore the condition */ - if (u < 1.01f * cooling->min_energy) + /* Get current internal energy and cooling rate */ + const float u = hydro_get_physical_internal_energy(p, xp, cosmo); + const double cooling_du_dt_cgs = + cooling_rate_cgs(cosmo, hydro_props, cooling, p); + + /* Convert to internal units */ + const float cooling_du_dt = + cooling_du_dt_cgs * cooling->conv_factor_energy_rate_from_cgs; + + /* If we are close to (or below) the limit, we ignore the condition */ + if (u < 1.01f * hydro_props->minimal_internal_energy || cooling_du_dt == 0.f) return FLT_MAX; else - return cooling->cooling_tstep_mult * u / fabsf(du_dt); + return cooling->cooling_tstep_mult * u / fabsf(cooling_du_dt); } /** * @brief Sets the cooling properties of the (x-)particles to a valid start * state. * + * Nothing to do here. Just set the radiated energy counter to 0. + * + * @param phys_const The physical constants in internal units. + * @param cooling The properties of the cooling function. + * @param us The internal system of units. + * @param cosmo The current cosmological model. * @param p Pointer to the particle data. * @param xp Pointer to the extended particle data. - * @param cooling The properties of the cooling function. */ __attribute__((always_inline)) INLINE static void cooling_first_init_part( const struct phys_const* restrict phys_const, @@ -176,30 +240,23 @@ static INLINE void cooling_init_backend(struct swift_params* parameter_file, const struct phys_const* phys_const, struct cooling_function_data* cooling) { - const double lambda_cgs = - parser_get_param_double(parameter_file, "LambdaCooling:lambda_cgs"); - const float min_temperature = parser_get_param_double( - parameter_file, "LambdaCooling:minimum_temperature"); - cooling->hydrogen_mass_abundance = parser_get_param_double( - parameter_file, "LambdaCooling:hydrogen_mass_abundance"); - cooling->mean_molecular_weight = parser_get_param_double( - parameter_file, "LambdaCooling:mean_molecular_weight"); - cooling->cooling_tstep_mult = parser_get_param_double( - parameter_file, "LambdaCooling:cooling_tstep_mult"); - - /* convert minimum temperature into minimum internal energy */ - const float u_floor = - phys_const->const_boltzmann_k * min_temperature / - (hydro_gamma_minus_one * cooling->mean_molecular_weight * - phys_const->const_proton_mass); - - cooling->min_energy = u_floor; - - /* convert lambda to code units */ - cooling->lambda = lambda_cgs * - units_cgs_conversion_factor(us, UNIT_CONV_TIME) / - (units_cgs_conversion_factor(us, UNIT_CONV_ENERGY) * - units_cgs_conversion_factor(us, UNIT_CONV_VOLUME)); + /* Read in the cooling parameters */ + cooling->lambda_nH2_cgs = + parser_get_param_double(parameter_file, "LambdaCooling:lambda_nH2_cgs"); + cooling->cooling_tstep_mult = parser_get_opt_param_float( + parameter_file, "LambdaCooling:cooling_tstep_mult", FLT_MAX); + + /* Some useful conversion values */ + cooling->conv_factor_density_to_cgs = + units_cgs_conversion_factor(us, UNIT_CONV_DENSITY); + cooling->conv_factor_energy_rate_from_cgs = + units_cgs_conversion_factor(us, UNIT_CONV_TIME) / + units_cgs_conversion_factor(us, UNIT_CONV_ENERGY_PER_UNIT_MASS); + + /* Useful constants */ + cooling->proton_mass_cgs_inv = + 1. / (phys_const->const_proton_mass * + units_cgs_conversion_factor(us, UNIT_CONV_MASS)); } /** @@ -211,11 +268,16 @@ static INLINE void cooling_print_backend( const struct cooling_function_data* cooling) { message( - "Cooling function is 'Constant lambda' with " - "(lambda,min_energy,hydrogen_mass_abundance,mean_molecular_weight) " - "= (%g,%g,%g,%g)", - cooling->lambda, cooling->min_energy, cooling->hydrogen_mass_abundance, - cooling->mean_molecular_weight); + "Cooling function is 'Constant lambda' with Lambda/n_H^2=%g [erg * s^-1 " + "* " + "cm^3]", + cooling->lambda_nH2_cgs); + + if (cooling->cooling_tstep_mult == FLT_MAX) + message("Cooling function time-step size is unlimited"); + else + message("Cooling function time-step size limited to %f of u/(du/dt)", + cooling->cooling_tstep_mult); } #endif /* SWIFT_COOLING_CONST_LAMBDA_H */ diff --git a/src/cooling/const_lambda/cooling_io.h b/src/cooling/const_lambda/cooling_io.h index 89c9471a291a4a6a5740a8c6c816913cbc6316a0..0dca5011ebe5bc6c2a4866387e9cf1ac0ba3447a 100644 --- a/src/cooling/const_lambda/cooling_io.h +++ b/src/cooling/const_lambda/cooling_io.h @@ -1,8 +1,6 @@ /******************************************************************************* * This file is part of SWIFT. - * Copyright (c) 2016 Tom Theuns (tom.theuns@durham.ac.uk) - * Matthieu Schaller (matthieu.schaller@durham.ac.uk) - * Richard Bower (r.g.bower@durham.ac.uk) + * Copyright (c) 2018 Matthieu Schaller (matthieu.schaller@durham.ac.uk) * Stefan Arridge (stefan.arridge@durham.ac.uk) * * This program is free software: you can redistribute it and/or modify @@ -22,6 +20,14 @@ #ifndef SWIFT_COOLING_CONST_LAMBDA_IO_H #define SWIFT_COOLING_CONST_LAMBDA_IO_H +/** + * @file src/cooling/const_lambda/cooling_io.h + * @brief i/o routines related to the "constant lambda" cooling function. + * + * This model assumes a constant cooling rate Lambda irrespective of redshift + * or density. + */ + /* Config parameters. */ #include "../config.h" @@ -31,20 +37,24 @@ #ifdef HAVE_HDF5 /** - * @brief Writes the current model of SPH to the file - * @param h_grpsph The HDF5 group in which to write + * @brief Writes the current model of cooling to the file + * @param h_grp The HDF5 group in which to write + * @param cooling the parameters of the cooling function. */ __attribute__((always_inline)) INLINE static void cooling_write_flavour( - hid_t h_grpsph) { + hid_t h_grp, const struct cooling_function_data* cooling) { - io_write_attribute_s(h_grpsph, "Cooling Model", "Constant Lambda"); + io_write_attribute_s(h_grp, "Cooling Model", "Constant Lambda"); + io_write_attribute_d(h_grp, "Lambda/n_H^2 [cgs]", cooling->lambda_nH2_cgs); } #endif /** * @brief Specifies which particle fields to write to a dataset * - * @param parts The particle array. + * Nothing to write for this scheme. + * + * @param xparts The extended particle array. * @param list The list of i/o properties to write. * @param cooling The #cooling_function_data * @@ -53,6 +63,7 @@ __attribute__((always_inline)) INLINE static void cooling_write_flavour( __attribute__((always_inline)) INLINE static int cooling_write_particles( const struct xpart* xparts, struct io_props* list, const struct cooling_function_data* cooling) { + return 0; } diff --git a/src/cooling/const_lambda/cooling_struct.h b/src/cooling/const_lambda/cooling_struct.h index 30d4e5e4af9c7bd139337709897d8111f88d2aa8..cc671a857887af90bda630e757af1b044b479e49 100644 --- a/src/cooling/const_lambda/cooling_struct.h +++ b/src/cooling/const_lambda/cooling_struct.h @@ -1,8 +1,6 @@ /******************************************************************************* * This file is part of SWIFT. - * Copyright (c) 2016 Tom Theuns (tom.theuns@durham.ac.uk) - * Matthieu Schaller (matthieu.schaller@durham.ac.uk) - * Richard Bower (r.g.bower@durham.ac.uk) + * Copyright (c) 2018 Matthieu Schaller (matthieu.schaller@durham.ac.uk) * Stefan Arridge (stefan.arridge@durham.ac.uk) * * This program is free software: you can redistribute it and/or modify @@ -19,26 +17,34 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * ******************************************************************************/ - #ifndef SWIFT_COOLING_STRUCT_CONST_LAMBDA_H #define SWIFT_COOLING_STRUCT_CONST_LAMBDA_H +/** + * @file src/cooling/const_lambda/cooling_struct.h + * @brief Structures related to the "constant lambda" cooling function. + * + * This model assumes a constant cooling rate Lambda irrespective of redshift + * or density. + */ + /** * @brief Properties of the cooling function. */ struct cooling_function_data { - /*! Cooling rate in internal units */ - double lambda; + /*! Cooling rate / nH^2 in physical cgs units [erg * s^-1 * cm^3] */ + double lambda_nH2_cgs; - /*! Fraction of gas mass that is Hydrogen. Used to calculate n_H */ - float hydrogen_mass_abundance; + /*! Conversion factor from internal units to cgs for density */ + double conv_factor_density_to_cgs; - /*! 'mu', used to convert min_temperature to min_internal energy */ - float mean_molecular_weight; + /*! Conversion factor from internal units from cgs for internal energy + * derivative */ + double conv_factor_energy_rate_from_cgs; - /*! Minimally allowed internal energy of all the particles */ - float min_energy; + /*! Inverse of the proton mass in cgs units [g^-1] */ + double proton_mass_cgs_inv; /*! Constant multiplication factor for time-step criterion */ float cooling_tstep_mult; diff --git a/src/cooling/grackle/cooling.h b/src/cooling/grackle/cooling.h index cb77b63294aacee425b917c1900eefd7ebfa5f34..479b1c8288cc12b12743c50684cb8b2af4d3a411 100644 --- a/src/cooling/grackle/cooling.h +++ b/src/cooling/grackle/cooling.h @@ -36,6 +36,7 @@ /* Local includes. */ #include "chemistry.h" +#include "cooling_io.h" #include "error.h" #include "hydro.h" #include "parser.h" @@ -491,6 +492,12 @@ __attribute__((always_inline)) INLINE static gr_float cooling_rate( const struct cooling_function_data* restrict cooling, const struct part* restrict p, struct xpart* restrict xp, double dt) { + if (cosmo->Omega_m != 0. || cosmo->Omega_r != 0. || cosmo->Omega_k != 0. || + cosmo->Omega_lambda != 0. || cosmo->Omega_b != 0.) + error( + "Check cosmology factors (physical vs. co-moving and drifted vs. " + "un-drifted)!"); + /* set current time */ code_units units = cooling->units; if (cooling->redshift == -1) @@ -515,7 +522,8 @@ __attribute__((always_inline)) INLINE static gr_float cooling_rate( /* general particle data */ gr_float density = hydro_get_physical_density(p, cosmo); - const double energy_before = hydro_get_physical_internal_energy(p, cosmo); + const double energy_before = + hydro_get_drifted_physical_internal_energy(p, cosmo); gr_float energy = energy_before; /* initialize density */ @@ -534,22 +542,11 @@ __attribute__((always_inline)) INLINE static gr_float cooling_rate( /* solve chemistry */ chemistry_data chemistry_grackle = cooling->chemistry; - chemistry_data_storage my_rates = grackle_rates; - int error_code = _solve_chemistry( - &chemistry_grackle, &my_rates, &units, dt, data.grid_dx, data.grid_rank, - data.grid_dimension, data.grid_start, data.grid_end, data.density, - data.internal_energy, data.x_velocity, data.y_velocity, data.z_velocity, - data.HI_density, data.HII_density, data.HM_density, data.HeI_density, - data.HeII_density, data.HeIII_density, data.H2I_density, - data.H2II_density, data.DI_density, data.DII_density, data.HDI_density, - data.e_density, data.metal_density, data.volumetric_heating_rate, - data.specific_heating_rate, data.RT_heating_rate, - data.RT_HI_ionization_rate, data.RT_HeI_ionization_rate, - data.RT_HeII_ionization_rate, data.RT_H2_dissociation_rate, NULL); - if (error_code == 0) error("Error in solve_chemistry."); - // if (solve_chemistry(&units, &data, dt) == 0) { - // error("Error in solve_chemistry."); - //} + chemistry_data_storage chemistry_rates = grackle_rates; + if (local_solve_chemistry(&chemistry_grackle, &chemistry_rates, &units, &data, + dt) == 0) { + error("Error in solve_chemistry."); + } /* copy from grackle data to particle */ cooling_copy_from_grackle(data, p, xp, density); @@ -596,7 +593,8 @@ __attribute__((always_inline)) INLINE static gr_float cooling_time( data.grid_end = grid_end; /* general particle data */ - const gr_float energy_before = hydro_get_physical_internal_energy(p, cosmo); + const gr_float energy_before = + hydro_get_drifted_physical_internal_energy(p, cosmo); gr_float density = hydro_get_physical_density(p, cosmo); gr_float energy = energy_before; @@ -616,7 +614,10 @@ __attribute__((always_inline)) INLINE static gr_float cooling_time( /* Compute cooling time */ gr_float cooling_time; - if (calculate_cooling_time(&units, &data, &cooling_time) == 0) { + chemistry_data chemistry_grackle = cooling->chemistry; + chemistry_data_storage chemistry_rates = grackle_rates; + if (local_calculate_cooling_time(&chemistry_grackle, &chemistry_rates, &units, + &data, &cooling_time) == 0) { error("Error in calculate_cooling_time."); } @@ -641,13 +642,21 @@ __attribute__((always_inline)) INLINE static void cooling_cool_part( const struct phys_const* restrict phys_const, const struct unit_system* restrict us, const struct cosmology* restrict cosmo, + const struct hydro_props* hydro_props, const struct cooling_function_data* restrict cooling, - struct part* restrict p, struct xpart* restrict xp, double dt) { + struct part* restrict p, struct xpart* restrict xp, double dt, + double dt_therm) { + + if (cosmo->Omega_m != 0. || cosmo->Omega_r != 0. || cosmo->Omega_k != 0. || + cosmo->Omega_lambda != 0. || cosmo->Omega_b != 0.) + error( + "Check cosmology factors (physical vs. co-moving and drifted vs. " + "un-drifted)!"); if (dt == 0.) return; /* Current du_dt */ - const float hydro_du_dt = hydro_get_internal_energy_dt(p); + const float hydro_du_dt = hydro_get_physical_internal_energy_dt(p, cosmo); /* compute cooling rate */ const float du_dt = cooling_rate(phys_const, us, cosmo, cooling, p, xp, dt); @@ -656,7 +665,7 @@ __attribute__((always_inline)) INLINE static void cooling_cool_part( xp->cooling_data.radiated_energy += -du_dt * dt * hydro_get_mass(p); /* Update the internal energy */ - hydro_set_internal_energy_dt(p, hydro_du_dt + du_dt); + hydro_set_physical_internal_energy_dt(p, cosmo, hydro_du_dt + du_dt); } /** @@ -674,7 +683,9 @@ __attribute__((always_inline)) INLINE static float cooling_timestep( const struct cooling_function_data* restrict cooling, const struct phys_const* restrict phys_const, const struct cosmology* restrict cosmo, - const struct unit_system* restrict us, const struct part* restrict p) { + const struct unit_system* restrict us, + const struct hydro_props* hydro_props, const struct part* restrict p, + const struct xpart* restrict xp) { return FLT_MAX; } diff --git a/src/cooling/grackle/cooling_io.h b/src/cooling/grackle/cooling_io.h index faf84cf97d8449d54f2727ec26b16a9d81d117c6..684ab347e19c8ea5f1897a54f21951256ef5f50b 100644 --- a/src/cooling/grackle/cooling_io.h +++ b/src/cooling/grackle/cooling_io.h @@ -29,20 +29,20 @@ #ifdef HAVE_HDF5 /** - * @brief Writes the current model of SPH to the file - * @param h_grpsph The HDF5 group in which to write + * @brief Writes the current model of cooling to the file + * @param h_grp The HDF5 group in which to write */ __attribute__((always_inline)) INLINE static void cooling_write_flavour( - hid_t h_grpsph) { + hid_t h_grp, const struct cooling_function_data* cooling) { #if COOLING_GRACKLE_MODE == 0 - io_write_attribute_s(h_grpsph, "Cooling Model", "Grackle"); + io_write_attribute_s(h_grp, "Cooling Model", "Grackle"); #elif COOLING_GRACKLE_MODE == 1 - io_write_attribute_s(h_grpsph, "Cooling Model", "Grackle1"); + io_write_attribute_s(h_grp, "Cooling Model", "Grackle1"); #elif COOLING_GRACKLE_MODE == 2 - io_write_attribute_s(h_grpsph, "Cooling Model", "Grackle2"); + io_write_attribute_s(h_grp, "Cooling Model", "Grackle2"); #elif COOLING_GRACKLE_MODE == 3 - io_write_attribute_s(h_grpsph, "Cooling Model", "Grackle3"); + io_write_attribute_s(h_grp, "Cooling Model", "Grackle3"); #else error("This function should be called only with one of the Grackle cooling."); #endif diff --git a/src/cooling/grackle/cooling_struct.h b/src/cooling/grackle/cooling_struct.h index b714690ce4688268723748b29506e458cccc4be9..6d4b37a6240446d580818e16ff887c8079e319a6 100644 --- a/src/cooling/grackle/cooling_struct.h +++ b/src/cooling/grackle/cooling_struct.h @@ -16,14 +16,14 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * ******************************************************************************/ -#ifndef SWIFT_COOLING_STRUCT_NONE_H -#define SWIFT_COOLING_STRUCT_NONE_H +#ifndef SWIFT_COOLING_STRUCT_GRACKLE_H +#define SWIFT_COOLING_STRUCT_GRACKLE_H + +#include "../config.h" /* include grackle */ #include <grackle.h> -#include "../config.h" - /** * @file src/cooling/none/cooling_struct.h * @brief Empty infrastructure for the cases without cooling function @@ -113,4 +113,4 @@ struct cooling_xpart_data { float metal_frac; }; -#endif /* SWIFT_COOLING_STRUCT_NONE_H */ +#endif /* SWIFT_COOLING_STRUCT_GRACKLE_H */ diff --git a/src/cooling/none/cooling.h b/src/cooling/none/cooling.h index 0cc465adcdad8fe19afe4a9867e5d68a22ed9119..c21af9c3f1b491256e9f2a65f2f924fa606f665d 100644 --- a/src/cooling/none/cooling.h +++ b/src/cooling/none/cooling.h @@ -44,17 +44,21 @@ * @param phys_const The physical constants in internal units. * @param us The internal system of units. * @param cosmo The current cosmological model. + * @param hydro_props The properties of the hydro scheme. * @param cooling The #cooling_function_data used in the run. * @param p Pointer to the particle data. * @param xp Pointer to the extended particle data. * @param dt The time-step of this particle. + * @param dt_therm The time-step operator used for thermal quantities. */ __attribute__((always_inline)) INLINE static void cooling_cool_part( const struct phys_const* restrict phys_const, const struct unit_system* restrict us, const struct cosmology* restrict cosmo, + const struct hydro_props* hydro_props, const struct cooling_function_data* restrict cooling, - struct part* restrict p, struct xpart* restrict xp, float dt) {} + struct part* restrict p, struct xpart* restrict xp, const float dt, + const float dt_therm) {} /** * @brief Computes the cooling time-step. @@ -64,14 +68,18 @@ __attribute__((always_inline)) INLINE static void cooling_cool_part( * @param cooling The #cooling_function_data used in the run. * @param phys_const The physical constants in internal units. * @param cosmo The current cosmological model. + * @param hydro_props The properties of the hydro scheme. * @param us The internal system of units. * @param p Pointer to the particle data. + * @param xp Pointer to the extended data of the particle. */ __attribute__((always_inline)) INLINE static float cooling_timestep( const struct cooling_function_data* restrict cooling, const struct phys_const* restrict phys_const, const struct cosmology* restrict cosmo, - const struct unit_system* restrict us, const struct part* restrict p) { + const struct unit_system* restrict us, + const struct hydro_props* hydro_props, const struct part* restrict p, + const struct xpart* restrict xp) { return FLT_MAX; } diff --git a/src/cooling/none/cooling_io.h b/src/cooling/none/cooling_io.h index e4c84f506bcd31ff95ededb5be889fbf9a27261b..518c166480a0b81f6856c8a39e2a64d34369dc84 100644 --- a/src/cooling/none/cooling_io.h +++ b/src/cooling/none/cooling_io.h @@ -29,12 +29,13 @@ /** * @brief Writes the current model of SPH to the file - * @param h_grpsph The HDF5 group in which to write + * @param h_grp The HDF5 group in which to write + * @param cooling the parameters of the cooling function. */ __attribute__((always_inline)) INLINE static void cooling_write_flavour( - hid_t h_grpsph) { + hid_t h_grp, const struct cooling_function_data* cooling) { - io_write_attribute_s(h_grpsph, "Cooling Model", "None"); + io_write_attribute_s(h_grp, "Cooling Model", "None"); } #endif diff --git a/src/cooling_io.h b/src/cooling_io.h index 88eeae2cabdaa8a0909977b84a7dbcf03145d988..1ced353d7ff8320a48731545300274c654a20744 100644 --- a/src/cooling_io.h +++ b/src/cooling_io.h @@ -29,6 +29,8 @@ #include "./cooling/const_du/cooling_io.h" #elif defined(COOLING_CONST_LAMBDA) #include "./cooling/const_lambda/cooling_io.h" +#elif defined(COOLING_COMPTON) +#include "./cooling/Compton/cooling_io.h" #elif defined(COOLING_GRACKLE) #include "./cooling/grackle/cooling_io.h" #elif defined(COOLING_EAGLE) diff --git a/src/cooling_struct.h b/src/cooling_struct.h index 9c187d596e714fddaf60ae61323624569196ba70..93de8d1b7a0bcfd56d2b1a503aea1e8339bc8016 100644 --- a/src/cooling_struct.h +++ b/src/cooling_struct.h @@ -34,6 +34,8 @@ #include "./cooling/const_du/cooling_struct.h" #elif defined(COOLING_CONST_LAMBDA) #include "./cooling/const_lambda/cooling_struct.h" +#elif defined(COOLING_COMPTON) +#include "./cooling/Compton/cooling_struct.h" #elif defined(COOLING_GRACKLE) #include "./cooling/grackle/cooling_struct.h" #elif defined(COOLING_EAGLE) diff --git a/src/cosmology.c b/src/cosmology.c index f209997dd3faae3ba884632ffa41cca5d6ae0710..4718ed5b316e514476e3ec38dd8771136f3a2f69 100644 --- a/src/cosmology.c +++ b/src/cosmology.c @@ -157,6 +157,8 @@ void cosmology_update(struct cosmology *c, const struct phys_const *phys_const, pow(a, -3. * hydro_gamma + 2.); /* 1 / a^(3*gamma - 2) */ c->a_factor_mu = pow(a, 0.5 * (3. * hydro_gamma - 5.)); /* a^{(3*gamma - 5) / 2} */ + c->a_factor_Balsara_eps = + pow(a, 0.5 * (1. - 3. * hydro_gamma)); /* a^{(1 - 3*gamma) / 2} */ /* Redshift */ c->z = a_inv - 1.; @@ -487,6 +489,11 @@ void cosmology_init(struct swift_params *params, const struct unit_system *us, c->time_base = (c->log_a_end - c->log_a_begin) / max_nr_timesteps; c->time_base_inv = 1. / c->time_base; + /* If a_begin == a_end we hang */ + + if (c->a_begin >= c->a_end) + error("a_begin must be strictly before (and not equal to) a_end"); + /* Construct derived quantities */ /* Curvature density (for closure) */ @@ -502,6 +509,10 @@ void cosmology_init(struct swift_params *params, const struct unit_system *us, c->H0 = H0_cgs * units_cgs_conversion_factor(us, UNIT_CONV_TIME); c->Hubble_time = 1. / c->H0; + /* Critical density at present day */ + c->critical_density_0 = + 3. * c->H0 * c->H0 / (8. * M_PI * phys_const->const_newton_G); + /* Initialise the interpolation tables */ c->drift_fac_interp_table = NULL; c->grav_kick_fac_interp_table = NULL; @@ -543,6 +554,7 @@ void cosmology_init_no_cosmo(struct cosmology *c) { c->log_a_end = 0.; c->H = 0.; + c->H0 = 0.; c->a = 1.; c->z = 0.; c->a_inv = 1.; @@ -552,10 +564,12 @@ void cosmology_init_no_cosmo(struct cosmology *c) { c->a_factor_pressure = 1.; c->a_factor_sound_speed = 1.; c->a_factor_mu = 1.; + c->a_factor_Balsara_eps = 1.; c->a_factor_hydro_accel = 1.; c->a_factor_grav_accel = 1.; c->critical_density = 0.; + c->critical_density_0 = 0.; c->time_step_factor = 1.; diff --git a/src/cosmology.h b/src/cosmology.h index 4556b039bd0e306dab37a05bc200c3aa2ab8a602..d6b7dfbdc854a66f89c5511a5076c4fb4a7a5d3f 100644 --- a/src/cosmology.h +++ b/src/cosmology.h @@ -54,10 +54,12 @@ struct cosmology { /*! Power of the scale-factor used for sound-speed conversion to physical */ double a_factor_sound_speed; - /*! Power of the scale-factor used for relative velocities in viscosity term - */ + /*! Power of the scale-factor used for relative velocities in visc. terms */ double a_factor_mu; + /*! {ower of the scale-factor used for epsilon term in the Balsara switch */ + double a_factor_Balsara_eps; + /*! Power of the scale-factor used for gravity accelerations */ double a_factor_grav_accel; @@ -73,6 +75,9 @@ struct cosmology { /*! The critical density at the current redshift (in internal units) */ double critical_density; + /*! The critical density at redshift 0 (in internal units) */ + double critical_density_0; + /*! Conversion factor from internal time-step size to cosmological step */ double time_step_factor; diff --git a/src/debug.c b/src/debug.c index da8748df900869256bfbf4b1814e01bf5d60d804..a980ef9457a31d4b36f99926a24d7bc55822670a 100644 --- a/src/debug.c +++ b/src/debug.c @@ -172,8 +172,8 @@ int checkSpacehmax(struct space *s) { float cell_h_max = 0.0f; for (int k = 0; k < s->nr_cells; k++) { if (s->cells_top[k].nodeID == s->e->nodeID && - s->cells_top[k].h_max > cell_h_max) { - cell_h_max = s->cells_top[k].h_max; + s->cells_top[k].hydro.h_max > cell_h_max) { + cell_h_max = s->cells_top[k].hydro.h_max; } } @@ -191,9 +191,9 @@ int checkSpacehmax(struct space *s) { /* There is a problem. Hunt it down. */ for (int k = 0; k < s->nr_cells; k++) { if (s->cells_top[k].nodeID == s->e->nodeID) { - if (s->cells_top[k].h_max > part_h_max) { - message("cell %d is inconsistent (%f > %f)", k, s->cells_top[k].h_max, - part_h_max); + if (s->cells_top[k].hydro.h_max > part_h_max) { + message("cell %d is inconsistent (%f > %f)", k, + s->cells_top[k].hydro.h_max, part_h_max); } } } @@ -229,9 +229,9 @@ int checkCellhdxmax(const struct cell *c, int *depth) { const double loc_max[3] = {c->loc[0] + c->width[0], c->loc[1] + c->width[1], c->loc[2] + c->width[2]}; - const size_t nr_parts = c->count; - struct part *parts = c->parts; - struct xpart *xparts = c->xparts; + const size_t nr_parts = c->hydro.count; + struct part *parts = c->hydro.parts; + struct xpart *xparts = c->hydro.xparts; for (size_t k = 0; k < nr_parts; k++) { struct part *const p = &parts[k]; @@ -268,14 +268,15 @@ int checkCellhdxmax(const struct cell *c, int *depth) { } /* Check. */ - if (c->h_max != h_max) { - message("%d Inconsistent h_max: cell %f != parts %f", *depth, c->h_max, - h_max); + if (c->hydro.h_max != h_max) { + message("%d Inconsistent h_max: cell %f != parts %f", *depth, + c->hydro.h_max, h_max); message("location: %f %f %f", c->loc[0], c->loc[1], c->loc[2]); result = 0; } - if (c->dx_max_part != dx_max) { - message("%d Inconsistent dx_max: %f != %f", *depth, c->dx_max_part, dx_max); + if (c->hydro.dx_max_part != dx_max) { + message("%d Inconsistent dx_max: %f != %f", *depth, c->hydro.dx_max_part, + dx_max); message("location: %f %f %f", c->loc[0], c->loc[1], c->loc[2]); result = 0; } @@ -316,13 +317,13 @@ static void dumpCells_map(struct cell *c, void *data) { #endif /* Only cells with particles are dumped. */ - if (c->count > 0 || c->gcount > 0 || c->scount > 0) { + if (c->hydro.count > 0 || c->grav.count > 0 || c->stars.count > 0) { /* In MPI mode we may only output cells with foreign partners. * These define the edges of the partitions. */ int ismpiactive = 0; #if WITH_MPI - ismpiactive = (c->send_xv != NULL); + ismpiactive = (c->mpi.hydro.send_xv != NULL); if (mpiactive) mpiactive = ismpiactive; else @@ -347,14 +348,14 @@ static void dumpCells_map(struct cell *c, void *data) { /* If requested we work out how many particles are active in this cell. */ int pactcount = 0; if (pactive) { - const struct part *parts = c->parts; - for (int k = 0; k < c->count; k++) + const struct part *parts = c->hydro.parts; + for (int k = 0; k < c->hydro.count; k++) if (part_is_active(&parts[k], e)) pactcount++; - struct gpart *gparts = c->gparts; - for (int k = 0; k < c->gcount; k++) + struct gpart *gparts = c->grav.parts; + for (int k = 0; k < c->grav.count; k++) if (gpart_is_active(&gparts[k], e)) pactcount++; - struct spart *sparts = c->sparts; - for (int k = 0; k < c->scount; k++) + struct spart *sparts = c->stars.parts; + for (int k = 0; k < c->stars.count; k++) if (spart_is_active(&sparts[k], e)) pactcount++; } @@ -362,9 +363,9 @@ static void dumpCells_map(struct cell *c, void *data) { " %6.3f %6.3f %6.3f %6.3f %6.3f %6.3f %6d %6d %6d %6d %6d %6d " "%6.1f %20lld %6d %6d %6d %6d %6d %6d %6d\n", c->loc[0], c->loc[1], c->loc[2], c->width[0], c->width[1], - c->width[2], e->step, c->count, c->gcount, c->scount, pactcount, - c->depth, ntasks, c->ti_hydro_end_min, - get_time_bin(c->ti_hydro_end_min), (c->super == c), + c->width[2], e->step, c->hydro.count, c->grav.count, + c->stars.count, pactcount, c->depth, ntasks, c->hydro.ti_end_min, + get_time_bin(c->hydro.ti_end_min), (c->super == c), (c->parent == NULL), cell_is_active_hydro(c, e), c->nodeID, c->nodeID == e->nodeID, ismpiactive); } diff --git a/src/drift.h b/src/drift.h index ff0fea744012b7143afed2a05b286d4646cdd69a..351b15381dde9a95af908003b1c8df01b56610fa 100644 --- a/src/drift.h +++ b/src/drift.h @@ -137,6 +137,12 @@ __attribute__((always_inline)) INLINE static void drift_spart( sp->x[0] += sp->v[0] * dt_drift; sp->x[1] += sp->v[1] * dt_drift; sp->x[2] += sp->v[2] * dt_drift; + + /* Compute offsets since last cell construction */ + for (int k = 0; k < 3; k++) { + const float dx = sp->v[k] * dt_drift; + sp->x_diff[k] -= dx; + } } #endif /* SWIFT_DRIFT_H */ diff --git a/src/dump.c b/src/dump.c index ba50b517a72e71ab0ca5e791319c6336925762cb..9c519c2130b2612309e623b8234e3369214b52e2 100644 --- a/src/dump.c +++ b/src/dump.c @@ -48,17 +48,24 @@ */ void *dump_get(struct dump *d, size_t count, size_t *offset) { size_t local_offset = atomic_add(&d->count, count); +#ifdef SWIFT_DEBUG_CHECKS + if (d->count > d->size) error("Dump file is too small."); +#endif *offset = local_offset + d->file_offset; return (char *)d->data + local_offset; } /** * @brief Ensure that at least size bytes are available in the #dump. + * + * @param d The #dump. + * @param required_size The required size for the #dump + * @param increase_size If not enough size, increase by this amount */ -void dump_ensure(struct dump *d, size_t size) { +void dump_ensure(struct dump *d, size_t required_size, size_t increase_size) { /* If we have enough space already, just bail. */ - if (d->size - d->count > size) return; + if (d->size - d->count > required_size) return; /* Unmap the current data. */ if (munmap(d->data, d->size) != 0) { @@ -70,7 +77,7 @@ void dump_ensure(struct dump *d, size_t size) { const size_t trunc_count = d->count & d->page_mask; d->file_offset += trunc_count; d->count -= trunc_count; - d->size = (size * dump_grow_ensure_factor + ~d->page_mask) & d->page_mask; + d->size = (d->count + increase_size + ~d->page_mask) & d->page_mask; /* Re-allocate the file size. */ if (posix_fallocate(d->fd, d->file_offset, d->size) != 0) { @@ -121,7 +128,9 @@ void dump_close(struct dump *d) { */ void dump_init(struct dump *d, const char *filename, size_t size) { - /* Create the output file. */ + /* Create the output file. + The option O_RDWR seems to be required by mmap. + */ if ((d->fd = open(filename, O_CREAT | O_RDWR, 0660)) == -1) { error("Failed to create dump file '%s' (%s).", filename, strerror(errno)); } diff --git a/src/dump.h b/src/dump.h index 6857aa3a008a27e0e8ed23854d84f848ee0ca2be..021bc1e1dc22c178a893e42384c91fafdcf63112 100644 --- a/src/dump.h +++ b/src/dump.h @@ -27,9 +27,6 @@ /* Standard headers */ #include <stdlib.h> -/* Some constants. */ -#define dump_grow_ensure_factor 10 - /** The dump struct. */ struct dump { @@ -54,7 +51,7 @@ struct dump { /* Function prototypes. */ void dump_init(struct dump *d, const char *filename, size_t size); -void dump_ensure(struct dump *d, size_t size); +void dump_ensure(struct dump *d, size_t required_size, size_t increase_size); void dump_sync(struct dump *d); void dump_close(struct dump *d); void *dump_get(struct dump *d, size_t count, size_t *offset); diff --git a/src/engine.c b/src/engine.c index ac47c984c0ef4ef28fdcee3cbc99d22805e2b20c..816a02f193f63158975b545ad6ad0c8cc06c10e6 100644 --- a/src/engine.c +++ b/src/engine.c @@ -67,6 +67,8 @@ #include "gravity.h" #include "gravity_cache.h" #include "hydro.h" +#include "logger.h" +#include "logger_io.h" #include "map.h" #include "memswap.h" #include "minmax.h" @@ -112,6 +114,7 @@ const char *engine_policy_names[] = {"none", "stars", "fof search", "structure finding", + "star formation", "feedback"}; /** The rank of the engine as a global variable (for messages). */ @@ -122,7 +125,8 @@ int engine_rank; */ struct end_of_step_data { - size_t updates, g_updates, s_updates; + size_t updated, g_updated, s_updated; + size_t inhibited, g_inhibited, s_inhibited; integertime_t ti_hydro_end_min, ti_hydro_end_max, ti_hydro_beg_max; integertime_t ti_gravity_end_min, ti_gravity_end_max, ti_gravity_beg_max; struct engine *e; @@ -151,335 +155,6 @@ void engine_addlink(struct engine *e, struct link **l, struct task *t) { res->next = atomic_swap(l, res); } -/** - * @brief Recursively add non-implicit star ghost tasks to a cell hierarchy. - */ -void engine_add_stars_ghosts(struct engine *e, struct cell *c, - struct task *stars_ghost_in, - struct task *stars_ghost_out) { - - /* If we have reached the leaf OR have to few particles to play with*/ - if (!c->split || c->scount < engine_max_sparts_per_ghost) { - - /* Add the ghost task and its dependencies */ - struct scheduler *s = &e->sched; - c->stars_ghost = scheduler_addtask(s, task_type_stars_ghost, - task_subtype_none, 0, 0, c, NULL); - scheduler_addunlock(s, stars_ghost_in, c->stars_ghost); - scheduler_addunlock(s, c->stars_ghost, stars_ghost_out); - } else { - /* Keep recursing */ - for (int k = 0; k < 8; k++) - if (c->progeny[k] != NULL) - engine_add_stars_ghosts(e, c->progeny[k], stars_ghost_in, - stars_ghost_out); - } -} - -/** - * @brief Recursively add non-implicit ghost tasks to a cell hierarchy. - */ -void engine_add_ghosts(struct engine *e, struct cell *c, struct task *ghost_in, - struct task *ghost_out) { - - /* If we have reached the leaf OR have to few particles to play with*/ - if (!c->split || c->count < engine_max_parts_per_ghost) { - - /* Add the ghost task and its dependencies */ - struct scheduler *s = &e->sched; - c->ghost = - scheduler_addtask(s, task_type_ghost, task_subtype_none, 0, 0, c, NULL); - scheduler_addunlock(s, ghost_in, c->ghost); - scheduler_addunlock(s, c->ghost, ghost_out); - } else { - /* Keep recursing */ - for (int k = 0; k < 8; k++) - if (c->progeny[k] != NULL) - engine_add_ghosts(e, c->progeny[k], ghost_in, ghost_out); - } -} - -/** - * @brief Generate the hydro hierarchical tasks for a hierarchy of cells - - * i.e. all the O(Npart) tasks -- timestep version - * - * Tasks are only created here. The dependencies will be added later on. - * - * Note that there is no need to recurse below the super-cell. Note also - * that we only add tasks if the relevant particles are present in the cell. - * - * @param e The #engine. - * @param c The #cell. - */ -void engine_make_hierarchical_tasks_common(struct engine *e, struct cell *c) { - - struct scheduler *s = &e->sched; - const int is_with_cooling = (e->policy & engine_policy_cooling); - - /* Are we in a super-cell ? */ - if (c->super == c) { - - /* Local tasks only... */ - if (c->nodeID == e->nodeID) { - - /* Add the two half kicks */ - c->kick1 = scheduler_addtask(s, task_type_kick1, task_subtype_none, 0, 0, - c, NULL); - - c->kick2 = scheduler_addtask(s, task_type_kick2, task_subtype_none, 0, 0, - c, NULL); - - /* Add the time-step calculation task and its dependency */ - c->timestep = scheduler_addtask(s, task_type_timestep, task_subtype_none, - 0, 0, c, NULL); - - /* Add the task finishing the force calculation */ - c->end_force = scheduler_addtask(s, task_type_end_force, - task_subtype_none, 0, 0, c, NULL); - - if (is_with_cooling) { - - c->cooling = scheduler_addtask(s, task_type_cooling, task_subtype_none, - 0, 0, c, NULL); - - scheduler_addunlock(s, c->end_force, c->cooling); - scheduler_addunlock(s, c->cooling, c->kick2); - - } else { - scheduler_addunlock(s, c->end_force, c->kick2); - } - scheduler_addunlock(s, c->kick2, c->timestep); - scheduler_addunlock(s, c->timestep, c->kick1); - } - - } else { /* We are above the super-cell so need to go deeper */ - - /* Recurse. */ - if (c->split) - for (int k = 0; k < 8; k++) - if (c->progeny[k] != NULL) - engine_make_hierarchical_tasks_common(e, c->progeny[k]); - } -} - -/** - * @brief Generate the hydro hierarchical tasks for a hierarchy of cells - - * i.e. all the O(Npart) tasks -- hydro version - * - * Tasks are only created here. The dependencies will be added later on. - * - * Note that there is no need to recurse below the super-cell. Note also - * that we only add tasks if the relevant particles are present in the cell. - * - * @param e The #engine. - * @param c The #cell. - */ -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->super_hydro == c) { - - /* Add the sort task. */ - c->sorts = - scheduler_addtask(s, task_type_sort, task_subtype_none, 0, 0, c, NULL); - - /* Local tasks only... */ - if (c->nodeID == e->nodeID) { - - /* Add the drift task. */ - c->drift_part = scheduler_addtask(s, task_type_drift_part, - task_subtype_none, 0, 0, c, NULL); - - /* Generate the ghost tasks. */ - c->ghost_in = - scheduler_addtask(s, task_type_ghost_in, task_subtype_none, 0, - /* implicit = */ 1, c, NULL); - c->ghost_out = - scheduler_addtask(s, task_type_ghost_out, task_subtype_none, 0, - /* implicit = */ 1, c, NULL); - engine_add_ghosts(e, c, c->ghost_in, c->ghost_out); - -#ifdef EXTRA_HYDRO_LOOP - /* Generate the extra ghost task. */ - c->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 */ - - /* Recurse. */ - if (c->split) - for (int k = 0; k < 8; k++) - if (c->progeny[k] != NULL) - engine_make_hierarchical_tasks_hydro(e, c->progeny[k]); - } -} - -/** - * @brief Generate the hydro hierarchical tasks for a hierarchy of cells - - * i.e. all the O(Npart) tasks -- gravity version - * - * Tasks are only created here. The dependencies will be added later on. - * - * Note that there is no need to recurse below the super-cell. Note also - * that we only add tasks if the relevant particles are present in the cell. - * - * @param e The #engine. - * @param c The #cell. - */ -void engine_make_hierarchical_tasks_gravity(struct engine *e, struct cell *c) { - - struct scheduler *s = &e->sched; - const int periodic = e->s->periodic; - const int is_self_gravity = (e->policy & engine_policy_self_gravity); - - /* Are we in a super-cell ? */ - if (c->super_gravity == c) { - - /* Local tasks only... */ - if (c->nodeID == e->nodeID) { - - c->drift_gpart = scheduler_addtask(s, task_type_drift_gpart, - task_subtype_none, 0, 0, c, NULL); - - if (is_self_gravity) { - - /* Initialisation of the multipoles */ - c->init_grav = scheduler_addtask(s, task_type_init_grav, - task_subtype_none, 0, 0, c, NULL); - - /* Gravity non-neighbouring pm calculations */ - c->grav_long_range = scheduler_addtask( - s, task_type_grav_long_range, task_subtype_none, 0, 0, c, NULL); - - /* Gravity recursive down-pass */ - c->grav_down = scheduler_addtask(s, task_type_grav_down, - task_subtype_none, 0, 0, c, NULL); - - /* Implicit tasks for the up and down passes */ - c->init_grav_out = scheduler_addtask(s, task_type_init_grav_out, - task_subtype_none, 0, 1, c, NULL); - c->grav_down_in = scheduler_addtask(s, task_type_grav_down_in, - task_subtype_none, 0, 1, c, NULL); - - /* Gravity mesh force propagation */ - if (periodic) - c->grav_mesh = scheduler_addtask(s, task_type_grav_mesh, - task_subtype_none, 0, 0, c, NULL); - - if (periodic) scheduler_addunlock(s, c->drift_gpart, c->grav_mesh); - if (periodic) scheduler_addunlock(s, c->grav_mesh, c->grav_down); - scheduler_addunlock(s, c->init_grav, c->grav_long_range); - scheduler_addunlock(s, c->grav_long_range, c->grav_down); - scheduler_addunlock(s, c->grav_down, c->super->end_force); - - /* Link in the implicit tasks */ - scheduler_addunlock(s, c->init_grav, c->init_grav_out); - scheduler_addunlock(s, c->grav_down_in, c->grav_down); - } - } - } - - /* We are below the super-cell but not below the maximal splitting depth */ - else if (c->super_gravity != NULL && c->depth < space_subdepth_grav) { - - /* Local tasks only... */ - if (c->nodeID == e->nodeID) { - - if (is_self_gravity) { - - c->init_grav_out = scheduler_addtask(s, task_type_init_grav_out, - task_subtype_none, 0, 1, c, NULL); - - c->grav_down_in = scheduler_addtask(s, task_type_grav_down_in, - task_subtype_none, 0, 1, c, NULL); - - scheduler_addunlock(s, c->parent->init_grav_out, c->init_grav_out); - scheduler_addunlock(s, c->grav_down_in, c->parent->grav_down_in); - } - } - } - - /* Recurse but not below the maximal splitting depth */ - if (c->split && c->depth <= space_subdepth_grav) - for (int k = 0; k < 8; k++) - if (c->progeny[k] != NULL) - engine_make_hierarchical_tasks_gravity(e, c->progeny[k]); -} - -/** - * @brief Generate the stars hierarchical tasks for a hierarchy of cells - - * i.e. all the O(Npart) tasks -- star version - * - * Tasks are only created here. The dependencies will be added later on. - * - * Note that there is no need to recurse below the super-cell. Note also - * that we only add tasks if the relevant particles are present in the cell. - * - * @param e The #engine. - * @param c The #cell. - */ -void engine_make_hierarchical_tasks_stars(struct engine *e, struct cell *c) { - - struct scheduler *s = &e->sched; - - /* Are we in a super-cell ? */ - if (c->super == c) { - - /* Local tasks only... */ - if (c->nodeID == e->nodeID) { - - /* Generate the ghost tasks. */ - c->stars_ghost_in = - scheduler_addtask(s, task_type_stars_ghost_in, task_subtype_none, 0, - /* implicit = */ 1, c, NULL); - c->stars_ghost_out = - scheduler_addtask(s, task_type_stars_ghost_out, task_subtype_none, 0, - /* implicit = */ 1, c, NULL); - engine_add_stars_ghosts(e, c, c->stars_ghost_in, c->stars_ghost_out); - } - } else { /* We are above the super-cell so need to go deeper */ - - /* Recurse. */ - if (c->split) - for (int k = 0; k < 8; k++) - if (c->progeny[k] != NULL) - engine_make_hierarchical_tasks_stars(e, c->progeny[k]); - } -} - -void engine_make_hierarchical_tasks_mapper(void *map_data, int num_elements, - void *extra_data) { - struct engine *e = (struct engine *)extra_data; - const int is_with_hydro = (e->policy & engine_policy_hydro); - const int is_with_self_gravity = (e->policy & engine_policy_self_gravity); - const int is_with_external_gravity = - (e->policy & engine_policy_external_gravity); - const int is_with_feedback = (e->policy & engine_policy_feedback); - - for (int ind = 0; ind < num_elements; ind++) { - struct cell *c = &((struct cell *)map_data)[ind]; - /* Make the common tasks (time integration) */ - engine_make_hierarchical_tasks_common(e, c); - /* Add the hydro stuff */ - if (is_with_hydro) engine_make_hierarchical_tasks_hydro(e, c); - /* And the gravity stuff */ - if (is_with_self_gravity || is_with_external_gravity) - engine_make_hierarchical_tasks_gravity(e, c); - if (is_with_feedback) engine_make_hierarchical_tasks_stars(e, c); - } -} - #ifdef WITH_MPI /** * Do the exchange of one type of particles with all the other nodes. @@ -722,7 +397,7 @@ struct savelink_mapper_data { for (int k = 0; k < counts[nodeID * nr_nodes + node]; k++) { \ if (parts[k + offset].gpart != NULL) { \ if (CHECKS) \ - if (parts[k].gpart->id_or_neg_offset > 0) \ + if (parts[k + offset].gpart->id_or_neg_offset > 0) \ error("Trying to link a partnerless " #TYPE "!"); \ parts[k + offset].gpart->id_or_neg_offset = -count; \ count++; \ @@ -860,11 +535,87 @@ void engine_redistribute(struct engine *e) { struct space *s = e->s; struct cell *cells = s->cells_top; const int nr_cells = s->nr_cells; + struct xpart *xparts = s->xparts; struct part *parts = s->parts; struct gpart *gparts = s->gparts; struct spart *sparts = s->sparts; ticks tic = getticks(); + size_t nr_parts = s->nr_parts; + size_t nr_gparts = s->nr_gparts; + size_t nr_sparts = s->nr_sparts; + + /* Start by moving inhibited particles to the end of the arrays */ + for (size_t k = 0; k < nr_parts; /* void */) { + if (parts[k].time_bin == time_bin_inhibited) { + nr_parts -= 1; + + /* Swap the particle */ + memswap(&parts[k], &parts[nr_parts], sizeof(struct part)); + + /* Swap the xpart */ + memswap(&xparts[k], &xparts[nr_parts], sizeof(struct xpart)); + + /* Swap the link with the gpart */ + if (parts[k].gpart != NULL) { + parts[k].gpart->id_or_neg_offset = -k; + } + if (parts[nr_parts].gpart != NULL) { + parts[nr_parts].gpart->id_or_neg_offset = -nr_parts; + } + } else { + k++; + } + } + + /* Now move inhibited star particles to the end of the arrays */ + for (size_t k = 0; k < nr_sparts; /* void */) { + if (sparts[k].time_bin == time_bin_inhibited) { + nr_sparts -= 1; + + /* Swap the particle */ + memswap(&s->sparts[k], &s->sparts[nr_sparts], sizeof(struct spart)); + + /* Swap the link with the gpart */ + if (s->sparts[k].gpart != NULL) { + s->sparts[k].gpart->id_or_neg_offset = -k; + } + if (s->sparts[nr_sparts].gpart != NULL) { + s->sparts[nr_sparts].gpart->id_or_neg_offset = -nr_sparts; + } + } else { + k++; + } + } + + /* Finally do the same with the gravity particles */ + for (size_t k = 0; k < nr_gparts; /* void */) { + if (gparts[k].time_bin == time_bin_inhibited) { + nr_gparts -= 1; + + /* Swap the particle */ + memswap(&s->gparts[k], &s->gparts[nr_gparts], sizeof(struct gpart)); + + /* Swap the link with part/spart */ + if (s->gparts[k].type == swift_type_gas) { + s->parts[-s->gparts[k].id_or_neg_offset].gpart = &s->gparts[k]; + } else if (s->gparts[k].type == swift_type_stars) { + s->sparts[-s->gparts[k].id_or_neg_offset].gpart = &s->gparts[k]; + } + if (s->gparts[nr_gparts].type == swift_type_gas) { + s->parts[-s->gparts[nr_gparts].id_or_neg_offset].gpart = + &s->gparts[nr_gparts]; + } else if (s->gparts[nr_gparts].type == swift_type_stars) { + s->sparts[-s->gparts[nr_gparts].id_or_neg_offset].gpart = + &s->gparts[nr_gparts]; + } + } else { + k++; + } + } + + /* Now we are ready to deal with real particles and can start the exchange. */ + /* Allocate temporary arrays to store the counts of particles to be sent * and the destination of each particle */ int *counts; @@ -872,7 +623,7 @@ void engine_redistribute(struct engine *e) { error("Failed to allocate counts temporary buffer."); int *dest; - if ((dest = (int *)malloc(sizeof(int) * s->nr_parts)) == NULL) + if ((dest = (int *)malloc(sizeof(int) * nr_parts)) == NULL) error("Failed to allocate dest temporary buffer."); /* Simple index of node IDs, used for mappers over nodes. */ @@ -892,16 +643,16 @@ void engine_redistribute(struct engine *e) { redist_data.base = (void *)parts; threadpool_map(&e->threadpool, engine_redistribute_dest_mapper_part, parts, - s->nr_parts, sizeof(struct part), 0, &redist_data); + nr_parts, sizeof(struct part), 0, &redist_data); /* Sort the particles according to their cell index. */ - if (s->nr_parts > 0) + if (nr_parts > 0) space_parts_sort(s->parts, s->xparts, dest, &counts[nodeID * nr_nodes], nr_nodes, 0); #ifdef SWIFT_DEBUG_CHECKS /* Verify that the part have been sorted correctly. */ - for (size_t k = 0; k < s->nr_parts; k++) { + for (size_t k = 0; k < nr_parts; k++) { const struct part *p = &s->parts[k]; /* New cell index */ @@ -925,7 +676,7 @@ void engine_redistribute(struct engine *e) { /* We will need to re-link the gpart partners of parts, so save their * relative positions in the sent lists. */ - if (s->nr_parts > 0 && s->nr_gparts > 0) { + if (nr_parts > 0 && nr_gparts > 0) { struct savelink_mapper_data savelink_data; savelink_data.nr_nodes = nr_nodes; @@ -943,7 +694,7 @@ void engine_redistribute(struct engine *e) { error("Failed to allocate s_counts temporary buffer."); int *s_dest; - if ((s_dest = (int *)malloc(sizeof(int) * s->nr_sparts)) == NULL) + if ((s_dest = (int *)malloc(sizeof(int) * nr_sparts)) == NULL) error("Failed to allocate s_dest temporary buffer."); redist_data.counts = s_counts; @@ -951,16 +702,16 @@ void engine_redistribute(struct engine *e) { redist_data.base = (void *)sparts; threadpool_map(&e->threadpool, engine_redistribute_dest_mapper_spart, sparts, - s->nr_sparts, sizeof(struct spart), 0, &redist_data); + nr_sparts, sizeof(struct spart), 0, &redist_data); /* Sort the particles according to their cell index. */ - if (s->nr_sparts > 0) + if (nr_sparts > 0) space_sparts_sort(s->sparts, s_dest, &s_counts[nodeID * nr_nodes], nr_nodes, 0); #ifdef SWIFT_DEBUG_CHECKS /* Verify that the spart have been sorted correctly. */ - for (size_t k = 0; k < s->nr_sparts; k++) { + for (size_t k = 0; k < nr_sparts; k++) { const struct spart *sp = &s->sparts[k]; /* New cell index */ @@ -983,7 +734,7 @@ void engine_redistribute(struct engine *e) { #endif /* We need to re-link the gpart partners of sparts. */ - if (s->nr_sparts > 0) { + if (nr_sparts > 0) { struct savelink_mapper_data savelink_data; savelink_data.nr_nodes = nr_nodes; @@ -1001,7 +752,7 @@ void engine_redistribute(struct engine *e) { error("Failed to allocate g_gcount temporary buffer."); int *g_dest; - if ((g_dest = (int *)malloc(sizeof(int) * s->nr_gparts)) == NULL) + if ((g_dest = (int *)malloc(sizeof(int) * nr_gparts)) == NULL) error("Failed to allocate g_dest temporary buffer."); redist_data.counts = g_counts; @@ -1009,16 +760,16 @@ void engine_redistribute(struct engine *e) { redist_data.base = (void *)gparts; threadpool_map(&e->threadpool, engine_redistribute_dest_mapper_gpart, gparts, - s->nr_gparts, sizeof(struct gpart), 0, &redist_data); + nr_gparts, sizeof(struct gpart), 0, &redist_data); /* Sort the gparticles according to their cell index. */ - if (s->nr_gparts > 0) + if (nr_gparts > 0) space_gparts_sort(s->gparts, s->parts, s->sparts, g_dest, &g_counts[nodeID * nr_nodes], nr_nodes); #ifdef SWIFT_DEBUG_CHECKS /* Verify that the gpart have been sorted correctly. */ - for (size_t k = 0; k < s->nr_gparts; k++) { + for (size_t k = 0; k < nr_gparts; k++) { const struct gpart *gp = &s->gparts[k]; /* New cell index */ @@ -1093,49 +844,50 @@ void engine_redistribute(struct engine *e) { /* Now each node knows how many parts, sparts and gparts will be transferred * to every other node. * Get the new numbers of particles for this node. */ - size_t nr_parts = 0, nr_gparts = 0, nr_sparts = 0; - for (int k = 0; k < nr_nodes; k++) nr_parts += counts[k * nr_nodes + nodeID]; + size_t nr_parts_new = 0, nr_gparts_new = 0, nr_sparts_new = 0; for (int k = 0; k < nr_nodes; k++) - nr_gparts += g_counts[k * nr_nodes + nodeID]; + nr_parts_new += counts[k * nr_nodes + nodeID]; for (int k = 0; k < nr_nodes; k++) - nr_sparts += s_counts[k * nr_nodes + nodeID]; + nr_gparts_new += g_counts[k * nr_nodes + nodeID]; + for (int k = 0; k < nr_nodes; k++) + nr_sparts_new += s_counts[k * nr_nodes + nodeID]; /* Now exchange the particles, type by type to keep the memory required * under control. */ /* SPH particles. */ - void *new_parts = engine_do_redistribute(counts, (char *)s->parts, nr_parts, - sizeof(struct part), part_align, - part_mpi_type, nr_nodes, nodeID); + void *new_parts = engine_do_redistribute( + counts, (char *)s->parts, nr_parts_new, sizeof(struct part), part_align, + part_mpi_type, nr_nodes, nodeID); free(s->parts); s->parts = (struct part *)new_parts; - s->nr_parts = nr_parts; - s->size_parts = engine_redistribute_alloc_margin * nr_parts; + s->nr_parts = nr_parts_new; + s->size_parts = engine_redistribute_alloc_margin * nr_parts_new; /* Extra SPH particle properties. */ - new_parts = engine_do_redistribute(counts, (char *)s->xparts, nr_parts, + new_parts = engine_do_redistribute(counts, (char *)s->xparts, nr_parts_new, sizeof(struct xpart), xpart_align, xpart_mpi_type, nr_nodes, nodeID); free(s->xparts); s->xparts = (struct xpart *)new_parts; /* Gravity particles. */ - new_parts = engine_do_redistribute(g_counts, (char *)s->gparts, nr_gparts, + new_parts = engine_do_redistribute(g_counts, (char *)s->gparts, nr_gparts_new, sizeof(struct gpart), gpart_align, gpart_mpi_type, nr_nodes, nodeID); free(s->gparts); s->gparts = (struct gpart *)new_parts; - s->nr_gparts = nr_gparts; - s->size_gparts = engine_redistribute_alloc_margin * nr_gparts; + s->nr_gparts = nr_gparts_new; + s->size_gparts = engine_redistribute_alloc_margin * nr_gparts_new; /* Star particles. */ - new_parts = engine_do_redistribute(s_counts, (char *)s->sparts, nr_sparts, + new_parts = engine_do_redistribute(s_counts, (char *)s->sparts, nr_sparts_new, sizeof(struct spart), spart_align, spart_mpi_type, nr_nodes, nodeID); free(s->sparts); s->sparts = (struct spart *)new_parts; - s->nr_sparts = nr_sparts; - s->size_sparts = engine_redistribute_alloc_margin * nr_sparts; + s->nr_sparts = nr_sparts_new; + s->size_sparts = engine_redistribute_alloc_margin * nr_sparts_new; /* All particles have now arrived. Time for some final operations on the stuff we just received */ @@ -1162,7 +914,7 @@ void engine_redistribute(struct engine *e) { #ifdef SWIFT_DEBUG_CHECKS /* Verify that all parts are in the right place. */ - for (size_t k = 0; k < nr_parts; k++) { + for (size_t k = 0; k < nr_parts_new; k++) { const int cid = cell_getid(s->cdim, s->parts[k].x[0] * s->iwidth[0], s->parts[k].x[1] * s->iwidth[1], s->parts[k].x[2] * s->iwidth[2]); @@ -1170,7 +922,7 @@ void engine_redistribute(struct engine *e) { error("Received particle (%zu) that does not belong here (nodeID=%i).", k, cells[cid].nodeID); } - for (size_t k = 0; k < nr_gparts; k++) { + for (size_t k = 0; k < nr_gparts_new; k++) { const int cid = cell_getid(s->cdim, s->gparts[k].x[0] * s->iwidth[0], s->gparts[k].x[1] * s->iwidth[1], s->gparts[k].x[2] * s->iwidth[2]); @@ -1178,7 +930,7 @@ void engine_redistribute(struct engine *e) { error("Received g-particle (%zu) that does not belong here (nodeID=%i).", k, cells[cid].nodeID); } - for (size_t k = 0; k < nr_sparts; k++) { + for (size_t k = 0; k < nr_sparts_new; k++) { const int cid = cell_getid(s->cdim, s->sparts[k].x[0] * s->iwidth[0], s->sparts[k].x[1] * s->iwidth[1], s->sparts[k].x[2] * s->iwidth[2]); @@ -1188,8 +940,8 @@ void engine_redistribute(struct engine *e) { } /* Verify that the links are correct */ - part_verify_links(s->parts, s->gparts, s->sparts, nr_parts, nr_gparts, - nr_sparts, e->verbose); + part_verify_links(s->parts, s->gparts, s->sparts, nr_parts_new, nr_gparts_new, + nr_sparts_new, e->verbose); #endif /* Be verbose about what just happened. */ @@ -1198,7 +950,7 @@ void engine_redistribute(struct engine *e) { for (int k = 0; k < nr_cells; k++) if (cells[k].nodeID == nodeID) my_cells += 1; message("node %i now has %zu parts, %zu sparts and %zu gparts in %i cells.", - nodeID, nr_parts, nr_sparts, nr_gparts, my_cells); + nodeID, nr_parts_new, nr_sparts_new, nr_gparts_new, my_cells); } /* Flag that a redistribute has taken place */ @@ -1365,94 +1117,95 @@ void engine_repartition_trigger(struct engine *e) { } /** - * @brief Add send tasks for the hydro pairs to a hierarchy of cells. + * @brief Exchange cell structures with other nodes. * * @param e The #engine. - * @param ci The sending #cell. - * @param cj Dummy cell containing the nodeID of the receiving node. - * @param t_xv The send_xv #task, if it has already been created. - * @param t_rho The send_rho #task, if it has already been created. - * @param t_gradient The send_gradient #task, if already created. */ -void engine_addtasks_send_hydro(struct engine *e, struct cell *ci, - struct cell *cj, struct task *t_xv, - struct task *t_rho, struct task *t_gradient) { +void engine_exchange_cells(struct engine *e) { #ifdef WITH_MPI - struct link *l = NULL; - struct scheduler *s = &e->sched; - const int nodeID = cj->nodeID; - - /* Check if any of the density tasks are for the target node. */ - for (l = ci->density; l != NULL; l = l->next) - if (l->t->ci->nodeID == nodeID || - (l->t->cj != NULL && l->t->cj->nodeID == nodeID)) - break; - - /* If so, attach send tasks. */ - if (l != NULL) { - - /* Create the tasks and their dependencies? */ - if (t_xv == NULL) { - - /* Create a tag for this cell. */ - if (ci->tag < 0) cell_tag(ci); - t_xv = scheduler_addtask(s, task_type_send, task_subtype_xv, ci->tag, 0, - ci, cj); - t_rho = scheduler_addtask(s, task_type_send, task_subtype_rho, ci->tag, 0, - ci, cj); -#ifdef EXTRA_HYDRO_LOOP - t_gradient = scheduler_addtask(s, task_type_send, task_subtype_gradient, - ci->tag, 0, ci, cj); -#endif - -#ifdef EXTRA_HYDRO_LOOP - - scheduler_addunlock(s, t_gradient, ci->super->kick2); + struct space *s = e->s; + const int nr_proxies = e->nr_proxies; + const int with_gravity = e->policy & engine_policy_self_gravity; + const ticks tic = getticks(); - scheduler_addunlock(s, ci->super_hydro->extra_ghost, t_gradient); + /* Exchange the cell structure with neighbouring ranks. */ + proxy_cells_exchange(e->proxies, e->nr_proxies, e->s, with_gravity); - /* The send_rho task should unlock the super_hydro-cell's extra_ghost - * task. */ - scheduler_addunlock(s, t_rho, ci->super_hydro->extra_ghost); + ticks tic2 = getticks(); - /* The send_rho task depends on the cell's ghost task. */ - scheduler_addunlock(s, ci->super_hydro->ghost_out, t_rho); + /* Count the number of particles we need to import and re-allocate + the buffer if needed. */ + size_t count_parts_in = 0, count_gparts_in = 0, count_sparts_in = 0; + for (int k = 0; k < nr_proxies; k++) + for (int j = 0; j < e->proxies[k].nr_cells_in; j++) { + if (e->proxies[k].cells_in_type[j] & proxy_cell_type_hydro) + count_parts_in += e->proxies[k].cells_in[j]->hydro.count; + if (e->proxies[k].cells_in_type[j] & proxy_cell_type_gravity) + count_gparts_in += e->proxies[k].cells_in[j]->grav.count; + count_sparts_in += e->proxies[k].cells_in[j]->stars.count; + } + if (count_parts_in > s->size_parts_foreign) { + if (s->parts_foreign != NULL) free(s->parts_foreign); + s->size_parts_foreign = 1.1 * count_parts_in; + if (posix_memalign((void **)&s->parts_foreign, part_align, + sizeof(struct part) * s->size_parts_foreign) != 0) + error("Failed to allocate foreign part data."); + } + if (count_gparts_in > s->size_gparts_foreign) { + if (s->gparts_foreign != NULL) free(s->gparts_foreign); + s->size_gparts_foreign = 1.1 * count_gparts_in; + if (posix_memalign((void **)&s->gparts_foreign, gpart_align, + sizeof(struct gpart) * s->size_gparts_foreign) != 0) + error("Failed to allocate foreign gpart data."); + } + if (count_sparts_in > s->size_sparts_foreign) { + if (s->sparts_foreign != NULL) free(s->sparts_foreign); + s->size_sparts_foreign = 1.1 * count_sparts_in; + if (posix_memalign((void **)&s->sparts_foreign, spart_align, + sizeof(struct spart) * s->size_sparts_foreign) != 0) + error("Failed to allocate foreign spart data."); + } - /* The send_xv task should unlock the super_hydro-cell's ghost task. */ - scheduler_addunlock(s, t_xv, ci->super_hydro->ghost_in); + if (e->verbose) + message("Counting and allocating arrays took %.3f %s.", + clocks_from_ticks(getticks() - tic2), clocks_getunit()); -#else - /* The send_rho task should unlock the super_hydro-cell's kick task. */ - scheduler_addunlock(s, t_rho, ci->super->end_force); + tic2 = getticks(); - /* The send_rho task depends on the cell's ghost task. */ - scheduler_addunlock(s, ci->super_hydro->ghost_out, t_rho); + /* Unpack the cells and link to the particle data. */ + struct part *parts = s->parts_foreign; + struct gpart *gparts = s->gparts_foreign; + struct spart *sparts = s->sparts_foreign; + for (int k = 0; k < nr_proxies; k++) { + for (int j = 0; j < e->proxies[k].nr_cells_in; j++) { - /* The send_xv task should unlock the super_hydro-cell's ghost task. */ - scheduler_addunlock(s, t_xv, ci->super_hydro->ghost_in); + if (e->proxies[k].cells_in_type[j] & proxy_cell_type_hydro) { + cell_link_parts(e->proxies[k].cells_in[j], parts); + parts = &parts[e->proxies[k].cells_in[j]->hydro.count]; + } -#endif + if (e->proxies[k].cells_in_type[j] & proxy_cell_type_gravity) { + cell_link_gparts(e->proxies[k].cells_in[j], gparts); + gparts = &gparts[e->proxies[k].cells_in[j]->grav.count]; + } - /* Drift before you send */ - scheduler_addunlock(s, ci->super_hydro->drift_part, t_xv); + cell_link_sparts(e->proxies[k].cells_in[j], sparts); + sparts = &sparts[e->proxies[k].cells_in[j]->stars.count]; } - - /* Add them to the local cell. */ - engine_addlink(e, &ci->send_xv, t_xv); - engine_addlink(e, &ci->send_rho, t_rho); -#ifdef EXTRA_HYDRO_LOOP - engine_addlink(e, &ci->send_gradient, t_gradient); -#endif } + s->nr_parts_foreign = parts - s->parts_foreign; + s->nr_gparts_foreign = gparts - s->gparts_foreign; + s->nr_sparts_foreign = sparts - s->sparts_foreign; + + if (e->verbose) + message("Recursively linking arrays took %.3f %s.", + clocks_from_ticks(getticks() - tic2), clocks_getunit()); - /* Recurse? */ - if (ci->split) - for (int k = 0; k < 8; k++) - if (ci->progeny[k] != NULL) - engine_addtasks_send_hydro(e, ci->progeny[k], cj, t_xv, t_rho, - t_gradient); + if (e->verbose) + message("took %.3f %s.", clocks_from_ticks(getticks() - tic), + clocks_getunit()); #else error("SWIFT was not compiled with MPI support."); @@ -1460,388 +1213,21 @@ void engine_addtasks_send_hydro(struct engine *e, struct cell *ci, } /** - * @brief Add send tasks for the gravity pairs to a hierarchy of cells. - * - * @param e The #engine. - * @param ci The sending #cell. - * @param cj Dummy cell containing the nodeID of the receiving node. - * @param t_grav The send_grav #task, if it has already been created. - */ -void engine_addtasks_send_gravity(struct engine *e, struct cell *ci, - struct cell *cj, struct task *t_grav) { - -#ifdef WITH_MPI - struct link *l = NULL; - struct scheduler *s = &e->sched; - const int nodeID = cj->nodeID; - - /* Check if any of the gravity tasks are for the target node. */ - for (l = ci->grav; l != NULL; l = l->next) - if (l->t->ci->nodeID == nodeID || - (l->t->cj != NULL && l->t->cj->nodeID == nodeID)) - break; - - /* If so, attach send tasks. */ - if (l != NULL) { - - /* Create the tasks and their dependencies? */ - if (t_grav == NULL) { - - /* Create a tag for this cell. */ - if (ci->tag < 0) cell_tag(ci); - - t_grav = scheduler_addtask(s, task_type_send, task_subtype_gpart, ci->tag, - 0, ci, cj); - - /* The sends should unlock the down pass. */ - scheduler_addunlock(s, t_grav, ci->super_gravity->grav_down); - - /* Drift before you send */ - scheduler_addunlock(s, ci->super_gravity->drift_gpart, t_grav); - } - - /* Add them to the local cell. */ - engine_addlink(e, &ci->send_grav, t_grav); - } - - /* Recurse? */ - if (ci->split) - for (int k = 0; k < 8; k++) - if (ci->progeny[k] != NULL) - engine_addtasks_send_gravity(e, ci->progeny[k], cj, t_grav); - -#else - error("SWIFT was not compiled with MPI support."); -#endif -} - -/** - * @brief Add send tasks for the time-step to a hierarchy of cells. - * - * @param e The #engine. - * @param ci The sending #cell. - * @param cj Dummy cell containing the nodeID of the receiving node. - * @param t_ti The send_ti #task, if it has already been created. - */ -void engine_addtasks_send_timestep(struct engine *e, struct cell *ci, - struct cell *cj, struct task *t_ti) { - -#ifdef WITH_MPI - struct link *l = NULL; - struct scheduler *s = &e->sched; - const int nodeID = cj->nodeID; - - /* Check if any of the gravity tasks are for the target node. */ - for (l = ci->grav; l != NULL; l = l->next) - if (l->t->ci->nodeID == nodeID || - (l->t->cj != NULL && l->t->cj->nodeID == nodeID)) - break; - - /* Check whether instead any of the hydro tasks are for the target node. */ - if (l == NULL) - for (l = ci->density; l != NULL; l = l->next) - if (l->t->ci->nodeID == nodeID || - (l->t->cj != NULL && l->t->cj->nodeID == nodeID)) - break; - - /* If found anything, attach send tasks. */ - if (l != NULL) { - - /* Create the tasks and their dependencies? */ - if (t_ti == NULL) { - - /* Create a tag for this cell. */ - if (ci->tag < 0) cell_tag(ci); - - t_ti = scheduler_addtask(s, task_type_send, task_subtype_tend, ci->tag, 0, - ci, cj); - - /* The super-cell's timestep task should unlock the send_ti task. */ - scheduler_addunlock(s, ci->super->timestep, t_ti); - } - - /* Add them to the local cell. */ - engine_addlink(e, &ci->send_ti, t_ti); - } - - /* Recurse? */ - if (ci->split) - for (int k = 0; k < 8; k++) - if (ci->progeny[k] != NULL) - engine_addtasks_send_timestep(e, ci->progeny[k], cj, t_ti); - -#else - error("SWIFT was not compiled with MPI support."); -#endif -} - -/** - * @brief Add recv tasks for hydro pairs to a hierarchy of cells. - * - * @param e The #engine. - * @param c The foreign #cell. - * @param t_xv The recv_xv #task, if it has already been created. - * @param t_rho The recv_rho #task, if it has already been created. - * @param t_gradient The recv_gradient #task, if it has already been created. - */ -void engine_addtasks_recv_hydro(struct engine *e, struct cell *c, - struct task *t_xv, struct task *t_rho, - struct task *t_gradient) { - -#ifdef WITH_MPI - struct scheduler *s = &e->sched; - - /* Have we reached a level where there are any hydro tasks ? */ - if (t_xv == NULL && c->density != NULL) { - -#ifdef SWIFT_DEBUG_CHECKS - /* Make sure this cell has a valid tag. */ - if (c->tag < 0) error("Trying to receive from untagged cell."); -#endif // SWIFT_DEBUG_CHECKS - - /* Create the tasks. */ - t_xv = scheduler_addtask(s, task_type_recv, task_subtype_xv, c->tag, 0, c, - NULL); - t_rho = scheduler_addtask(s, task_type_recv, task_subtype_rho, c->tag, 0, c, - NULL); -#ifdef EXTRA_HYDRO_LOOP - t_gradient = scheduler_addtask(s, task_type_recv, task_subtype_gradient, - c->tag, 0, c, NULL); -#endif - } - - c->recv_xv = t_xv; - c->recv_rho = t_rho; - c->recv_gradient = t_gradient; - - /* Add dependencies. */ - if (c->sorts != NULL) scheduler_addunlock(s, t_xv, c->sorts); - - for (struct link *l = c->density; l != NULL; l = l->next) { - scheduler_addunlock(s, t_xv, l->t); - scheduler_addunlock(s, l->t, t_rho); - } -#ifdef EXTRA_HYDRO_LOOP - for (struct link *l = c->gradient; l != NULL; l = l->next) { - scheduler_addunlock(s, t_rho, l->t); - scheduler_addunlock(s, l->t, t_gradient); - } - for (struct link *l = c->force; l != NULL; l = l->next) - scheduler_addunlock(s, t_gradient, l->t); -#else - for (struct link *l = c->force; l != NULL; l = l->next) - scheduler_addunlock(s, t_rho, l->t); -#endif - - /* Recurse? */ - if (c->split) - for (int k = 0; k < 8; k++) - if (c->progeny[k] != NULL) - engine_addtasks_recv_hydro(e, c->progeny[k], t_xv, t_rho, t_gradient); - -#else - error("SWIFT was not compiled with MPI support."); -#endif -} - -/** - * @brief Add recv tasks for gravity pairs to a hierarchy of cells. - * - * @param e The #engine. - * @param c The foreign #cell. - * @param t_grav The recv_gpart #task, if it has already been created. - */ -void engine_addtasks_recv_gravity(struct engine *e, struct cell *c, - struct task *t_grav) { - -#ifdef WITH_MPI - struct scheduler *s = &e->sched; - - /* Have we reached a level where there are any gravity tasks ? */ - if (t_grav == NULL && c->grav != NULL) { - -#ifdef SWIFT_DEBUG_CHECKS - /* Make sure this cell has a valid tag. */ - if (c->tag < 0) error("Trying to receive from untagged cell."); -#endif // SWIFT_DEBUG_CHECKS - - /* Create the tasks. */ - t_grav = scheduler_addtask(s, task_type_recv, task_subtype_gpart, c->tag, 0, - c, NULL); - } - - c->recv_grav = t_grav; - - for (struct link *l = c->grav; l != NULL; l = l->next) - scheduler_addunlock(s, t_grav, l->t); - - /* Recurse? */ - if (c->split) - for (int k = 0; k < 8; k++) - if (c->progeny[k] != NULL) - engine_addtasks_recv_gravity(e, c->progeny[k], t_grav); - -#else - error("SWIFT was not compiled with MPI support."); -#endif -} - -/** - * @brief Add recv tasks for gravity pairs to a hierarchy of cells. - * - * @param e The #engine. - * @param c The foreign #cell. - * @param t_ti The recv_ti #task, if already been created. - */ -void engine_addtasks_recv_timestep(struct engine *e, struct cell *c, - struct task *t_ti) { - -#ifdef WITH_MPI - struct scheduler *s = &e->sched; - - /* Have we reached a level where there are any self/pair tasks ? */ - if (t_ti == NULL && (c->grav != NULL || c->density != NULL)) { - -#ifdef SWIFT_DEBUG_CHECKS - /* Make sure this cell has a valid tag. */ - if (c->tag < 0) error("Trying to receive from untagged cell."); -#endif // SWIFT_DEBUG_CHECKS - - t_ti = scheduler_addtask(s, task_type_recv, task_subtype_tend, c->tag, 0, c, - NULL); - } - - c->recv_ti = t_ti; - - for (struct link *l = c->grav; l != NULL; l = l->next) - scheduler_addunlock(s, l->t, t_ti); - - for (struct link *l = c->force; l != NULL; l = l->next) - scheduler_addunlock(s, l->t, t_ti); - - /* Recurse? */ - if (c->split) - for (int k = 0; k < 8; k++) - if (c->progeny[k] != NULL) - engine_addtasks_recv_timestep(e, c->progeny[k], t_ti); - -#else - error("SWIFT was not compiled with MPI support."); -#endif -} - -/** - * @brief Exchange cell structures with other nodes. - * - * @param e The #engine. - */ -void engine_exchange_cells(struct engine *e) { - -#ifdef WITH_MPI - - struct space *s = e->s; - const int nr_proxies = e->nr_proxies; - const int with_gravity = e->policy & engine_policy_self_gravity; - const ticks tic = getticks(); - - /* Exchange the cell structure with neighbouring ranks. */ - proxy_cells_exchange(e->proxies, e->nr_proxies, e->s, with_gravity); - - ticks tic2 = getticks(); - - /* Count the number of particles we need to import and re-allocate - the buffer if needed. */ - size_t count_parts_in = 0, count_gparts_in = 0, count_sparts_in = 0; - for (int k = 0; k < nr_proxies; k++) - for (int j = 0; j < e->proxies[k].nr_cells_in; j++) { - if (e->proxies[k].cells_in_type[j] & proxy_cell_type_hydro) - count_parts_in += e->proxies[k].cells_in[j]->count; - if (e->proxies[k].cells_in_type[j] & proxy_cell_type_gravity) - count_gparts_in += e->proxies[k].cells_in[j]->gcount; - count_sparts_in += e->proxies[k].cells_in[j]->scount; - } - if (count_parts_in > s->size_parts_foreign) { - if (s->parts_foreign != NULL) free(s->parts_foreign); - s->size_parts_foreign = 1.1 * count_parts_in; - if (posix_memalign((void **)&s->parts_foreign, part_align, - sizeof(struct part) * s->size_parts_foreign) != 0) - error("Failed to allocate foreign part data."); - } - if (count_gparts_in > s->size_gparts_foreign) { - if (s->gparts_foreign != NULL) free(s->gparts_foreign); - s->size_gparts_foreign = 1.1 * count_gparts_in; - if (posix_memalign((void **)&s->gparts_foreign, gpart_align, - sizeof(struct gpart) * s->size_gparts_foreign) != 0) - error("Failed to allocate foreign gpart data."); - } - if (count_sparts_in > s->size_sparts_foreign) { - if (s->sparts_foreign != NULL) free(s->sparts_foreign); - s->size_sparts_foreign = 1.1 * count_sparts_in; - if (posix_memalign((void **)&s->sparts_foreign, spart_align, - sizeof(struct spart) * s->size_sparts_foreign) != 0) - error("Failed to allocate foreign spart data."); - } - - if (e->verbose) - message("Counting and allocating arrays took %.3f %s.", - clocks_from_ticks(getticks() - tic2), clocks_getunit()); - - tic2 = getticks(); - - /* Unpack the cells and link to the particle data. */ - struct part *parts = s->parts_foreign; - struct gpart *gparts = s->gparts_foreign; - struct spart *sparts = s->sparts_foreign; - for (int k = 0; k < nr_proxies; k++) { - for (int j = 0; j < e->proxies[k].nr_cells_in; j++) { - - if (e->proxies[k].cells_in_type[j] & proxy_cell_type_hydro) { - cell_link_parts(e->proxies[k].cells_in[j], parts); - parts = &parts[e->proxies[k].cells_in[j]->count]; - } - - if (e->proxies[k].cells_in_type[j] & proxy_cell_type_gravity) { - cell_link_gparts(e->proxies[k].cells_in[j], gparts); - gparts = &gparts[e->proxies[k].cells_in[j]->gcount]; - } - - cell_link_sparts(e->proxies[k].cells_in[j], sparts); - sparts = &sparts[e->proxies[k].cells_in[j]->scount]; - } - } - s->nr_parts_foreign = parts - s->parts_foreign; - s->nr_gparts_foreign = gparts - s->gparts_foreign; - s->nr_sparts_foreign = sparts - s->sparts_foreign; - - if (e->verbose) - message("Recursively linking arrays took %.3f %s.", - clocks_from_ticks(getticks() - tic2), clocks_getunit()); - - if (e->verbose) - message("took %.3f %s.", clocks_from_ticks(getticks() - tic), - clocks_getunit()); - -#else - error("SWIFT was not compiled with MPI support."); -#endif -} - -/** - * @brief Exchange straying particles with other nodes. + * @brief Exchange straying particles with other nodes. * * @param e The #engine. * @param offset_parts The index in the parts array as of which the foreign - * parts reside. + * parts reside (i.e. the current number of local #part). * @param ind_part The foreign #cell ID of each part. * @param Npart The number of stray parts, contains the number of parts received * on return. * @param offset_gparts The index in the gparts array as of which the foreign - * parts reside. + * parts reside (i.e. the current number of local #gpart). * @param ind_gpart The foreign #cell ID of each gpart. * @param Ngpart The number of stray gparts, contains the number of gparts * received on return. * @param offset_sparts The index in the sparts array as of which the foreign - * parts reside. + * parts reside (i.e. the current number of local #spart). * @param ind_spart The foreign #cell ID of each spart. * @param Nspart The number of stray sparts, contains the number of sparts * received on return. @@ -1849,11 +1235,11 @@ void engine_exchange_cells(struct engine *e) { * Note that this function does not mess-up the linkage between parts and * gparts, i.e. the received particles have correct linkeage. */ -void engine_exchange_strays(struct engine *e, size_t offset_parts, - int *ind_part, size_t *Npart, size_t offset_gparts, - int *ind_gpart, size_t *Ngpart, - size_t offset_sparts, int *ind_spart, - size_t *Nspart) { +void engine_exchange_strays(struct engine *e, const size_t offset_parts, + const int *ind_part, size_t *Npart, + const size_t offset_gparts, const int *ind_gpart, + size_t *Ngpart, const size_t offset_sparts, + const int *ind_spart, size_t *Nspart) { #ifdef WITH_MPI @@ -1869,6 +1255,10 @@ void engine_exchange_strays(struct engine *e, size_t offset_parts, /* Put the parts into the corresponding proxies. */ for (size_t k = 0; k < *Npart; k++) { + + /* Ignore the particles we want to get rid of (inhibited, ...). */ + if (ind_part[k] == -1) continue; + /* Get the target node and proxy ID. */ const int node_id = e->s->cells_top[ind_part[k]].nodeID; if (node_id < 0 || node_id >= e->nr_nodes) @@ -1889,6 +1279,11 @@ void engine_exchange_strays(struct engine *e, size_t offset_parts, -e->proxies[pid].nr_parts_out; } +#ifdef SWIFT_DEBUG_CHECKS + if (s->parts[offset_parts + k].time_bin == time_bin_inhibited) + error("Attempting to exchange an inhibited particle"); +#endif + /* Load the part and xpart into the proxy. */ proxy_parts_load(&e->proxies[pid], &s->parts[offset_parts + k], &s->xparts[offset_parts + k], 1); @@ -1896,17 +1291,23 @@ void engine_exchange_strays(struct engine *e, size_t offset_parts, /* Put the sparts into the corresponding proxies. */ for (size_t k = 0; k < *Nspart; k++) { + + /* Ignore the particles we want to get rid of (inhibited, ...). */ + if (ind_spart[k] == -1) continue; + + /* Get the target node and proxy ID. */ const int node_id = e->s->cells_top[ind_spart[k]].nodeID; if (node_id < 0 || node_id >= e->nr_nodes) error("Bad node ID %i.", node_id); const int pid = e->proxy_ind[node_id]; - if (pid < 0) + if (pid < 0) { error( "Do not have a proxy for the requested nodeID %i for part with " "id=%lld, x=[%e,%e,%e].", node_id, s->sparts[offset_sparts + k].id, s->sparts[offset_sparts + k].x[0], s->sparts[offset_sparts + k].x[1], s->sparts[offset_sparts + k].x[2]); + } /* Re-link the associated gpart with the buffer offset of the spart. */ if (s->sparts[offset_sparts + k].gpart != NULL) { @@ -1914,23 +1315,39 @@ void engine_exchange_strays(struct engine *e, size_t offset_parts, -e->proxies[pid].nr_sparts_out; } +#ifdef SWIFT_DEBUG_CHECKS + if (s->sparts[offset_sparts + k].time_bin == time_bin_inhibited) + error("Attempting to exchange an inhibited particle"); +#endif + /* Load the spart into the proxy */ proxy_sparts_load(&e->proxies[pid], &s->sparts[offset_sparts + k], 1); } /* Put the gparts into the corresponding proxies. */ for (size_t k = 0; k < *Ngpart; k++) { + + /* Ignore the particles we want to get rid of (inhibited, ...). */ + if (ind_gpart[k] == -1) continue; + + /* Get the target node and proxy ID. */ const int node_id = e->s->cells_top[ind_gpart[k]].nodeID; if (node_id < 0 || node_id >= e->nr_nodes) error("Bad node ID %i.", node_id); const int pid = e->proxy_ind[node_id]; - if (pid < 0) + if (pid < 0) { error( "Do not have a proxy for the requested nodeID %i for part with " "id=%lli, x=[%e,%e,%e].", node_id, s->gparts[offset_gparts + k].id_or_neg_offset, s->gparts[offset_gparts + k].x[0], s->gparts[offset_gparts + k].x[1], s->gparts[offset_gparts + k].x[2]); + } + +#ifdef SWIFT_DEBUG_CHECKS + if (s->gparts[offset_gparts + k].time_bin == time_bin_inhibited) + error("Attempting to exchange an inhibited particle"); +#endif /* Load the gpart into the proxy */ proxy_gparts_load(&e->proxies[pid], &s->gparts[offset_gparts + k], 1); @@ -1993,6 +1410,8 @@ void engine_exchange_strays(struct engine *e, size_t offset_parts, free(s->xparts); s->parts = parts_new; s->xparts = xparts_new; + + /* Reset the links */ for (size_t k = 0; k < offset_parts; k++) { if (s->parts[k].gpart != NULL) { s->parts[k].gpart->id_or_neg_offset = -k; @@ -2009,6 +1428,8 @@ void engine_exchange_strays(struct engine *e, size_t offset_parts, memcpy(sparts_new, s->sparts, sizeof(struct spart) * offset_sparts); free(s->sparts); s->sparts = sparts_new; + + /* Reset the links */ for (size_t k = 0; k < offset_sparts; k++) { if (s->sparts[k].gpart != NULL) { s->sparts[k].gpart->id_or_neg_offset = -k; @@ -2026,6 +1447,7 @@ void engine_exchange_strays(struct engine *e, size_t offset_parts, free(s->gparts); s->gparts = gparts_new; + /* Reset the links */ for (size_t k = 0; k < offset_gparts; k++) { if (s->gparts[k].type == swift_type_gas) { s->parts[-s->gparts[k].id_or_neg_offset].gpart = &s->gparts[k]; @@ -2196,19 +1618,16 @@ void engine_exchange_top_multipoles(struct engine *e) { /* Each node (space) has constructed its own top-level multipoles. * We now need to make sure every other node has a copy of everything. * - * WARNING: Adult stuff ahead: don't do this at home! - * - * Since all nodes have their top-level multi-poles computed - * and all foreign ones set to 0 (all bytes), we can gather all the m-poles - * by doing a bit-wise OR reduction across all the nodes directly in - * place inside the multi-poles_top array. - * This only works if the foreign m-poles on every nodes are zeroed and no - * multi-pole is present on more than one node (two things guaranteed by the - * domain decomposition). + * We use our home-made reduction operation that simply performs a XOR + * operation on the multipoles. Since only local multipoles are non-zero and + * each multipole is only present once, the bit-by-bit XOR will + * create the desired result. */ - MPI_Allreduce(MPI_IN_PLACE, e->s->multipoles_top, - e->s->nr_cells * sizeof(struct gravity_tensors), MPI_BYTE, - MPI_BOR, MPI_COMM_WORLD); + int err = MPI_Allreduce(MPI_IN_PLACE, e->s->multipoles_top, e->s->nr_cells, + multipole_mpi_type, multipole_mpi_reduce_op, + MPI_COMM_WORLD); + if (err != MPI_SUCCESS) + mpi_error(err, "Failed to all-reduce the top-level multipoles."); #ifdef SWIFT_DEBUG_CHECKS long long counter = 0; @@ -2217,6 +1636,9 @@ void engine_exchange_top_multipoles(struct engine *e) { for (int i = 0; i < e->s->nr_cells; ++i) { const struct gravity_tensors *m = &e->s->multipoles_top[i]; counter += m->m_pole.num_gpart; + if (m->m_pole.num_gpart < 0) { + error("m->m_pole.num_gpart is negative: %lld", m->m_pole.num_gpart); + } if (m->m_pole.M_000 > 0.) { if (m->CoM[0] < 0. || m->CoM[0] > e->s->dim[0]) error("Invalid multipole position in X"); @@ -2227,7 +1649,10 @@ void engine_exchange_top_multipoles(struct engine *e) { } } if (counter != e->total_nr_gparts) - error("Total particles in multipoles inconsistent with engine"); + error( + "Total particles in multipoles inconsistent with engine.\n " + " counter = %lld, nr_gparts = %lld", + counter, e->total_nr_gparts); #endif #else @@ -2243,1954 +1668,148 @@ void engine_exchange_proxy_multipoles(struct engine *e) { /* Start by counting the number of cells to send and receive */ int count_send_cells = 0; - int count_recv_cells = 0; - int count_send_requests = 0; - int count_recv_requests = 0; - - /* Loop over the proxies. */ - for (int pid = 0; pid < e->nr_proxies; pid++) { - - /* Get a handle on the proxy. */ - const struct proxy *p = &e->proxies[pid]; - - /* Now collect the number of requests associated */ - count_recv_requests += p->nr_cells_in; - count_send_requests += p->nr_cells_out; - - /* And the actual number of things we are going to ship */ - for (int k = 0; k < p->nr_cells_in; k++) - count_recv_cells += p->cells_in[k]->pcell_size; - - for (int k = 0; k < p->nr_cells_out; k++) - count_send_cells += p->cells_out[k]->pcell_size; - } - - /* Allocate the buffers for the packed data */ - struct gravity_tensors *buffer_send = NULL; - if (posix_memalign((void **)&buffer_send, SWIFT_CACHE_ALIGNMENT, - count_send_cells * sizeof(struct gravity_tensors)) != 0) - error("Unable to allocate memory for multipole transactions"); - - struct gravity_tensors *buffer_recv = NULL; - if (posix_memalign((void **)&buffer_recv, SWIFT_CACHE_ALIGNMENT, - count_recv_cells * sizeof(struct gravity_tensors)) != 0) - error("Unable to allocate memory for multipole transactions"); - - /* Also allocate the MPI requests */ - const int count_requests = count_send_requests + count_recv_requests; - MPI_Request *requests = - (MPI_Request *)malloc(sizeof(MPI_Request) * count_requests); - if (requests == NULL) error("Unable to allocate memory for MPI requests"); - - int this_request = 0; - int this_recv = 0; - int this_send = 0; - - /* Loop over the proxies to issue the receives. */ - for (int pid = 0; pid < e->nr_proxies; pid++) { - - /* Get a handle on the proxy. */ - const struct proxy *p = &e->proxies[pid]; - - for (int k = 0; k < p->nr_cells_in; k++) { - - const int num_elements = p->cells_in[k]->pcell_size; - - /* Receive everything */ - MPI_Irecv(&buffer_recv[this_recv], num_elements, multipole_mpi_type, - p->cells_in[k]->nodeID, p->cells_in[k]->tag, MPI_COMM_WORLD, - &requests[this_request]); - - /* Move to the next slot in the buffers */ - this_recv += num_elements; - this_request++; - } - - /* Loop over the proxies to issue the sends. */ - for (int k = 0; k < p->nr_cells_out; k++) { - - /* Number of multipoles in this cell hierarchy */ - const int num_elements = p->cells_out[k]->pcell_size; - - /* Let's pack everything recursively */ - cell_pack_multipoles(p->cells_out[k], &buffer_send[this_send]); - - /* Send everything (note the use of cells_in[0] to get the correct node - * ID. */ - MPI_Isend(&buffer_send[this_send], num_elements, multipole_mpi_type, - p->cells_in[0]->nodeID, p->cells_out[k]->tag, MPI_COMM_WORLD, - &requests[this_request]); - - /* Move to the next slot in the buffers */ - this_send += num_elements; - this_request++; - } - } - - /* Wait for all the requests to arrive home */ - MPI_Status *stats = (MPI_Status *)malloc(count_requests * sizeof(MPI_Status)); - int res; - if ((res = MPI_Waitall(count_requests, requests, stats)) != MPI_SUCCESS) { - for (int k = 0; k < count_requests; ++k) { - char buff[MPI_MAX_ERROR_STRING]; - MPI_Error_string(stats[k].MPI_ERROR, buff, &res); - message("request from source %i, tag %i has error '%s'.", - stats[k].MPI_SOURCE, stats[k].MPI_TAG, buff); - } - error("Failed during waitall for multipole data."); - } - - /* Let's now unpack the multipoles at the right place */ - this_recv = 0; - for (int pid = 0; pid < e->nr_proxies; pid++) { - - /* Get a handle on the proxy. */ - const struct proxy *p = &e->proxies[pid]; - - for (int k = 0; k < p->nr_cells_in; k++) { - - const int num_elements = p->cells_in[k]->pcell_size; - -#ifdef SWIFT_DEBUG_CHECKS - - /* Check that the first element (top-level cell's multipole) matches what - * we received */ - if (p->cells_in[k]->multipole->m_pole.num_gpart != - buffer_recv[this_recv].m_pole.num_gpart) - error("Current: M_000=%e num_gpart=%lld\n New: M_000=%e num_gpart=%lld", - p->cells_in[k]->multipole->m_pole.M_000, - p->cells_in[k]->multipole->m_pole.num_gpart, - buffer_recv[this_recv].m_pole.M_000, - buffer_recv[this_recv].m_pole.num_gpart); -#endif - - /* Unpack recursively */ - cell_unpack_multipoles(p->cells_in[k], &buffer_recv[this_recv]); - - /* Move to the next slot in the buffers */ - this_recv += num_elements; - } - } - - /* Free everything */ - free(stats); - free(buffer_send); - free(buffer_recv); - free(requests); - - /* How much time did this take? */ - if (e->verbose) - message("took %.3f %s.", clocks_from_ticks(getticks() - tic), - clocks_getunit()); -#else - error("SWIFT was not compiled with MPI support."); -#endif -} - -/** - * @brief Constructs the top-level tasks for the short-range gravity - * and long-range gravity interactions. - * - * - All top-cells get a self task. - * - All pairs within range according to the multipole acceptance - * criterion get a pair task. - */ -void engine_make_self_gravity_tasks_mapper(void *map_data, int num_elements, - void *extra_data) { - - struct engine *e = ((struct engine **)extra_data)[0]; - struct space *s = e->s; - struct scheduler *sched = &e->sched; - const int nodeID = e->nodeID; - const int periodic = s->periodic; - const double dim[3] = {s->dim[0], s->dim[1], s->dim[2]}; - const int cdim[3] = {s->cdim[0], s->cdim[1], s->cdim[2]}; - struct cell *cells = s->cells_top; - const double theta_crit = e->gravity_properties->theta_crit; - const double max_distance = e->mesh->r_cut_max; - - /* Compute how many cells away we need to walk */ - const double distance = 2.5 * cells[0].width[0] / theta_crit; - int delta = (int)(distance / cells[0].width[0]) + 1; - int delta_m = delta; - int delta_p = delta; - - /* Special case where every cell is in range of every other one */ - if (delta >= cdim[0] / 2) { - if (cdim[0] % 2 == 0) { - delta_m = cdim[0] / 2; - delta_p = cdim[0] / 2 - 1; - } else { - delta_m = cdim[0] / 2; - delta_p = cdim[0] / 2; - } - } - - /* Loop through the elements, which are just byte offsets from NULL. */ - for (int ind = 0; ind < num_elements; ind++) { - - /* Get the cell index. */ - const int cid = (size_t)(map_data) + ind; - - /* Integer indices of the cell in the top-level grid */ - const int i = cid / (cdim[1] * cdim[2]); - const int j = (cid / cdim[2]) % cdim[1]; - const int k = cid % cdim[2]; - - /* Get the cell */ - struct cell *ci = &cells[cid]; - - /* Skip cells without gravity particles */ - if (ci->gcount == 0) continue; - - /* Is that cell local ? */ - if (ci->nodeID != nodeID) continue; - - /* If the cells is local build a self-interaction */ - scheduler_addtask(sched, task_type_self, task_subtype_grav, 0, 0, ci, NULL); - - /* Recover the multipole information */ - const struct gravity_tensors *const multi_i = ci->multipole; - const double CoM_i[3] = {multi_i->CoM[0], multi_i->CoM[1], multi_i->CoM[2]}; - -#ifdef SWIFT_DEBUG_CHECKS - if (cell_getid(cdim, i, j, k) != cid) - error("Incorrect calculation of indices (i,j,k)=(%d,%d,%d) cid=%d", i, j, - k, cid); - - if (multi_i->r_max != multi_i->r_max_rebuild) - error( - "Multipole size not equal ot it's size after rebuild. But we just " - "rebuilt..."); -#endif - - /* Loop over every other cell within (Manhattan) range delta */ - for (int x = -delta_m; x <= delta_p; x++) { - int ii = i + x; - if (ii >= cdim[0]) - ii -= cdim[0]; - else if (ii < 0) - ii += cdim[0]; - for (int y = -delta_m; y <= delta_p; y++) { - int jj = j + y; - if (jj >= cdim[1]) - jj -= cdim[1]; - else if (jj < 0) - jj += cdim[1]; - for (int z = -delta_m; z <= delta_p; z++) { - int kk = k + z; - if (kk >= cdim[2]) - kk -= cdim[2]; - else if (kk < 0) - kk += cdim[2]; - - /* Get the cell */ - const int cjd = cell_getid(cdim, ii, jj, kk); - struct cell *cj = &cells[cjd]; - -#ifdef SWIFT_DEBUG_CHECKS - const int iii = cjd / (cdim[1] * cdim[2]); - const int jjj = (cjd / cdim[2]) % cdim[1]; - const int kkk = cjd % cdim[2]; - - if (ii != iii || jj != jjj || kk != kkk) - error( - "Incorrect calculation of indices (iii,jjj,kkk)=(%d,%d,%d) " - "cjd=%d", - iii, jjj, kkk, cjd); -#endif - - /* Avoid duplicates of local pairs*/ - if (cid <= cjd && cj->nodeID == nodeID) continue; - - /* Skip cells without gravity particles */ - if (cj->gcount == 0) continue; - - /* Recover the multipole information */ - const struct gravity_tensors *const multi_j = cj->multipole; - - /* Get the distance between the CoMs */ - double dx = CoM_i[0] - multi_j->CoM[0]; - double dy = CoM_i[1] - multi_j->CoM[1]; - double dz = CoM_i[2] - multi_j->CoM[2]; - - /* Apply BC */ - if (periodic) { - dx = nearest(dx, dim[0]); - dy = nearest(dy, dim[1]); - dz = nearest(dz, dim[2]); - } - const double r2 = dx * dx + dy * dy + dz * dz; - - /* Minimal distance between any pair of particles */ - const double min_radius = - sqrt(r2) - (multi_i->r_max + multi_j->r_max); - - /* Are we beyond the distance where the truncated forces are 0 ?*/ - if (periodic && min_radius > max_distance) continue; - - /* Are the cells too close for a MM interaction ? */ - if (!cell_can_use_pair_mm_rebuild(ci, cj, e, s)) { - - /* Ok, we need to add a direct pair calculation */ - scheduler_addtask(sched, task_type_pair, task_subtype_grav, 0, 0, - ci, cj); - } - } - } - } - } -} - -/** - * @brief Constructs the top-level tasks for the short-range gravity - * interactions (master function). - * - * - Create the FFT task and the array of gravity ghosts. - * - Call the mapper function to create the other tasks. - * - * @param e The #engine. - */ -void engine_make_self_gravity_tasks(struct engine *e) { - - struct space *s = e->s; - struct task **ghosts = NULL; - - /* Create the multipole self and pair tasks. */ - void *extra_data[2] = {e, ghosts}; - threadpool_map(&e->threadpool, engine_make_self_gravity_tasks_mapper, NULL, - s->nr_cells, 1, 0, extra_data); -} - -/** - * @brief Constructs the top-level tasks for the external gravity. - * - * @param e The #engine. - */ -void engine_make_external_gravity_tasks(struct engine *e) { - - struct space *s = e->s; - struct scheduler *sched = &e->sched; - const int nodeID = e->nodeID; - struct cell *cells = s->cells_top; - const int nr_cells = s->nr_cells; - - for (int cid = 0; cid < nr_cells; ++cid) { - - struct cell *ci = &cells[cid]; - - /* Skip cells without gravity particles */ - if (ci->gcount == 0) continue; - - /* Is that neighbour local ? */ - if (ci->nodeID != nodeID) continue; - - /* If the cell is local, build a self-interaction */ - scheduler_addtask(sched, task_type_self, task_subtype_external_grav, 0, 0, - ci, NULL); - } -} - -/** - * @brief Constructs the top-level pair tasks for the first hydro loop over - * neighbours - * - * Here we construct all the tasks for all possible neighbouring non-empty - * local cells in the hierarchy. No dependencies are being added thus far. - * Additional loop over neighbours can later be added by simply duplicating - * all the tasks created by this function. - * - * @param map_data Offset of first two indices disguised as a pointer. - * @param num_elements Number of cells to traverse. - * @param extra_data The #engine. - */ -void engine_make_hydroloop_tasks_mapper(void *map_data, int num_elements, - void *extra_data) { - - /* Extract the engine pointer. */ - struct engine *e = (struct engine *)extra_data; - - struct space *s = e->s; - struct scheduler *sched = &e->sched; - const int nodeID = e->nodeID; - const int *cdim = s->cdim; - struct cell *cells = s->cells_top; - - /* Loop through the elements, which are just byte offsets from NULL. */ - for (int ind = 0; ind < num_elements; ind++) { - - /* Get the cell index. */ - const int cid = (size_t)(map_data) + ind; - const int i = cid / (cdim[1] * cdim[2]); - const int j = (cid / cdim[2]) % cdim[1]; - const int k = cid % cdim[2]; - - /* Get the cell */ - struct cell *ci = &cells[cid]; - - /* Skip cells without hydro particles */ - if (ci->count == 0) continue; - - /* If the cells is local build a self-interaction */ - if (ci->nodeID == nodeID) - scheduler_addtask(sched, task_type_self, task_subtype_density, 0, 0, ci, - NULL); - - /* Now loop over all the neighbours of this cell */ - for (int ii = -1; ii < 2; ii++) { - int iii = i + ii; - if (!s->periodic && (iii < 0 || iii >= cdim[0])) continue; - iii = (iii + cdim[0]) % cdim[0]; - for (int jj = -1; jj < 2; jj++) { - int jjj = j + jj; - if (!s->periodic && (jjj < 0 || jjj >= cdim[1])) continue; - jjj = (jjj + cdim[1]) % cdim[1]; - for (int kk = -1; kk < 2; kk++) { - int kkk = k + kk; - if (!s->periodic && (kkk < 0 || kkk >= cdim[2])) continue; - kkk = (kkk + cdim[2]) % cdim[2]; - - /* Get the neighbouring cell */ - const int cjd = cell_getid(cdim, iii, jjj, kkk); - struct cell *cj = &cells[cjd]; - - /* Is that neighbour local and does it have particles ? */ - if (cid >= cjd || cj->count == 0 || - (ci->nodeID != nodeID && cj->nodeID != nodeID)) - continue; - - /* Construct the pair task */ - const int sid = sortlistID[(kk + 1) + 3 * ((jj + 1) + 3 * (ii + 1))]; - scheduler_addtask(sched, task_type_pair, task_subtype_density, sid, 0, - ci, cj); - } - } - } - } -} - -/** - * @brief Constructs the top-level pair tasks for the star loop over - * neighbours - * - * Here we construct all the tasks for all possible neighbouring non-empty - * local cells in the hierarchy. No dependencies are being added thus far. - * Additional loop over neighbours can later be added by simply duplicating - * all the tasks created by this function. - * - * @param map_data Offset of first two indices disguised as a pointer. - * @param num_elements Number of cells to traverse. - * @param extra_data The #engine. - */ -void engine_make_starsloop_tasks_mapper(void *map_data, int num_elements, - void *extra_data) { - - /* Extract the engine pointer. */ - struct engine *e = (struct engine *)extra_data; - - struct space *s = e->s; - struct scheduler *sched = &e->sched; - const int nodeID = e->nodeID; - const int *cdim = s->cdim; - struct cell *cells = s->cells_top; - - /* Loop through the elements, which are just byte offsets from NULL. */ - for (int ind = 0; ind < num_elements; ind++) { - - /* Get the cell index. */ - const int cid = (size_t)(map_data) + ind; - const int i = cid / (cdim[1] * cdim[2]); - const int j = (cid / cdim[2]) % cdim[1]; - const int k = cid % cdim[2]; - - /* Get the cell */ - struct cell *ci = &cells[cid]; - - /* Skip cells without star particles */ - if (ci->scount == 0) continue; - - /* If the cells is local build a self-interaction */ - if (ci->nodeID == nodeID) - scheduler_addtask(sched, task_type_self, task_subtype_stars_density, 0, 0, - ci, NULL); - - /* Now loop over all the neighbours of this cell */ - for (int ii = -1; ii < 2; ii++) { - int iii = i + ii; - if (!s->periodic && (iii < 0 || iii >= cdim[0])) continue; - iii = (iii + cdim[0]) % cdim[0]; - for (int jj = -1; jj < 2; jj++) { - int jjj = j + jj; - if (!s->periodic && (jjj < 0 || jjj >= cdim[1])) continue; - jjj = (jjj + cdim[1]) % cdim[1]; - for (int kk = -1; kk < 2; kk++) { - int kkk = k + kk; - if (!s->periodic && (kkk < 0 || kkk >= cdim[2])) continue; - kkk = (kkk + cdim[2]) % cdim[2]; - - /* Get the neighbouring cell */ - const int cjd = cell_getid(cdim, iii, jjj, kkk); - struct cell *cj = &cells[cjd]; - - /* Is that neighbour local and does it have particles ? */ - if (cid >= cjd || cj->count == 0 || - (ci->nodeID != nodeID && cj->nodeID != nodeID)) - continue; - - /* Construct the pair task */ - const int sid = sortlistID[(kk + 1) + 3 * ((jj + 1) + 3 * (ii + 1))]; - scheduler_addtask(sched, task_type_pair, task_subtype_stars_density, - sid, 0, ci, cj); - } - } - } - } -} - -/** - * @brief Counts the tasks associated with one cell and constructs the links - * - * For each hydrodynamic and gravity task, construct the links with - * the corresponding cell. Similarly, construct the dependencies for - * all the sorting tasks. - */ -void engine_count_and_link_tasks_mapper(void *map_data, int num_elements, - void *extra_data) { - - struct engine *e = (struct engine *)extra_data; - struct scheduler *const sched = &e->sched; - - for (int ind = 0; ind < num_elements; ind++) { - struct task *t = &((struct task *)map_data)[ind]; - - struct cell *ci = t->ci; - struct cell *cj = t->cj; - const enum task_types t_type = t->type; - const enum task_subtypes t_subtype = t->subtype; - - /* Link sort tasks to all the higher sort task. */ - if (t_type == task_type_sort) { - for (struct cell *finger = t->ci->parent; finger != NULL; - finger = finger->parent) - if (finger->sorts != NULL) scheduler_addunlock(sched, t, finger->sorts); - } - - /* Link self tasks to cells. */ - else if (t_type == task_type_self) { - atomic_inc(&ci->nr_tasks); - - if (t_subtype == task_subtype_density) { - engine_addlink(e, &ci->density, t); - } else if (t_subtype == task_subtype_grav) { - engine_addlink(e, &ci->grav, t); - } else if (t_subtype == task_subtype_external_grav) { - engine_addlink(e, &ci->grav, t); - } else if (t->subtype == task_subtype_stars_density) { - engine_addlink(e, &ci->stars_density, t); - } - - /* Link pair tasks to cells. */ - } else if (t_type == task_type_pair) { - atomic_inc(&ci->nr_tasks); - atomic_inc(&cj->nr_tasks); - - if (t_subtype == task_subtype_density) { - engine_addlink(e, &ci->density, t); - engine_addlink(e, &cj->density, t); - } else if (t_subtype == task_subtype_grav) { - engine_addlink(e, &ci->grav, t); - engine_addlink(e, &cj->grav, t); - } else if (t->subtype == task_subtype_stars_density) { - engine_addlink(e, &ci->stars_density, t); - engine_addlink(e, &cj->stars_density, t); - } -#ifdef SWIFT_DEBUG_CHECKS - else if (t_subtype == task_subtype_external_grav) { - error("Found a pair/external-gravity task..."); - } -#endif - - /* Link sub-self tasks to cells. */ - } else if (t_type == task_type_sub_self) { - atomic_inc(&ci->nr_tasks); - - if (t_subtype == task_subtype_density) { - engine_addlink(e, &ci->density, t); - } else if (t_subtype == task_subtype_grav) { - engine_addlink(e, &ci->grav, t); - } else if (t_subtype == task_subtype_external_grav) { - engine_addlink(e, &ci->grav, t); - } else if (t->subtype == task_subtype_stars_density) { - engine_addlink(e, &ci->stars_density, t); - } - - /* Link sub-pair tasks to cells. */ - } else if (t_type == task_type_sub_pair) { - atomic_inc(&ci->nr_tasks); - atomic_inc(&cj->nr_tasks); - - if (t_subtype == task_subtype_density) { - engine_addlink(e, &ci->density, t); - engine_addlink(e, &cj->density, t); - } else if (t_subtype == task_subtype_grav) { - engine_addlink(e, &ci->grav, t); - engine_addlink(e, &cj->grav, t); - } else if (t->subtype == task_subtype_stars_density) { - engine_addlink(e, &ci->stars_density, t); - engine_addlink(e, &cj->stars_density, t); - } -#ifdef SWIFT_DEBUG_CHECKS - else if (t_subtype == task_subtype_external_grav) { - error("Found a sub-pair/external-gravity task..."); - } -#endif - - /* Multipole-multipole interaction of progenies */ - } else if (t_type == task_type_grav_mm) { - - atomic_inc(&ci->nr_mm_tasks); - atomic_inc(&cj->nr_mm_tasks); - engine_addlink(e, &ci->grav_mm, t); - engine_addlink(e, &cj->grav_mm, t); - } - } -} - -/** - * @brief Creates all the task dependencies for the gravity - * - * @param e The #engine - */ -void engine_link_gravity_tasks(struct engine *e) { - - struct scheduler *sched = &e->sched; - const int nodeID = e->nodeID; - const int nr_tasks = sched->nr_tasks; - - for (int k = 0; k < nr_tasks; k++) { - - /* Get a pointer to the task. */ - struct task *t = &sched->tasks[k]; - - if (t->type == task_type_none) continue; - - /* Get the cells we act on */ - struct cell *ci = t->ci; - struct cell *cj = t->cj; - const enum task_types t_type = t->type; - const enum task_subtypes t_subtype = t->subtype; - - struct cell *ci_parent = (ci->parent != NULL) ? ci->parent : ci; - struct cell *cj_parent = - (cj != NULL && cj->parent != NULL) ? cj->parent : cj; - -/* Node ID (if running with MPI) */ -#ifdef WITH_MPI - const int ci_nodeID = ci->nodeID; - const int cj_nodeID = (cj != NULL) ? cj->nodeID : -1; -#else - const int ci_nodeID = nodeID; - const int cj_nodeID = nodeID; -#endif - - /* Self-interaction for self-gravity? */ - if (t_type == task_type_self && t_subtype == task_subtype_grav) { - -#ifdef SWIFT_DEBUG_CHECKS - if (ci_nodeID != nodeID) error("Non-local self task"); -#endif - - /* drift ---+-> gravity --> grav_down */ - /* init --/ */ - scheduler_addunlock(sched, ci->super_gravity->drift_gpart, t); - scheduler_addunlock(sched, ci_parent->init_grav_out, t); - scheduler_addunlock(sched, t, ci_parent->grav_down_in); - } - - /* Self-interaction for external gravity ? */ - if (t_type == task_type_self && t_subtype == task_subtype_external_grav) { - -#ifdef SWIFT_DEBUG_CHECKS - if (ci_nodeID != nodeID) error("Non-local self task"); -#endif - - /* drift -----> gravity --> end_force */ - scheduler_addunlock(sched, ci->super_gravity->drift_gpart, t); - scheduler_addunlock(sched, t, ci->super->end_force); - } - - /* Otherwise, pair interaction? */ - else if (t_type == task_type_pair && t_subtype == task_subtype_grav) { - - if (ci_nodeID == nodeID) { - - /* drift ---+-> gravity --> grav_down */ - /* init --/ */ - scheduler_addunlock(sched, ci->super_gravity->drift_gpart, t); - scheduler_addunlock(sched, ci_parent->init_grav_out, t); - scheduler_addunlock(sched, t, ci_parent->grav_down_in); - } - if (cj_nodeID == nodeID) { - - /* drift ---+-> gravity --> grav_down */ - /* init --/ */ - if (ci->super_gravity != cj->super_gravity) /* Avoid double unlock */ - scheduler_addunlock(sched, cj->super_gravity->drift_gpart, t); - - if (ci_parent != cj_parent) { /* Avoid double unlock */ - scheduler_addunlock(sched, cj_parent->init_grav_out, t); - scheduler_addunlock(sched, t, cj_parent->grav_down_in); - } - } - } - - /* Otherwise, sub-self interaction? */ - else if (t_type == task_type_sub_self && t_subtype == task_subtype_grav) { - -#ifdef SWIFT_DEBUG_CHECKS - if (ci_nodeID != nodeID) error("Non-local sub-self task"); -#endif - /* drift ---+-> gravity --> grav_down */ - /* init --/ */ - scheduler_addunlock(sched, ci->super_gravity->drift_gpart, t); - scheduler_addunlock(sched, ci_parent->init_grav_out, t); - scheduler_addunlock(sched, t, ci_parent->grav_down_in); - } - - /* Sub-self-interaction for external gravity ? */ - else if (t_type == task_type_sub_self && - t_subtype == task_subtype_external_grav) { - -#ifdef SWIFT_DEBUG_CHECKS - if (ci_nodeID != nodeID) error("Non-local sub-self task"); -#endif - - /* drift -----> gravity --> end_force */ - scheduler_addunlock(sched, ci->super_gravity->drift_gpart, t); - scheduler_addunlock(sched, t, ci->super->end_force); - } - - /* Otherwise, sub-pair interaction? */ - else if (t_type == task_type_sub_pair && t_subtype == task_subtype_grav) { - - if (ci_nodeID == nodeID) { - - /* drift ---+-> gravity --> grav_down */ - /* init --/ */ - scheduler_addunlock(sched, ci->super_gravity->drift_gpart, t); - scheduler_addunlock(sched, ci_parent->init_grav_out, t); - scheduler_addunlock(sched, t, ci_parent->grav_down_in); - } - if (cj_nodeID == nodeID) { - - /* drift ---+-> gravity --> grav_down */ - /* init --/ */ - if (ci->super_gravity != cj->super_gravity) /* Avoid double unlock */ - scheduler_addunlock(sched, cj->super_gravity->drift_gpart, t); - - if (ci_parent != cj_parent) { /* Avoid double unlock */ - scheduler_addunlock(sched, cj_parent->init_grav_out, t); - scheduler_addunlock(sched, t, cj_parent->grav_down_in); - } - } - } - - /* Otherwise M-M interaction? */ - else if (t_type == task_type_grav_mm) { - - if (ci_nodeID == nodeID) { - - /* init -----> gravity --> grav_down */ - scheduler_addunlock(sched, ci_parent->init_grav_out, t); - scheduler_addunlock(sched, t, ci_parent->grav_down_in); - } - if (cj_nodeID == nodeID) { - - /* init -----> gravity --> grav_down */ - if (ci_parent != cj_parent) { /* Avoid double unlock */ - scheduler_addunlock(sched, cj_parent->init_grav_out, t); - scheduler_addunlock(sched, t, cj_parent->grav_down_in); - } - } - } - } -} - -#ifdef EXTRA_HYDRO_LOOP - -/** - * @brief Creates the dependency network for the hydro tasks of a given cell. - * - * @param sched The #scheduler. - * @param density The density task to link. - * @param gradient The gradient task to link. - * @param force The force task to link. - * @param c The cell. - * @param with_cooling Do we have a cooling task ? - */ -static inline void engine_make_hydro_loops_dependencies( - struct scheduler *sched, struct task *density, struct task *gradient, - struct task *force, struct cell *c, int with_cooling) { - - /* density loop --> ghost --> gradient loop --> extra_ghost */ - /* extra_ghost --> force loop */ - scheduler_addunlock(sched, density, c->super_hydro->ghost_in); - scheduler_addunlock(sched, c->super_hydro->ghost_out, gradient); - scheduler_addunlock(sched, gradient, c->super_hydro->extra_ghost); - scheduler_addunlock(sched, c->super_hydro->extra_ghost, force); -} - -#else - -/** - * @brief Creates the dependency network for the hydro tasks of a given cell. - * - * @param sched The #scheduler. - * @param density The density task to link. - * @param force The force task to link. - * @param c The cell. - * @param with_cooling Are we running with cooling switched on ? - */ -static inline void engine_make_hydro_loops_dependencies(struct scheduler *sched, - struct task *density, - struct task *force, - struct cell *c, - int with_cooling) { - /* density loop --> ghost --> force loop */ - scheduler_addunlock(sched, density, c->super_hydro->ghost_in); - scheduler_addunlock(sched, c->super_hydro->ghost_out, force); -} - -#endif -/** - * @brief Creates the dependency network for the stars tasks of a given cell. - * - * @param sched The #scheduler. - * @param density The density task to link. - * @param c The cell. - */ -static inline void engine_make_stars_loops_dependencies(struct scheduler *sched, - struct task *density, - struct cell *c) { - /* density loop --> ghost */ - scheduler_addunlock(sched, density, c->super->stars_ghost_in); -} - -/** - * @brief Duplicates the first hydro loop and construct all the - * dependencies for the hydro part - * - * This is done by looping over all the previously constructed tasks - * and adding another task involving the same cells but this time - * corresponding to the second hydro loop over neighbours. - * With all the relevant tasks for a given cell available, we construct - * all the dependencies for that cell. - */ -void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, - void *extra_data) { - - struct engine *e = (struct engine *)extra_data; - struct scheduler *sched = &e->sched; - const int nodeID = e->nodeID; - const int with_cooling = (e->policy & engine_policy_cooling); - - for (int ind = 0; ind < num_elements; ind++) { - struct task *t = &((struct task *)map_data)[ind]; - - /* Sort tasks depend on the drift of the cell. */ - if (t->type == task_type_sort && t->ci->nodeID == engine_rank) { - scheduler_addunlock(sched, t->ci->super_hydro->drift_part, t); - } - - /* Self-interaction? */ - else if (t->type == task_type_self && t->subtype == task_subtype_density) { - - /* Make the self-density tasks depend on the drift only. */ - scheduler_addunlock(sched, t->ci->super_hydro->drift_part, t); - -#ifdef EXTRA_HYDRO_LOOP - /* Start by constructing the task for the second and third hydro loop. */ - struct task *t2 = scheduler_addtask( - sched, task_type_self, task_subtype_gradient, 0, 0, t->ci, NULL); - struct task *t3 = scheduler_addtask( - sched, task_type_self, task_subtype_force, 0, 0, t->ci, NULL); - - /* Add the link between the new loops and the cell */ - engine_addlink(e, &t->ci->gradient, t2); - engine_addlink(e, &t->ci->force, t3); - - /* Now, build all the dependencies for the hydro */ - engine_make_hydro_loops_dependencies(sched, t, t2, t3, t->ci, - with_cooling); - scheduler_addunlock(sched, t3, t->ci->super->end_force); -#else - - /* Start by constructing the task for the second hydro loop */ - struct task *t2 = scheduler_addtask( - sched, task_type_self, task_subtype_force, 0, 0, t->ci, NULL); - - /* Add the link between the new loop and the cell */ - engine_addlink(e, &t->ci->force, t2); - - /* Now, build all the dependencies for the hydro */ - engine_make_hydro_loops_dependencies(sched, t, t2, t->ci, with_cooling); - scheduler_addunlock(sched, t2, t->ci->super->end_force); -#endif - } - - /* Otherwise, pair interaction? */ - else if (t->type == task_type_pair && t->subtype == task_subtype_density) { - - /* Make all density tasks depend on the drift and the sorts. */ - if (t->ci->nodeID == engine_rank) - scheduler_addunlock(sched, t->ci->super_hydro->drift_part, t); - scheduler_addunlock(sched, t->ci->super_hydro->sorts, t); - if (t->ci->super_hydro != t->cj->super_hydro) { - if (t->cj->nodeID == engine_rank) - scheduler_addunlock(sched, t->cj->super_hydro->drift_part, t); - scheduler_addunlock(sched, t->cj->super_hydro->sorts, t); - } - -#ifdef EXTRA_HYDRO_LOOP - /* Start by constructing the task for the second and third hydro loop */ - struct task *t2 = scheduler_addtask( - sched, task_type_pair, task_subtype_gradient, 0, 0, t->ci, t->cj); - struct task *t3 = scheduler_addtask( - sched, task_type_pair, task_subtype_force, 0, 0, t->ci, t->cj); - - /* Add the link between the new loop and both cells */ - engine_addlink(e, &t->ci->gradient, t2); - engine_addlink(e, &t->cj->gradient, t2); - engine_addlink(e, &t->ci->force, t3); - engine_addlink(e, &t->cj->force, t3); - - /* Now, build all the dependencies for the hydro for the cells */ - /* that are local and are not descendant of the same super_hydro-cells */ - if (t->ci->nodeID == nodeID) { - engine_make_hydro_loops_dependencies(sched, t, t2, t3, t->ci, - with_cooling); - scheduler_addunlock(sched, t3, t->ci->super->end_force); - } - if (t->cj->nodeID == nodeID) { - if (t->ci->super_hydro != t->cj->super_hydro) - engine_make_hydro_loops_dependencies(sched, t, t2, t3, t->cj, - with_cooling); - if (t->ci->super != t->cj->super) - scheduler_addunlock(sched, t3, t->cj->super->end_force); - } - -#else - - /* Start by constructing the task for the second hydro loop */ - struct task *t2 = scheduler_addtask( - sched, task_type_pair, task_subtype_force, 0, 0, t->ci, t->cj); - - /* Add the link between the new loop and both cells */ - engine_addlink(e, &t->ci->force, t2); - engine_addlink(e, &t->cj->force, t2); - - /* Now, build all the dependencies for the hydro for the cells */ - /* that are local and are not descendant of the same super_hydro-cells */ - if (t->ci->nodeID == nodeID) { - engine_make_hydro_loops_dependencies(sched, t, t2, t->ci, with_cooling); - scheduler_addunlock(sched, t2, t->ci->super->end_force); - } - if (t->cj->nodeID == nodeID) { - if (t->ci->super_hydro != t->cj->super_hydro) - engine_make_hydro_loops_dependencies(sched, t, t2, t->cj, - with_cooling); - if (t->ci->super != t->cj->super) - scheduler_addunlock(sched, t2, t->cj->super->end_force); - } - -#endif - - } - - /* Otherwise, sub-self interaction? */ - else if (t->type == task_type_sub_self && - t->subtype == task_subtype_density) { - - /* Make all density tasks depend on the drift and sorts. */ - scheduler_addunlock(sched, t->ci->super_hydro->drift_part, t); - scheduler_addunlock(sched, t->ci->super_hydro->sorts, t); - -#ifdef EXTRA_HYDRO_LOOP - - /* Start by constructing the task for the second and third hydro loop */ - struct task *t2 = - scheduler_addtask(sched, task_type_sub_self, task_subtype_gradient, - t->flags, 0, t->ci, t->cj); - struct task *t3 = - scheduler_addtask(sched, task_type_sub_self, task_subtype_force, - t->flags, 0, t->ci, t->cj); - - /* Add the link between the new loop and the cell */ - engine_addlink(e, &t->ci->gradient, t2); - engine_addlink(e, &t->ci->force, t3); - - /* Now, build all the dependencies for the hydro for the cells */ - /* that are local and are not descendant of the same super_hydro-cells */ - if (t->ci->nodeID == nodeID) { - engine_make_hydro_loops_dependencies(sched, t, t2, t3, t->ci, - with_cooling); - scheduler_addunlock(sched, t3, t->ci->super->end_force); - } - -#else - /* Start by constructing the task for the second hydro loop */ - struct task *t2 = - scheduler_addtask(sched, task_type_sub_self, task_subtype_force, - t->flags, 0, t->ci, t->cj); - - /* Add the link between the new loop and the cell */ - engine_addlink(e, &t->ci->force, t2); - - /* Now, build all the dependencies for the hydro for the cells */ - /* that are local and are not descendant of the same super_hydro-cells */ - if (t->ci->nodeID == nodeID) { - engine_make_hydro_loops_dependencies(sched, t, t2, t->ci, with_cooling); - scheduler_addunlock(sched, t2, t->ci->super->end_force); - } -#endif - } - - /* Otherwise, sub-pair interaction? */ - else if (t->type == task_type_sub_pair && - t->subtype == task_subtype_density) { - - /* Make all density tasks depend on the drift. */ - if (t->ci->nodeID == engine_rank) - scheduler_addunlock(sched, t->ci->super_hydro->drift_part, t); - scheduler_addunlock(sched, t->ci->super_hydro->sorts, t); - if (t->ci->super_hydro != t->cj->super_hydro) { - if (t->cj->nodeID == engine_rank) - scheduler_addunlock(sched, t->cj->super_hydro->drift_part, t); - scheduler_addunlock(sched, t->cj->super_hydro->sorts, t); - } - -#ifdef EXTRA_HYDRO_LOOP - - /* Start by constructing the task for the second and third hydro loop */ - struct task *t2 = - scheduler_addtask(sched, task_type_sub_pair, task_subtype_gradient, - t->flags, 0, t->ci, t->cj); - struct task *t3 = - scheduler_addtask(sched, task_type_sub_pair, task_subtype_force, - t->flags, 0, t->ci, t->cj); - - /* Add the link between the new loop and both cells */ - engine_addlink(e, &t->ci->gradient, t2); - engine_addlink(e, &t->cj->gradient, t2); - engine_addlink(e, &t->ci->force, t3); - engine_addlink(e, &t->cj->force, t3); - - /* Now, build all the dependencies for the hydro for the cells */ - /* that are local and are not descendant of the same super_hydro-cells */ - if (t->ci->nodeID == nodeID) { - engine_make_hydro_loops_dependencies(sched, t, t2, t3, t->ci, - with_cooling); - scheduler_addunlock(sched, t3, t->ci->super->end_force); - } - if (t->cj->nodeID == nodeID) { - if (t->ci->super_hydro != t->cj->super_hydro) - engine_make_hydro_loops_dependencies(sched, t, t2, t3, t->cj, - with_cooling); - if (t->ci->super != t->cj->super) - scheduler_addunlock(sched, t3, t->cj->super->end_force); - } - -#else - /* Start by constructing the task for the second hydro loop */ - struct task *t2 = - scheduler_addtask(sched, task_type_sub_pair, task_subtype_force, - t->flags, 0, t->ci, t->cj); - - /* Add the link between the new loop and both cells */ - engine_addlink(e, &t->ci->force, t2); - engine_addlink(e, &t->cj->force, t2); - - /* Now, build all the dependencies for the hydro for the cells */ - /* that are local and are not descendant of the same super_hydro-cells */ - if (t->ci->nodeID == nodeID) { - engine_make_hydro_loops_dependencies(sched, t, t2, t->ci, with_cooling); - scheduler_addunlock(sched, t2, t->ci->super->end_force); - } - if (t->cj->nodeID == nodeID) { - if (t->ci->super_hydro != t->cj->super_hydro) - engine_make_hydro_loops_dependencies(sched, t, t2, t->cj, - with_cooling); - if (t->ci->super != t->cj->super) - scheduler_addunlock(sched, t2, t->cj->super->end_force); - } -#endif - } - } -} - -/** - * @brief Duplicates the first hydro loop and construct all the - * dependencies for the stars - * - * This is done by looping over all the previously constructed tasks - * and adding another task involving the same cells but this time - * corresponding to the second hydro loop over neighbours. - * With all the relevant tasks for a given cell available, we construct - * all the dependencies for that cell. - */ -void engine_link_stars_tasks_mapper(void *map_data, int num_elements, - void *extra_data) { - - struct engine *e = (struct engine *)extra_data; - struct scheduler *sched = &e->sched; - const int nodeID = e->nodeID; - - for (int ind = 0; ind < num_elements; ind++) { - struct task *t = &((struct task *)map_data)[ind]; - - /* Self-interaction? */ - if (t->type == task_type_self && t->subtype == task_subtype_stars_density) { - - /* Make the self-density tasks depend on the drifts. */ - scheduler_addunlock(sched, t->ci->super->drift_part, t); - - scheduler_addunlock(sched, t->ci->super->drift_gpart, t); - - /* Now, build all the dependencies for the stars */ - engine_make_stars_loops_dependencies(sched, t, t->ci); - scheduler_addunlock(sched, t->ci->stars_ghost_out, - t->ci->super->end_force); - } - - /* Otherwise, pair interaction? */ - else if (t->type == task_type_pair && - t->subtype == task_subtype_stars_density) { - - /* Make all density tasks depend on the drift and the sorts. */ - if (t->ci->nodeID == engine_rank) - scheduler_addunlock(sched, t->ci->super->drift_part, t); - scheduler_addunlock(sched, t->ci->super->sorts, t); - if (t->ci->super != t->cj->super) { - if (t->cj->nodeID == engine_rank) - scheduler_addunlock(sched, t->cj->super->drift_part, t); - scheduler_addunlock(sched, t->cj->super->sorts, t); - } - - /* Now, build all the dependencies for the stars for the cells */ - /* that are local and are not descendant of the same super-cells */ - if (t->ci->nodeID == nodeID) { - engine_make_stars_loops_dependencies(sched, t, t->ci); - } - if (t->cj->nodeID == nodeID) { - if (t->ci->super != t->cj->super) - engine_make_stars_loops_dependencies(sched, t, t->cj); - } - - } - - /* Otherwise, sub-self interaction? */ - else if (t->type == task_type_sub_self && - t->subtype == task_subtype_stars_density) { - - /* Make all density tasks depend on the drift and sorts. */ - scheduler_addunlock(sched, t->ci->super->drift_part, t); - scheduler_addunlock(sched, t->ci->super->sorts, t); - - /* Now, build all the dependencies for the stars for the cells */ - /* that are local and are not descendant of the same super-cells */ - if (t->ci->nodeID == nodeID) { - engine_make_stars_loops_dependencies(sched, t, t->ci); - } else - error("oo"); - } - - /* Otherwise, sub-pair interaction? */ - else if (t->type == task_type_sub_pair && - t->subtype == task_subtype_stars_density) { - - /* Make all density tasks depend on the drift. */ - if (t->ci->nodeID == engine_rank) - scheduler_addunlock(sched, t->ci->super->drift_part, t); - scheduler_addunlock(sched, t->ci->super->sorts, t); - if (t->ci->super != t->cj->super) { - if (t->cj->nodeID == engine_rank) - scheduler_addunlock(sched, t->cj->super->drift_part, t); - scheduler_addunlock(sched, t->cj->super->sorts, t); - } - - /* Now, build all the dependencies for the stars for the cells */ - /* that are local and are not descendant of the same super-cells */ - if (t->ci->nodeID == nodeID) { - engine_make_stars_loops_dependencies(sched, t, t->ci); - } - if (t->cj->nodeID == nodeID) { - if (t->ci->super != t->cj->super) - engine_make_stars_loops_dependencies(sched, t, t->cj); - } - } - } -} - -/** - * @brief Fill the #space's task list. - * - * @param e The #engine we are working with. - */ -void engine_maketasks(struct engine *e) { - - struct space *s = e->s; - struct scheduler *sched = &e->sched; - struct cell *cells = s->cells_top; - const int nr_cells = s->nr_cells; - const ticks tic = getticks(); - - /* Re-set the scheduler. */ - scheduler_reset(sched, engine_estimate_nr_tasks(e)); - - ticks tic2 = getticks(); - - /* Construct the first hydro loop over neighbours */ - if (e->policy & engine_policy_hydro) - threadpool_map(&e->threadpool, engine_make_hydroloop_tasks_mapper, NULL, - s->nr_cells, 1, 0, e); - - if (e->verbose) - message("Making hydro tasks took %.3f %s.", - clocks_from_ticks(getticks() - tic2), clocks_getunit()); - - tic2 = getticks(); - - /* Construct the stars hydro loop over neighbours */ - if (e->policy & engine_policy_feedback) { - threadpool_map(&e->threadpool, engine_make_starsloop_tasks_mapper, NULL, - s->nr_cells, 1, 0, e); - } - - /* Add the self gravity tasks. */ - if (e->policy & engine_policy_self_gravity) engine_make_self_gravity_tasks(e); - - if (e->verbose) - message("Making gravity tasks took %.3f %s.", - clocks_from_ticks(getticks() - tic2), clocks_getunit()); - - /* Add the external gravity tasks. */ - if (e->policy & engine_policy_external_gravity) - engine_make_external_gravity_tasks(e); - - if (e->sched.nr_tasks == 0 && (s->nr_gparts > 0 || s->nr_parts > 0)) - error("We have particles but no hydro or gravity tasks were created."); - - /* Free the old list of cell-task links. */ - if (e->links != NULL) free(e->links); - e->size_links = 0; - -/* The maximum number of links is the - * number of cells (s->tot_cells) times the number of neighbours (26) times - * the number of interaction types, so 26 * 2 (density, force) pairs - * and 2 (density, force) self. - */ -#ifdef EXTRA_HYDRO_LOOP - const size_t hydro_tasks_per_cell = 27 * 3; -#else - const size_t hydro_tasks_per_cell = 27 * 2; -#endif - const size_t self_grav_tasks_per_cell = 125; - const size_t ext_grav_tasks_per_cell = 1; - const size_t stars_tasks_per_cell = 15; - - if (e->policy & engine_policy_hydro) - e->size_links += s->tot_cells * hydro_tasks_per_cell; - if (e->policy & engine_policy_external_gravity) - e->size_links += s->tot_cells * ext_grav_tasks_per_cell; - if (e->policy & engine_policy_self_gravity) - e->size_links += s->tot_cells * self_grav_tasks_per_cell; - if (e->policy & engine_policy_stars) - e->size_links += s->tot_cells * stars_tasks_per_cell; - - /* Allocate the new link list */ - if ((e->links = (struct link *)malloc(sizeof(struct link) * e->size_links)) == - NULL) - error("Failed to allocate cell-task links."); - e->nr_links = 0; - - tic2 = getticks(); - - /* Split the tasks. */ - scheduler_splittasks(sched); - - if (e->verbose) - message("Splitting tasks took %.3f %s.", - clocks_from_ticks(getticks() - tic2), clocks_getunit()); - -#ifdef SWIFT_DEBUG_CHECKS - /* Verify that we are not left with invalid tasks */ - for (int i = 0; i < e->sched.nr_tasks; ++i) { - const struct task *t = &e->sched.tasks[i]; - if (t->ci == NULL && t->cj != NULL && !t->skip) error("Invalid task"); - } -#endif - - tic2 = getticks(); - - /* Count the number of tasks associated with each cell and - store the density tasks in each cell, and make each sort - depend on the sorts of its progeny. */ - threadpool_map(&e->threadpool, engine_count_and_link_tasks_mapper, - sched->tasks, sched->nr_tasks, sizeof(struct task), 0, e); - - if (e->verbose) - message("Counting and linking tasks took %.3f %s.", - clocks_from_ticks(getticks() - tic2), clocks_getunit()); - - tic2 = getticks(); - - /* Re-set the tag counter. MPI tags are defined for top-level cells in - * cell_set_super_mapper. */ -#ifdef WITH_MPI - cell_next_tag = 0; -#endif - - /* Now that the self/pair tasks are at the right level, set the super - * pointers. */ - threadpool_map(&e->threadpool, cell_set_super_mapper, cells, nr_cells, - sizeof(struct cell), 0, e); - - if (e->verbose) - message("Setting super-pointers took %.3f %s.", - clocks_from_ticks(getticks() - tic2), clocks_getunit()); - - /* Append hierarchical tasks to each cell. */ - threadpool_map(&e->threadpool, engine_make_hierarchical_tasks_mapper, cells, - nr_cells, sizeof(struct cell), 0, e); - - tic2 = getticks(); - - /* Run through the tasks and make force tasks for each density task. - Each force task depends on the cell ghosts and unlocks the kick task - of its super-cell. */ - if (e->policy & engine_policy_hydro) - threadpool_map(&e->threadpool, engine_make_extra_hydroloop_tasks_mapper, - sched->tasks, sched->nr_tasks, sizeof(struct task), 0, e); - - if (e->verbose) - message("Making extra hydroloop tasks took %.3f %s.", - clocks_from_ticks(getticks() - tic2), clocks_getunit()); - - tic2 = getticks(); - - /* Add the dependencies for the gravity stuff */ - if (e->policy & (engine_policy_self_gravity | engine_policy_external_gravity)) - engine_link_gravity_tasks(e); - - if (e->verbose) - message("Linking gravity tasks took %.3f %s.", - clocks_from_ticks(getticks() - tic2), clocks_getunit()); - - tic2 = getticks(); - - if (e->policy & engine_policy_stars) - threadpool_map(&e->threadpool, engine_link_stars_tasks_mapper, sched->tasks, - sched->nr_tasks, sizeof(struct task), 0, e); - - if (e->verbose) - message("Linking stars tasks took %.3f %s (including reweight).", - clocks_from_ticks(getticks() - tic2), clocks_getunit()); - -#ifdef WITH_MPI - if (e->policy & engine_policy_feedback) - error("Cannot run stellar feedback with MPI (yet)."); - - /* Add the communication tasks if MPI is being used. */ - if (e->policy & engine_policy_mpi) { - - tic2 = getticks(); - - /* Loop over the proxies and add the send tasks, which also generates the - * cell tags for super-cells. */ - for (int pid = 0; pid < e->nr_proxies; pid++) { - - /* Get a handle on the proxy. */ - struct proxy *p = &e->proxies[pid]; - - for (int k = 0; k < p->nr_cells_out; k++) - engine_addtasks_send_timestep(e, p->cells_out[k], p->cells_in[0], NULL); - - /* Loop through the proxy's outgoing cells and add the - send tasks for the cells in the proxy that have a hydro connection. */ - if (e->policy & engine_policy_hydro) - for (int k = 0; k < p->nr_cells_out; k++) - if (p->cells_out_type[k] & proxy_cell_type_hydro) - engine_addtasks_send_hydro(e, p->cells_out[k], p->cells_in[0], NULL, - NULL, NULL); - - /* Loop through the proxy's outgoing cells and add the - send tasks for the cells in the proxy that have a gravity connection. - */ - if (e->policy & engine_policy_self_gravity) - for (int k = 0; k < p->nr_cells_out; k++) - if (p->cells_out_type[k] & proxy_cell_type_gravity) - engine_addtasks_send_gravity(e, p->cells_out[k], p->cells_in[0], - NULL); - } - - if (e->verbose) - message("Creating send tasks took %.3f %s.", - clocks_from_ticks(getticks() - tic2), clocks_getunit()); - - tic2 = getticks(); - - /* Exchange the cell tags. */ - proxy_tags_exchange(e->proxies, e->nr_proxies, s); - - if (e->verbose) - message("Exchanging cell tags took %.3f %s.", - clocks_from_ticks(getticks() - tic2), clocks_getunit()); - - tic2 = getticks(); - - /* Loop over the proxies and add the recv tasks, which relies on having the - * cell tags. */ - for (int pid = 0; pid < e->nr_proxies; pid++) { - - /* Get a handle on the proxy. */ - struct proxy *p = &e->proxies[pid]; - - for (int k = 0; k < p->nr_cells_in; k++) - engine_addtasks_recv_timestep(e, p->cells_in[k], NULL); - - /* Loop through the proxy's incoming cells and add the - recv tasks for the cells in the proxy that have a hydro connection. */ - if (e->policy & engine_policy_hydro) - for (int k = 0; k < p->nr_cells_in; k++) - if (p->cells_in_type[k] & proxy_cell_type_hydro) - engine_addtasks_recv_hydro(e, p->cells_in[k], NULL, NULL, NULL); - - /* Loop through the proxy's incoming cells and add the - recv tasks for the cells in the proxy that have a gravity connection. - */ - if (e->policy & engine_policy_self_gravity) - for (int k = 0; k < p->nr_cells_in; k++) - if (p->cells_in_type[k] & proxy_cell_type_gravity) - engine_addtasks_recv_gravity(e, p->cells_in[k], NULL); - } - - if (e->verbose) - message("Creating recv tasks took %.3f %s.", - clocks_from_ticks(getticks() - tic2), clocks_getunit()); - } -#endif - - tic2 = getticks(); - - /* Set the unlocks per task. */ - scheduler_set_unlocks(sched); - - if (e->verbose) - message("Setting unlocks took %.3f %s.", - clocks_from_ticks(getticks() - tic2), clocks_getunit()); - - tic2 = getticks(); - - /* Rank the tasks. */ - scheduler_ranktasks(sched); - - if (e->verbose) - message("Ranking the tasks took %.3f %s.", - clocks_from_ticks(getticks() - tic2), clocks_getunit()); - - /* Weight the tasks. */ - scheduler_reweight(sched, e->verbose); - - /* Set the tasks age. */ - e->tasks_age = 0; - - if (e->verbose) - message("took %.3f %s (including reweight).", - clocks_from_ticks(getticks() - tic), clocks_getunit()); -} - -/** - * @brief Mark tasks to be un-skipped and set the sort flags accordingly. - * Threadpool mapper function. - * - * @param map_data pointer to the tasks - * @param num_elements number of tasks - * @param extra_data pointer to int that will define if a rebuild is needed. - */ -void engine_marktasks_mapper(void *map_data, int num_elements, - void *extra_data) { - /* Unpack the arguments. */ - struct task *tasks = (struct task *)map_data; - size_t *rebuild_space = &((size_t *)extra_data)[1]; - struct scheduler *s = (struct scheduler *)(((size_t *)extra_data)[2]); - struct engine *e = (struct engine *)((size_t *)extra_data)[0]; - const int nodeID = e->nodeID; - - for (int ind = 0; ind < num_elements; ind++) { - - /* Get basic task information */ - struct task *t = &tasks[ind]; - const enum task_types t_type = t->type; - const enum task_subtypes t_subtype = t->subtype; - - /* Single-cell task? */ - if (t_type == task_type_self || t_type == task_type_sub_self) { - - /* Local pointer. */ - struct cell *ci = t->ci; - - if (ci->nodeID != engine_rank) error("Non-local self task found"); - - /* Activate the hydro drift */ - if (t_type == task_type_self && t_subtype == task_subtype_density) { - if (cell_is_active_hydro(ci, e)) { - scheduler_activate(s, t); - cell_activate_drift_part(ci, s); - } - } - - /* Store current values of dx_max and h_max. */ - else if (t_type == task_type_sub_self && - t_subtype == task_subtype_density) { - if (cell_is_active_hydro(ci, e)) { - scheduler_activate(s, t); - cell_activate_subcell_hydro_tasks(ci, NULL, s); - } - } - - else if (t_type == task_type_self && t_subtype == task_subtype_force) { - if (cell_is_active_hydro(ci, e)) scheduler_activate(s, t); - } - - else if (t_type == task_type_sub_self && - t_subtype == task_subtype_force) { - if (cell_is_active_hydro(ci, e)) scheduler_activate(s, t); - } - -#ifdef EXTRA_HYDRO_LOOP - else if (t_type == task_type_self && t_subtype == task_subtype_gradient) { - if (cell_is_active_hydro(ci, e)) scheduler_activate(s, t); - } - - else if (t_type == task_type_sub_self && - t_subtype == task_subtype_gradient) { - if (cell_is_active_hydro(ci, e)) scheduler_activate(s, t); - } -#endif - - /* Activate the star density */ - else if (t_type == task_type_self && - t_subtype == task_subtype_stars_density) { - if (cell_is_active_stars(ci, e)) { - scheduler_activate(s, t); - cell_activate_drift_part(ci, s); - cell_activate_drift_gpart(ci, s); - } - } - - /* Store current values of dx_max and h_max. */ - else if (t_type == task_type_sub_self && - t_subtype == task_subtype_stars_density) { - if (cell_is_active_stars(ci, e)) { - scheduler_activate(s, t); - cell_activate_subcell_stars_tasks(ci, NULL, s); - } - } - - /* Activate the gravity drift */ - else if (t_type == task_type_self && t_subtype == task_subtype_grav) { - if (cell_is_active_gravity(ci, e)) { - scheduler_activate(s, t); - cell_activate_subcell_grav_tasks(t->ci, NULL, s); - } - } - - /* Activate the gravity drift */ - else if (t_type == task_type_self && - t_subtype == task_subtype_external_grav) { - if (cell_is_active_gravity(ci, e)) { - scheduler_activate(s, t); - cell_activate_drift_gpart(t->ci, s); - } - } - -#ifdef SWIFT_DEBUG_CHECKS - else { - error("Invalid task type / sub-type encountered"); - } -#endif - } - - /* Pair? */ - else if (t_type == task_type_pair || t_type == task_type_sub_pair) { - - /* Local pointers. */ - struct cell *ci = t->ci; - struct cell *cj = t->cj; -#ifdef WITH_MPI - const int ci_nodeID = ci->nodeID; - const int cj_nodeID = cj->nodeID; -#else - const int ci_nodeID = nodeID; - const int cj_nodeID = nodeID; -#endif - const int ci_active_hydro = cell_is_active_hydro(ci, e); - const int cj_active_hydro = cell_is_active_hydro(cj, e); - const int ci_active_gravity = cell_is_active_gravity(ci, e); - const int cj_active_gravity = cell_is_active_gravity(cj, e); - const int ci_active_stars = cell_is_active_stars(ci, e); - const int cj_active_stars = cell_is_active_stars(cj, e); - - /* Only activate tasks that involve a local active cell. */ - if ((t_subtype == task_subtype_density || - t_subtype == task_subtype_gradient || - t_subtype == task_subtype_force) && - ((ci_active_hydro && ci_nodeID == nodeID) || - (cj_active_hydro && cj_nodeID == nodeID))) { - - scheduler_activate(s, t); - - /* Set the correct sorting flags */ - if (t_type == task_type_pair && - (t_subtype == task_subtype_density || - t_subtype == task_subtype_stars_density)) { - - /* Store some values. */ - atomic_or(&ci->requires_sorts, 1 << t->flags); - atomic_or(&cj->requires_sorts, 1 << t->flags); - ci->dx_max_sort_old = ci->dx_max_sort; - cj->dx_max_sort_old = cj->dx_max_sort; - - /* Activate the hydro drift tasks. */ - if (ci_nodeID == nodeID) cell_activate_drift_part(ci, s); - if (cj_nodeID == nodeID) cell_activate_drift_part(cj, s); - - /* Check the sorts and activate them if needed. */ - cell_activate_sorts(ci, t->flags, s); - cell_activate_sorts(cj, t->flags, s); - - } - - /* Store current values of dx_max and h_max. */ - else if (t_type == task_type_sub_pair && - (t_subtype == task_subtype_density || - t_subtype == task_subtype_stars_density)) { - cell_activate_subcell_hydro_tasks(t->ci, t->cj, s); - } - } - - /* Stars */ - if (t_subtype == task_subtype_stars_density && - ((ci_active_stars && ci->nodeID == engine_rank) || - (cj_active_stars && cj->nodeID == engine_rank))) { - - scheduler_activate(s, t); - - /* Set the correct sorting flags */ - if (t_type == task_type_pair) { - - /* Store some values. */ - atomic_or(&ci->requires_sorts, 1 << t->flags); - atomic_or(&cj->requires_sorts, 1 << t->flags); - ci->dx_max_sort_old = ci->dx_max_sort; - cj->dx_max_sort_old = cj->dx_max_sort; - - /* Activate the hydro drift tasks. */ - if (ci_nodeID == nodeID) { - cell_activate_drift_part(ci, s); - cell_activate_drift_gpart(ci, s); - } - if (cj_nodeID == nodeID) { - cell_activate_drift_part(cj, s); - cell_activate_drift_gpart(cj, s); - } - - /* Check the sorts and activate them if needed. */ - cell_activate_sorts(ci, t->flags, s); - cell_activate_sorts(cj, t->flags, s); - - } - - /* Store current values of dx_max and h_max. */ - else if (t_type == task_type_sub_pair) { - cell_activate_subcell_stars_tasks(t->ci, t->cj, s); - } - } - - if ((t_subtype == task_subtype_grav) && - ((ci_active_gravity && ci_nodeID == nodeID) || - (cj_active_gravity && cj_nodeID == nodeID))) { - - scheduler_activate(s, t); - - if (t_type == task_type_pair && t_subtype == task_subtype_grav) { - /* Activate the gravity drift */ - cell_activate_subcell_grav_tasks(t->ci, t->cj, s); - } - -#ifdef SWIFT_DEBUG_CHECKS - else if (t_type == task_type_sub_pair && - t_subtype == task_subtype_grav) { - error("Invalid task sub-type encountered"); - } -#endif - } - - /* Only interested in density tasks as of here. */ - if (t_subtype == task_subtype_density) { - - /* Too much particle movement? */ - if (cell_need_rebuild_for_pair(ci, cj)) *rebuild_space = 1; - -#ifdef WITH_MPI - /* Activate the send/recv tasks. */ - if (ci_nodeID != nodeID) { - - /* If the local cell is active, receive data from the foreign cell. */ - if (cj_active_hydro) { - scheduler_activate(s, ci->recv_xv); - if (ci_active_hydro) { - scheduler_activate(s, ci->recv_rho); -#ifdef EXTRA_HYDRO_LOOP - scheduler_activate(s, ci->recv_gradient); -#endif - } - } - - /* If the foreign cell is active, we want its ti_end values. */ - if (ci_active_hydro) scheduler_activate(s, ci->recv_ti); - - /* Is the foreign cell active and will need stuff from us? */ - if (ci_active_hydro) { - - struct link *l = scheduler_activate_send(s, cj->send_xv, ci_nodeID); - - /* Drift the cell which will be sent at the level at which it is - sent, i.e. drift the cell specified in the send task (l->t) - itself. */ - cell_activate_drift_part(l->t->ci, s); - - /* If the local cell is also active, more stuff will be needed. */ - if (cj_active_hydro) { - scheduler_activate_send(s, cj->send_rho, ci_nodeID); - -#ifdef EXTRA_HYDRO_LOOP - scheduler_activate_send(s, cj->send_gradient, ci_nodeID); -#endif - } - } - - /* If the local cell is active, send its ti_end values. */ - if (cj_active_hydro) - scheduler_activate_send(s, cj->send_ti, ci_nodeID); - - } else if (cj_nodeID != nodeID) { - - /* If the local cell is active, receive data from the foreign cell. */ - if (ci_active_hydro) { - scheduler_activate(s, cj->recv_xv); - if (cj_active_hydro) { - scheduler_activate(s, cj->recv_rho); -#ifdef EXTRA_HYDRO_LOOP - scheduler_activate(s, cj->recv_gradient); -#endif - } - } - - /* If the foreign cell is active, we want its ti_end values. */ - if (cj_active_hydro) scheduler_activate(s, cj->recv_ti); - - /* Is the foreign cell active and will need stuff from us? */ - if (cj_active_hydro) { - - struct link *l = scheduler_activate_send(s, ci->send_xv, cj_nodeID); - - /* Drift the cell which will be sent at the level at which it is - sent, i.e. drift the cell specified in the send task (l->t) - itself. */ - cell_activate_drift_part(l->t->ci, s); - - /* If the local cell is also active, more stuff will be needed. */ - if (ci_active_hydro) { - - scheduler_activate_send(s, ci->send_rho, cj_nodeID); - -#ifdef EXTRA_HYDRO_LOOP - scheduler_activate_send(s, ci->send_gradient, cj_nodeID); -#endif - } - } - - /* If the local cell is active, send its ti_end values. */ - if (ci_active_hydro) - scheduler_activate_send(s, ci->send_ti, cj_nodeID); - } -#endif - } + int count_recv_cells = 0; + int count_send_requests = 0; + int count_recv_requests = 0; - /* Only interested in stars_density tasks as of here. */ - if (t->subtype == task_subtype_stars_density) { + /* Loop over the proxies. */ + for (int pid = 0; pid < e->nr_proxies; pid++) { - /* Too much particle movement? */ - if (cell_need_rebuild_for_pair(ci, cj)) *rebuild_space = 1; + /* Get a handle on the proxy. */ + const struct proxy *p = &e->proxies[pid]; - // LOIC: Need implementing MPI case - } + /* Now collect the number of requests associated */ + count_recv_requests += p->nr_cells_in; + count_send_requests += p->nr_cells_out; - /* Only interested in gravity tasks as of here. */ - if (t_subtype == task_subtype_grav) { + /* And the actual number of things we are going to ship */ + for (int k = 0; k < p->nr_cells_in; k++) + count_recv_cells += p->cells_in[k]->mpi.pcell_size; -#ifdef WITH_MPI - /* Activate the send/recv tasks. */ - if (ci_nodeID != nodeID) { + for (int k = 0; k < p->nr_cells_out; k++) + count_send_cells += p->cells_out[k]->mpi.pcell_size; + } - /* If the local cell is active, receive data from the foreign cell. */ - if (cj_active_gravity) scheduler_activate(s, ci->recv_grav); + /* Allocate the buffers for the packed data */ + struct gravity_tensors *buffer_send = NULL; + if (posix_memalign((void **)&buffer_send, SWIFT_CACHE_ALIGNMENT, + count_send_cells * sizeof(struct gravity_tensors)) != 0) + error("Unable to allocate memory for multipole transactions"); - /* If the foreign cell is active, we want its ti_end values. */ - if (ci_active_gravity) scheduler_activate(s, ci->recv_ti); + struct gravity_tensors *buffer_recv = NULL; + if (posix_memalign((void **)&buffer_recv, SWIFT_CACHE_ALIGNMENT, + count_recv_cells * sizeof(struct gravity_tensors)) != 0) + error("Unable to allocate memory for multipole transactions"); - /* Is the foreign cell active and will need stuff from us? */ - if (ci_active_gravity) { + /* Also allocate the MPI requests */ + const int count_requests = count_send_requests + count_recv_requests; + MPI_Request *requests = + (MPI_Request *)malloc(sizeof(MPI_Request) * count_requests); + if (requests == NULL) error("Unable to allocate memory for MPI requests"); - struct link *l = - scheduler_activate_send(s, cj->send_grav, ci_nodeID); + int this_request = 0; + int this_recv = 0; + int this_send = 0; - /* Drift the cell which will be sent at the level at which it is - sent, i.e. drift the cell specified in the send task (l->t) - itself. */ - cell_activate_drift_gpart(l->t->ci, s); - } + /* Loop over the proxies to issue the receives. */ + for (int pid = 0; pid < e->nr_proxies; pid++) { - /* If the local cell is active, send its ti_end values. */ - if (cj_active_gravity) - scheduler_activate_send(s, cj->send_ti, ci_nodeID); + /* Get a handle on the proxy. */ + const struct proxy *p = &e->proxies[pid]; - } else if (cj_nodeID != nodeID) { + for (int k = 0; k < p->nr_cells_in; k++) { - /* If the local cell is active, receive data from the foreign cell. */ - if (ci_active_gravity) scheduler_activate(s, cj->recv_grav); + const int num_elements = p->cells_in[k]->mpi.pcell_size; - /* If the foreign cell is active, we want its ti_end values. */ - if (cj_active_gravity) scheduler_activate(s, cj->recv_ti); + /* Receive everything */ + MPI_Irecv(&buffer_recv[this_recv], num_elements, multipole_mpi_type, + p->cells_in[k]->nodeID, p->cells_in[k]->mpi.tag, MPI_COMM_WORLD, + &requests[this_request]); - /* Is the foreign cell active and will need stuff from us? */ - if (cj_active_gravity) { + /* Move to the next slot in the buffers */ + this_recv += num_elements; + this_request++; + } - struct link *l = - scheduler_activate_send(s, ci->send_grav, cj_nodeID); + /* Loop over the proxies to issue the sends. */ + for (int k = 0; k < p->nr_cells_out; k++) { - /* Drift the cell which will be sent at the level at which it is - sent, i.e. drift the cell specified in the send task (l->t) - itself. */ - cell_activate_drift_gpart(l->t->ci, s); - } + /* Number of multipoles in this cell hierarchy */ + const int num_elements = p->cells_out[k]->mpi.pcell_size; - /* If the local cell is active, send its ti_end values. */ - if (ci_active_gravity) - scheduler_activate_send(s, ci->send_ti, cj_nodeID); - } -#endif - } - } + /* Let's pack everything recursively */ + cell_pack_multipoles(p->cells_out[k], &buffer_send[this_send]); - /* End force ? */ - else if (t_type == task_type_end_force) { + /* Send everything (note the use of cells_in[0] to get the correct node + * ID. */ + MPI_Isend(&buffer_send[this_send], num_elements, multipole_mpi_type, + p->cells_in[0]->nodeID, p->cells_out[k]->mpi.tag, + MPI_COMM_WORLD, &requests[this_request]); - if (cell_is_active_hydro(t->ci, e) || cell_is_active_gravity(t->ci, e)) - scheduler_activate(s, t); + /* Move to the next slot in the buffers */ + this_send += num_elements; + this_request++; } + } - /* Kick ? */ - else if (t_type == task_type_kick1 || t_type == task_type_kick2) { - - if (cell_is_active_hydro(t->ci, e) || cell_is_active_gravity(t->ci, e)) - scheduler_activate(s, t); + /* Wait for all the requests to arrive home */ + MPI_Status *stats = (MPI_Status *)malloc(count_requests * sizeof(MPI_Status)); + int res; + if ((res = MPI_Waitall(count_requests, requests, stats)) != MPI_SUCCESS) { + for (int k = 0; k < count_requests; ++k) { + char buff[MPI_MAX_ERROR_STRING]; + MPI_Error_string(stats[k].MPI_ERROR, buff, &res); + message("request from source %i, tag %i has error '%s'.", + stats[k].MPI_SOURCE, stats[k].MPI_TAG, buff); } + error("Failed during waitall for multipole data."); + } - /* Hydro ghost tasks ? */ - else if (t_type == task_type_ghost || t_type == task_type_extra_ghost || - t_type == task_type_ghost_in || t_type == task_type_ghost_out) { - if (cell_is_active_hydro(t->ci, e)) scheduler_activate(s, t); - } + /* Let's now unpack the multipoles at the right place */ + this_recv = 0; + for (int pid = 0; pid < e->nr_proxies; pid++) { - /* Gravity stuff ? */ - else if (t_type == task_type_grav_down || t_type == task_type_grav_mesh || - t_type == task_type_grav_long_range || - t_type == task_type_init_grav || - t_type == task_type_init_grav_out || - t_type == task_type_grav_down_in) { - if (cell_is_active_gravity(t->ci, e)) scheduler_activate(s, t); - } + /* Get a handle on the proxy. */ + const struct proxy *p = &e->proxies[pid]; - /* Multipole - Multipole interaction task */ - else if (t_type == task_type_grav_mm) { + for (int k = 0; k < p->nr_cells_in; k++) { - /* Local pointers. */ - const struct cell *ci = t->ci; - const struct cell *cj = t->cj; -#ifdef WITH_MPI - const int ci_nodeID = ci->nodeID; - const int cj_nodeID = (cj != NULL) ? cj->nodeID : -1; -#else - const int ci_nodeID = nodeID; - const int cj_nodeID = nodeID; -#endif - const int ci_active_gravity = cell_is_active_gravity_mm(ci, e); - const int cj_active_gravity = cell_is_active_gravity_mm(cj, e); + const int num_elements = p->cells_in[k]->mpi.pcell_size; - if ((ci_active_gravity && ci_nodeID == nodeID) || - (cj_active_gravity && cj_nodeID == nodeID)) - scheduler_activate(s, t); - } +#ifdef SWIFT_DEBUG_CHECKS - /* Star ghost tasks ? */ - else if (t_type == task_type_stars_ghost || - t_type == task_type_stars_ghost_in || - t_type == task_type_stars_ghost_out) { - if (cell_is_active_stars(t->ci, e)) scheduler_activate(s, t); - } + /* Check that the first element (top-level cell's multipole) matches what + * we received */ + if (p->cells_in[k]->grav.multipole->m_pole.num_gpart != + buffer_recv[this_recv].m_pole.num_gpart) + error("Current: M_000=%e num_gpart=%lld\n New: M_000=%e num_gpart=%lld", + p->cells_in[k]->grav.multipole->m_pole.M_000, + p->cells_in[k]->grav.multipole->m_pole.num_gpart, + buffer_recv[this_recv].m_pole.M_000, + buffer_recv[this_recv].m_pole.num_gpart); +#endif - /* Time-step? */ - else if (t_type == task_type_timestep) { - t->ci->updated = 0; - t->ci->g_updated = 0; - t->ci->s_updated = 0; - if (cell_is_active_hydro(t->ci, e) || cell_is_active_gravity(t->ci, e)) - scheduler_activate(s, t); - } + /* Unpack recursively */ + cell_unpack_multipoles(p->cells_in[k], &buffer_recv[this_recv]); - /* Subgrid tasks */ - else if (t_type == task_type_cooling) { - if (cell_is_active_hydro(t->ci, e) || cell_is_active_gravity(t->ci, e)) - scheduler_activate(s, t); + /* Move to the next slot in the buffers */ + this_recv += num_elements; } } -} - -/** - * @brief Mark tasks to be un-skipped and set the sort flags accordingly. - * - * @return 1 if the space has to be rebuilt, 0 otherwise. - */ -int engine_marktasks(struct engine *e) { - - struct scheduler *s = &e->sched; - const ticks tic = getticks(); - int rebuild_space = 0; - /* Run through the tasks and mark as skip or not. */ - size_t extra_data[3] = {(size_t)e, (size_t)rebuild_space, (size_t)&e->sched}; - threadpool_map(&e->threadpool, engine_marktasks_mapper, s->tasks, s->nr_tasks, - sizeof(struct task), 0, extra_data); - rebuild_space = extra_data[1]; + /* Free everything */ + free(stats); + free(buffer_send); + free(buffer_recv); + free(requests); + /* How much time did this take? */ if (e->verbose) message("took %.3f %s.", clocks_from_ticks(getticks() - tic), clocks_getunit()); - - /* All is well... */ - return rebuild_space; +#else + error("SWIFT was not compiled with MPI support."); +#endif } /** @@ -4297,6 +1916,9 @@ int engine_estimate_nr_tasks(struct engine *e) { if (e->policy & engine_policy_stars) { n1 += 2; } +#if defined(WITH_LOGGER) + n1 += 1; +#endif #ifdef WITH_MPI @@ -4310,7 +1932,7 @@ int engine_estimate_nr_tasks(struct engine *e) { struct cell *c = &e->s->cells_top[k]; /* Any cells with particles will have tasks (local & foreign). */ - int nparts = c->count + c->gcount + c->scount; + int nparts = c->hydro.count + c->grav.count + c->stars.count; if (nparts > 0) { ntop++; ncells++; @@ -4351,10 +1973,12 @@ int engine_estimate_nr_tasks(struct engine *e) { * @brief Rebuild the space and tasks. * * @param e The #engine. + * @param repartitioned Did we just redistribute? * @param clean_smoothing_length_values Are we cleaning up the values of * the smoothing lengths before building the tasks ? */ -void engine_rebuild(struct engine *e, int clean_smoothing_length_values) { +void engine_rebuild(struct engine *e, int repartitioned, + int clean_smoothing_length_values) { const ticks tic = getticks(); @@ -4363,10 +1987,23 @@ void engine_rebuild(struct engine *e, int clean_smoothing_length_values) { e->restarting = 0; /* Re-build the space. */ - space_rebuild(e->s, e->verbose); + space_rebuild(e->s, repartitioned, e->verbose); - /* Construct the list of purely local cells */ - space_list_local_cells(e->s); + /* Update the global counters of particles */ + long long num_particles[3] = {e->s->nr_parts, e->s->nr_gparts, + e->s->nr_sparts}; +#ifdef WITH_MPI + MPI_Allreduce(MPI_IN_PLACE, num_particles, 3, MPI_LONG_LONG, MPI_SUM, + MPI_COMM_WORLD); +#endif + e->total_nr_parts = num_particles[0]; + e->total_nr_gparts = num_particles[1]; + e->total_nr_sparts = num_particles[2]; + + /* Flag that there are no inhibited particles */ + e->nr_inhibited_parts = 0; + e->nr_inhibited_gparts = 0; + e->nr_inhibited_sparts = 0; /* Re-compute the mesh forces */ if ((e->policy & engine_policy_self_gravity) && e->s->periodic) @@ -4411,7 +2048,7 @@ void engine_rebuild(struct engine *e, int clean_smoothing_length_values) { engine_maketasks(e); /* Make the list of top-level cells that have tasks */ - space_list_cells_with_tasks(e->s); + space_list_useful_top_level_cells(e->s); #ifdef SWIFT_DEBUG_CHECKS /* Check that all cells have been drifted to the current time. @@ -4457,15 +2094,22 @@ void engine_prepare(struct engine *e) { const ticks tic = getticks(); int drifted_all = 0; + int repartitioned = 0; /* Unskip active tasks and check for rebuild */ if (!e->forcerebuild && !e->forcerepart && !e->restarting) engine_unskip(e); + const ticks tic2 = getticks(); + #ifdef WITH_MPI MPI_Allreduce(MPI_IN_PLACE, &e->forcerebuild, 1, MPI_INT, MPI_MAX, MPI_COMM_WORLD); #endif + if (e->verbose) + message("Communicating rebuild flag took %.3f %s.", + clocks_from_ticks(getticks() - tic2), clocks_getunit()); + /* Do we need repartitioning ? */ if (e->forcerepart) { @@ -4475,6 +2119,7 @@ void engine_prepare(struct engine *e) { /* And repartition */ engine_repartition(e); + repartitioned = 1; } /* Do we need rebuilding ? */ @@ -4484,7 +2129,7 @@ void engine_prepare(struct engine *e) { if (!e->restarting && !drifted_all) engine_drift_all(e); /* And rebuild */ - engine_rebuild(e, 0); + engine_rebuild(e, repartitioned, 0); } #ifdef SWIFT_DEBUG_CHECKS @@ -4540,13 +2185,14 @@ void engine_collect_end_of_step_recurse(struct cell *c, /* Skip super-cells (Their values are already set) */ #ifdef WITH_MPI - if (c->timestep != NULL || c->recv_ti != NULL) return; + if (c->timestep != NULL || c->mpi.recv_ti != NULL) return; #else if (c->timestep != NULL) return; #endif /* WITH_MPI */ /* Counters for the different quantities. */ size_t updated = 0, g_updated = 0, s_updated = 0; + size_t inhibited = 0, g_inhibited = 0, s_inhibited = 0; integertime_t ti_hydro_end_min = max_nr_timesteps, ti_hydro_end_max = 0, ti_hydro_beg_max = 0; integertime_t ti_gravity_end_min = max_nr_timesteps, ti_gravity_end_max = 0, @@ -4555,41 +2201,49 @@ void engine_collect_end_of_step_recurse(struct cell *c, /* Collect the values from the progeny. */ for (int k = 0; k < 8; k++) { struct cell *cp = c->progeny[k]; - if (cp != NULL && (cp->count > 0 || cp->gcount > 0 || cp->scount > 0)) { + if (cp != NULL && + (cp->hydro.count > 0 || cp->grav.count > 0 || cp->stars.count > 0)) { /* Recurse */ engine_collect_end_of_step_recurse(cp, e); /* And update */ - ti_hydro_end_min = min(ti_hydro_end_min, cp->ti_hydro_end_min); - ti_hydro_end_max = max(ti_hydro_end_max, cp->ti_hydro_end_max); - ti_hydro_beg_max = max(ti_hydro_beg_max, cp->ti_hydro_beg_max); + ti_hydro_end_min = min(ti_hydro_end_min, cp->hydro.ti_end_min); + ti_hydro_end_max = max(ti_hydro_end_max, cp->hydro.ti_end_max); + ti_hydro_beg_max = max(ti_hydro_beg_max, cp->hydro.ti_beg_max); - ti_gravity_end_min = min(ti_gravity_end_min, cp->ti_gravity_end_min); - ti_gravity_end_max = max(ti_gravity_end_max, cp->ti_gravity_end_max); - ti_gravity_beg_max = max(ti_gravity_beg_max, cp->ti_gravity_beg_max); + ti_gravity_end_min = min(ti_gravity_end_min, cp->grav.ti_end_min); + ti_gravity_end_max = max(ti_gravity_end_max, cp->grav.ti_end_max); + ti_gravity_beg_max = max(ti_gravity_beg_max, cp->grav.ti_beg_max); - updated += cp->updated; - g_updated += cp->g_updated; - s_updated += cp->s_updated; + updated += cp->hydro.updated; + g_updated += cp->grav.updated; + s_updated += cp->stars.updated; + + inhibited += cp->hydro.inhibited; + g_inhibited += cp->grav.inhibited; + s_inhibited += cp->stars.inhibited; /* Collected, so clear for next time. */ - cp->updated = 0; - cp->g_updated = 0; - cp->s_updated = 0; + cp->hydro.updated = 0; + cp->grav.updated = 0; + cp->stars.updated = 0; } } /* Store the collected values in the cell. */ - c->ti_hydro_end_min = ti_hydro_end_min; - c->ti_hydro_end_max = ti_hydro_end_max; - c->ti_hydro_beg_max = ti_hydro_beg_max; - c->ti_gravity_end_min = ti_gravity_end_min; - c->ti_gravity_end_max = ti_gravity_end_max; - c->ti_gravity_beg_max = ti_gravity_beg_max; - c->updated = updated; - c->g_updated = g_updated; - c->s_updated = s_updated; + c->hydro.ti_end_min = ti_hydro_end_min; + c->hydro.ti_end_max = ti_hydro_end_max; + c->hydro.ti_beg_max = ti_hydro_beg_max; + c->grav.ti_end_min = ti_gravity_end_min; + c->grav.ti_end_max = ti_gravity_end_max; + c->grav.ti_beg_max = ti_gravity_beg_max; + c->hydro.updated = updated; + c->grav.updated = g_updated; + c->stars.updated = s_updated; + c->hydro.inhibited = inhibited; + c->grav.inhibited = g_inhibited; + c->stars.inhibited = s_inhibited; } /** @@ -4612,7 +2266,8 @@ void engine_collect_end_of_step_mapper(void *map_data, int num_elements, int *local_cells = (int *)map_data; /* Local collectible */ - size_t updates = 0, g_updates = 0, s_updates = 0; + size_t updated = 0, g_updated = 0, s_updated = 0; + size_t inhibited = 0, g_inhibited = 0, s_inhibited = 0; integertime_t ti_hydro_end_min = max_nr_timesteps, ti_hydro_end_max = 0, ti_hydro_beg_max = 0; integertime_t ti_gravity_end_min = max_nr_timesteps, ti_gravity_end_max = 0, @@ -4621,39 +2276,47 @@ void engine_collect_end_of_step_mapper(void *map_data, int num_elements, for (int ind = 0; ind < num_elements; ind++) { struct cell *c = &s->cells_top[local_cells[ind]]; - if (c->count > 0 || c->gcount > 0 || c->scount > 0) { + if (c->hydro.count > 0 || c->grav.count > 0 || c->stars.count > 0) { /* Make the top-cells recurse */ engine_collect_end_of_step_recurse(c, e); /* And aggregate */ - if (c->ti_hydro_end_min > e->ti_current) - ti_hydro_end_min = min(ti_hydro_end_min, c->ti_hydro_end_min); - ti_hydro_end_max = max(ti_hydro_end_max, c->ti_hydro_end_max); - ti_hydro_beg_max = max(ti_hydro_beg_max, c->ti_hydro_beg_max); + if (c->hydro.ti_end_min > e->ti_current) + ti_hydro_end_min = min(ti_hydro_end_min, c->hydro.ti_end_min); + ti_hydro_end_max = max(ti_hydro_end_max, c->hydro.ti_end_max); + ti_hydro_beg_max = max(ti_hydro_beg_max, c->hydro.ti_beg_max); - if (c->ti_gravity_end_min > e->ti_current) - ti_gravity_end_min = min(ti_gravity_end_min, c->ti_gravity_end_min); - ti_gravity_end_max = max(ti_gravity_end_max, c->ti_gravity_end_max); - ti_gravity_beg_max = max(ti_gravity_beg_max, c->ti_gravity_beg_max); + if (c->grav.ti_end_min > e->ti_current) + ti_gravity_end_min = min(ti_gravity_end_min, c->grav.ti_end_min); + ti_gravity_end_max = max(ti_gravity_end_max, c->grav.ti_end_max); + ti_gravity_beg_max = max(ti_gravity_beg_max, c->grav.ti_beg_max); - updates += c->updated; - g_updates += c->g_updated; - s_updates += c->s_updated; + updated += c->hydro.updated; + g_updated += c->grav.updated; + s_updated += c->stars.updated; + + inhibited += c->hydro.inhibited; + g_inhibited += c->grav.inhibited; + s_inhibited += c->stars.inhibited; /* Collected, so clear for next time. */ - c->updated = 0; - c->g_updated = 0; - c->s_updated = 0; + c->hydro.updated = 0; + c->grav.updated = 0; + c->stars.updated = 0; } } /* Let's write back to the global data. * We use the space lock to garanty single access*/ if (lock_lock(&s->lock) == 0) { - data->updates += updates; - data->g_updates += g_updates; - data->s_updates += s_updates; + data->updated += updated; + data->g_updated += g_updated; + data->s_updated += s_updated; + + data->inhibited += inhibited; + data->g_inhibited += g_inhibited; + data->s_inhibited += s_inhibited; if (ti_hydro_end_min > e->ti_current) data->ti_hydro_end_min = min(ti_hydro_end_min, data->ti_hydro_end_min); @@ -4692,9 +2355,10 @@ void engine_collect_end_of_step_mapper(void *map_data, int num_elements, void engine_collect_end_of_step(struct engine *e, int apply) { const ticks tic = getticks(); - const struct space *s = e->s; + struct space *s = e->s; struct end_of_step_data data; - data.updates = 0, data.g_updates = 0, data.s_updates = 0; + data.updated = 0, data.g_updated = 0, data.s_updated = 0; + data.inhibited = 0, data.g_inhibited = 0, data.s_inhibited = 0; data.ti_hydro_end_min = max_nr_timesteps, data.ti_hydro_end_max = 0, data.ti_hydro_beg_max = 0; data.ti_gravity_end_min = max_nr_timesteps, data.ti_gravity_end_max = 0, @@ -4706,12 +2370,17 @@ void engine_collect_end_of_step(struct engine *e, int apply) { s->local_cells_with_tasks_top, s->nr_local_cells_with_tasks, sizeof(int), 0, &data); + /* Store the local number of inhibited particles */ + s->nr_inhibited_parts = data.inhibited; + s->nr_inhibited_gparts = data.g_inhibited; + s->nr_inhibited_sparts = data.s_inhibited; + /* Store these in the temporary collection group. */ - collectgroup1_init(&e->collect_group1, data.updates, data.g_updates, - data.s_updates, data.ti_hydro_end_min, - data.ti_hydro_end_max, data.ti_hydro_beg_max, - data.ti_gravity_end_min, data.ti_gravity_end_max, - data.ti_gravity_beg_max, e->forcerebuild); + collectgroup1_init( + &e->collect_group1, data.updated, data.g_updated, data.s_updated, + data.inhibited, data.g_inhibited, data.s_inhibited, data.ti_hydro_end_min, + data.ti_hydro_end_max, data.ti_hydro_beg_max, data.ti_gravity_end_min, + data.ti_gravity_end_max, data.ti_gravity_beg_max, e->forcerebuild); /* Aggregate collective data from the different nodes for this step. */ #ifdef WITH_MPI @@ -4736,21 +2405,37 @@ void engine_collect_end_of_step(struct engine *e, int apply) { in_i[1], e->collect_group1.ti_gravity_end_min); long long in_ll[3], out_ll[3]; - out_ll[0] = data.updates; - out_ll[1] = data.g_updates; - out_ll[2] = data.s_updates; + out_ll[0] = data.updated; + out_ll[1] = data.g_updated; + out_ll[2] = data.s_updated; + if (MPI_Allreduce(out_ll, in_ll, 3, MPI_LONG_LONG_INT, MPI_SUM, + MPI_COMM_WORLD) != MPI_SUCCESS) + error("Failed to aggregate particle counts."); + if (in_ll[0] != (long long)e->collect_group1.updated) + error("Failed to get same updated, is %lld, should be %lld", in_ll[0], + e->collect_group1.updated); + if (in_ll[1] != (long long)e->collect_group1.g_updated) + error("Failed to get same g_updated, is %lld, should be %lld", in_ll[1], + e->collect_group1.g_updated); + if (in_ll[2] != (long long)e->collect_group1.s_updated) + error("Failed to get same s_updated, is %lld, should be %lld", in_ll[2], + e->collect_group1.s_updated); + + out_ll[0] = data.inhibited; + out_ll[1] = data.g_inhibited; + out_ll[2] = data.s_inhibited; if (MPI_Allreduce(out_ll, in_ll, 3, MPI_LONG_LONG_INT, MPI_SUM, MPI_COMM_WORLD) != MPI_SUCCESS) error("Failed to aggregate particle counts."); - if (in_ll[0] != (long long)e->collect_group1.updates) - error("Failed to get same updates, is %lld, should be %lld", in_ll[0], - e->collect_group1.updates); - if (in_ll[1] != (long long)e->collect_group1.g_updates) - error("Failed to get same g_updates, is %lld, should be %lld", in_ll[1], - e->collect_group1.g_updates); - if (in_ll[2] != (long long)e->collect_group1.s_updates) - error("Failed to get same s_updates, is %lld, should be %lld", in_ll[2], - e->collect_group1.s_updates); + if (in_ll[0] != (long long)e->collect_group1.inhibited) + error("Failed to get same inhibited, is %lld, should be %lld", in_ll[0], + e->collect_group1.inhibited); + if (in_ll[1] != (long long)e->collect_group1.g_inhibited) + error("Failed to get same g_inhibited, is %lld, should be %lld", in_ll[1], + e->collect_group1.g_inhibited); + if (in_ll[2] != (long long)e->collect_group1.s_inhibited) + error("Failed to get same s_inhibited, is %lld, should be %lld", in_ll[2], + e->collect_group1.s_inhibited); int buff = 0; if (MPI_Allreduce(&e->forcerebuild, &buff, 1, MPI_INT, MPI_MAX, @@ -4979,7 +2664,7 @@ void engine_init_particles(struct engine *e, int flag_entropy_ICs, if (e->nodeID == 0) message("Computing initial gas densities."); /* Construct all cells and tasks to start everything */ - engine_rebuild(e, clean_h_values); + engine_rebuild(e, 0, clean_h_values); /* No time integration. We just want the density and ghosts */ engine_skip_force_and_kick(e); @@ -4992,6 +2677,15 @@ void engine_init_particles(struct engine *e, int flag_entropy_ICs, space_init_gparts(s, e->verbose); space_init_sparts(s, e->verbose); +#ifdef WITH_LOGGER + /* Mark the first time step in the particle logger file. */ + logger_log_timestamp(e->logger, e->ti_current, e->time, + &e->logger->timestamp_offset); + /* Make sure that we have enough space in the particle logger file + * to store the particles in current time step. */ + logger_ensure_size(e->logger, e->total_nr_parts, e->total_nr_gparts, 0); +#endif + /* Now, launch the calculation */ TIMER_TIC; engine_launch(e); @@ -5020,7 +2714,7 @@ void engine_init_particles(struct engine *e, int flag_entropy_ICs, long long num_gpart_mpole = 0; if (e->policy & engine_policy_self_gravity) { for (int i = 0; i < e->s->nr_cells; ++i) - num_gpart_mpole += e->s->cells_top[i].multipole->m_pole.num_gpart; + num_gpart_mpole += e->s->cells_top[i].grav.multipole->m_pole.num_gpart; if (num_gpart_mpole != e->total_nr_gparts) error( "Top-level multipoles don't contain the total number of gpart " @@ -5054,6 +2748,7 @@ void engine_init_particles(struct engine *e, int flag_entropy_ICs, #endif if (e->nodeID == 0) scheduler_write_dependencies(&e->sched, e->verbose); + if (e->nodeID == 0) scheduler_write_task_level(&e->sched); /* Run the 0th time-step */ TIMER_TIC2; @@ -5124,12 +2819,27 @@ void engine_init_particles(struct engine *e, int flag_entropy_ICs, if (s->cells_top != NULL && s->nr_parts > 0) { for (int i = 0; i < s->nr_cells; i++) { struct cell *c = &s->cells_top[i]; - if (c->nodeID == engine_rank && c->count > 0) { - float part_h_max = c->parts[0].h; - for (int k = 1; k < c->count; k++) { - if (c->parts[k].h > part_h_max) part_h_max = c->parts[k].h; + if (c->nodeID == engine_rank && c->hydro.count > 0) { + float part_h_max = c->hydro.parts[0].h; + for (int k = 1; k < c->hydro.count; k++) { + if (c->hydro.parts[k].h > part_h_max) + part_h_max = c->hydro.parts[k].h; + } + c->hydro.h_max = max(part_h_max, c->hydro.h_max); + } + } + } + + if (s->cells_top != NULL && s->nr_sparts > 0) { + for (int i = 0; i < s->nr_cells; i++) { + struct cell *c = &s->cells_top[i]; + if (c->nodeID == engine_rank && c->stars.count > 0) { + float spart_h_max = c->stars.parts[0].h; + for (int k = 1; k < c->stars.count; k++) { + if (c->stars.parts[k].h > spart_h_max) + spart_h_max = c->stars.parts[k].h; } - c->h_max = max(part_h_max, c->h_max); + c->stars.h_max = max(spart_h_max, c->stars.h_max); } } } @@ -5189,7 +2899,7 @@ void engine_step(struct engine *e) { } /* We need some cells to exist but not the whole task stuff. */ - if (e->restarting) space_rebuild(e->s, e->verbose); + if (e->restarting) space_rebuild(e->s, 0, e->verbose); /* Move forward in time */ e->ti_old = e->ti_current; @@ -5228,6 +2938,15 @@ void engine_step(struct engine *e) { ((double)e->total_nr_gparts) * e->gravity_properties->rebuild_frequency)) e->forcerebuild = 1; +#ifdef WITH_LOGGER + /* Mark the current time step in the particle logger file. */ + logger_log_timestamp(e->logger, e->ti_current, e->time, + &e->logger->timestamp_offset); + /* Make sure that we have enough space in the particle logger file + * to store the particles in current time step. */ + logger_ensure_size(e->logger, e->total_nr_parts, e->total_nr_gparts, 0); +#endif + /* Are we drifting everything (a la Gadget/GIZMO) ? */ if (e->policy & engine_policy_drift_all && !e->forcerebuild) engine_drift_all(e); @@ -5260,7 +2979,7 @@ void engine_step(struct engine *e) { long long num_gpart_mpole = 0; if (e->policy & engine_policy_self_gravity) { for (int i = 0; i < e->s->nr_cells; ++i) - num_gpart_mpole += e->s->cells_top[i].multipole->m_pole.num_gpart; + num_gpart_mpole += e->s->cells_top[i].grav.multipole->m_pole.num_gpart; if (num_gpart_mpole != e->total_nr_gparts) error( "Multipoles don't contain the total number of gpart mpoles=%lld " @@ -5289,9 +3008,9 @@ void engine_step(struct engine *e) { /* Collect information about the next time-step */ engine_collect_end_of_step(e, 1); e->forcerebuild = e->collect_group1.forcerebuild; - e->updates_since_rebuild += e->collect_group1.updates; - e->g_updates_since_rebuild += e->collect_group1.g_updates; - e->s_updates_since_rebuild += e->collect_group1.s_updates; + e->updates_since_rebuild += e->collect_group1.updated; + e->g_updates_since_rebuild += e->collect_group1.g_updated; + e->s_updates_since_rebuild += e->collect_group1.s_updated; #ifdef SWIFT_DEBUG_CHECKS if (e->ti_end_min == e->ti_current && e->ti_end_min < max_nr_timesteps) @@ -5329,6 +3048,9 @@ void engine_step(struct engine *e) { */ void engine_check_for_dumps(struct engine *e) { + const int with_stf = (e->policy & engine_policy_structure_finding); + const int stf_time_output = (e->stf_output_freq_format == io_stf_time); + /* Save some statistics ? */ int save_stats = 0; if (e->ti_end_min > e->ti_next_stats && e->ti_next_stats > 0) save_stats = 1; @@ -5345,13 +3067,11 @@ void engine_check_for_dumps(struct engine *e) { /* Do we want to perform structure finding? */ int run_stf = 0; - if ((e->policy & engine_policy_structure_finding)) { - if (e->stf_output_freq_format == io_stf_steps && - e->step % e->delta_step_stf == 0) - run_stf = 1; - else if (e->stf_output_freq_format == io_stf_time && - e->ti_end_min > e->ti_next_stf && e->ti_next_stf > 0) - run_stf = 1; + if (with_stf && stf_time_output) { + if (e->ti_end_min > e->ti_next_stf && e->ti_next_stf > 0) run_stf = 1; + } + if (with_stf && !stf_time_output) { + if (e->step % e->delta_step_stf == 0) run_stf = 1; } /* Do we want to perform a FOF search? */ if (e->policy & engine_policy_fof) @@ -5380,23 +3100,36 @@ void engine_check_for_dumps(struct engine *e) { /* Let's fake that we are at the common dump time */ e->ti_current = e->ti_next_snapshot; e->max_active_bin = 0; - if (!(e->policy & engine_policy_cosmology)) - e->time = e->ti_next_snapshot * e->time_base + e->time_begin; + if ((e->policy & engine_policy_cosmology)) { + cosmology_update(e->cosmology, e->physical_constants, e->ti_current); + e->time = e->cosmology->time; + } else { + e->time = e->ti_next_stats * e->time_base + e->time_begin; + } /* Drift everyone */ engine_drift_all(e); /* Dump everything */ engine_print_stats(e); +#ifdef WITH_LOGGER + /* Write a file containing the offsets in the particle logger. */ + engine_dump_index(e); +#else engine_dump_snapshot(e); +#endif } else if (e->ti_next_stats < e->ti_next_snapshot) { /* Let's fake that we are at the stats dump time */ e->ti_current = e->ti_next_stats; e->max_active_bin = 0; - if (!(e->policy & engine_policy_cosmology)) + if ((e->policy & engine_policy_cosmology)) { + cosmology_update(e->cosmology, e->physical_constants, e->ti_current); + e->time = e->cosmology->time; + } else { e->time = e->ti_next_stats * e->time_base + e->time_begin; + } /* Drift everyone */ engine_drift_all(e); @@ -5414,21 +3147,35 @@ void engine_check_for_dumps(struct engine *e) { engine_drift_all(e); /* Dump snapshot */ +#ifdef WITH_LOGGER + /* Write a file containing the offsets in the particle logger. */ + engine_dump_index(e); +#else engine_dump_snapshot(e); +#endif } else if (e->ti_next_stats > e->ti_next_snapshot) { /* Let's fake that we are at the snapshot dump time */ e->ti_current = e->ti_next_snapshot; e->max_active_bin = 0; - if (!(e->policy & engine_policy_cosmology)) - e->time = e->ti_next_snapshot * e->time_base + e->time_begin; + if ((e->policy & engine_policy_cosmology)) { + cosmology_update(e->cosmology, e->physical_constants, e->ti_current); + e->time = e->cosmology->time; + } else { + e->time = e->ti_next_stats * e->time_base + e->time_begin; + } /* Drift everyone */ engine_drift_all(e); /* Dump snapshot */ +#ifdef WITH_LOGGER + /* Write a file containing the offsets in the particle logger. */ + engine_dump_index(e); +#else engine_dump_snapshot(e); +#endif /* Let's fake that we are at the stats dump time */ e->ti_current = e->ti_next_stats; @@ -5452,14 +3199,23 @@ void engine_check_for_dumps(struct engine *e) { /* Let's fake that we are at the snapshot dump time */ e->ti_current = e->ti_next_snapshot; e->max_active_bin = 0; - if (!(e->policy & engine_policy_cosmology)) - e->time = e->ti_next_snapshot * e->time_base + e->time_begin; + if ((e->policy & engine_policy_cosmology)) { + cosmology_update(e->cosmology, e->physical_constants, e->ti_current); + e->time = e->cosmology->time; + } else { + e->time = e->ti_next_stats * e->time_base + e->time_begin; + } /* Drift everyone */ engine_drift_all(e); /* Dump... */ +#ifdef WITH_LOGGER + /* Write a file containing the offsets in the particle logger. */ + engine_dump_index(e); +#else engine_dump_snapshot(e); +#endif /* ... and find the next output time */ engine_compute_next_snapshot_time(e); @@ -5469,8 +3225,12 @@ void engine_check_for_dumps(struct engine *e) { /* Let's fake that we are at the stats dump time */ e->ti_current = e->ti_next_stats; e->max_active_bin = 0; - if (!(e->policy & engine_policy_cosmology)) + if ((e->policy & engine_policy_cosmology)) { + cosmology_update(e->cosmology, e->physical_constants, e->ti_current); + e->time = e->cosmology->time; + } else { e->time = e->ti_next_stats * e->time_base + e->time_begin; + } /* Drift everyone */ engine_drift_all(e); @@ -5485,10 +3245,25 @@ void engine_check_for_dumps(struct engine *e) { /* Perform structure finding? */ if (run_stf) { - // MATTHIEU: Add a drift_all here. And check the order with the other i/o - // options. - #ifdef HAVE_VELOCIRAPTOR + + // MATTHIEU: Check the order with the other i/o options. + if (!dump_snapshot && !save_stats) { + + /* Let's fake that we are at the stats dump time */ + e->ti_current = e->ti_next_stf; + e->max_active_bin = 0; + if ((e->policy & engine_policy_cosmology)) { + cosmology_update(e->cosmology, e->physical_constants, e->ti_current); + e->time = e->cosmology->time; + } else { + e->time = e->ti_next_stats * e->time_base + e->time_begin; + } + + /* Drift everyone */ + engine_drift_all(e); + } + velociraptor_init(e); velociraptor_invoke(e); @@ -5524,14 +3299,15 @@ void engine_check_for_dumps(struct engine *e) { /* Do we want to perform structure finding? */ run_stf = 0; - if ((e->policy & engine_policy_structure_finding) && - e->stf_output_freq_format == io_stf_time) { + if (with_stf && stf_time_output) { if (e->ti_end_min > e->ti_next_stf && e->ti_next_stf > 0) run_stf = 1; } } /* Restore the information we stored */ e->ti_current = ti_current; + if (e->policy & engine_policy_cosmology) + cosmology_update(e->cosmology, e->physical_constants, e->ti_current); e->max_active_bin = max_active_bin; e->time = time; } @@ -5647,12 +3423,38 @@ void engine_unskip(struct engine *e) { void engine_do_drift_all_mapper(void *map_data, int num_elements, void *extra_data) { - struct engine *e = (struct engine *)extra_data; - struct cell *cells = (struct cell *)map_data; + const struct engine *e = (const struct engine *)extra_data; + const int restarting = e->restarting; + struct space *s = e->s; + struct cell *cells_top; + int *local_cells_with_tasks_top; + + if (restarting) { + + /* When restarting, we loop over all top-level cells */ + cells_top = (struct cell *)map_data; + local_cells_with_tasks_top = NULL; + + } else { + + /* In any other case, we use th list of local cells with tasks */ + cells_top = s->cells_top; + local_cells_with_tasks_top = (int *)map_data; + } for (int ind = 0; ind < num_elements; ind++) { - struct cell *c = &cells[ind]; - if (c != NULL && c->nodeID == e->nodeID) { + + struct cell *c; + + /* When restarting, the list of local cells with tasks does not + yet exist. We use the raw list of top-level cells instead */ + if (restarting) + c = &cells_top[ind]; + else + c = &cells_top[local_cells_with_tasks_top[ind]]; + + if (c->nodeID == e->nodeID) { + /* Drift all the particles */ cell_drift_part(c, e, 1); @@ -5688,8 +3490,19 @@ void engine_drift_all(struct engine *e) { } #endif - threadpool_map(&e->threadpool, engine_do_drift_all_mapper, e->s->cells_top, - e->s->nr_cells, sizeof(struct cell), 0, e); + if (!e->restarting) { + + /* Normal case: We have a list of local cells with tasks to play with */ + threadpool_map(&e->threadpool, engine_do_drift_all_mapper, + e->s->local_cells_with_tasks_top, + e->s->nr_local_cells_with_tasks, sizeof(int), 0, e); + } else { + + /* When restarting, the list of local cells with tasks does not yet + exist. We use the raw list of top-level cells instead */ + threadpool_map(&e->threadpool, engine_do_drift_all_mapper, e->s->cells_top, + e->s->nr_cells, sizeof(struct cell), 0, e); + } /* Synchronize particle positions */ space_synchronize_particle_positions(e->s); @@ -5726,7 +3539,7 @@ void engine_do_drift_top_multipoles_mapper(void *map_data, int num_elements, if (c != NULL) { /* Drift the multipole at this level only */ - if (c->ti_old_multipole != e->ti_current) cell_drift_multipole(c, e); + if (c->grav.ti_old_multipole != e->ti_current) cell_drift_multipole(c, e); } } } @@ -6022,7 +3835,7 @@ void engine_makeproxies(struct engine *e) { proxy_addcell_out(&proxies[pid], &cells[cid], proxy_type); /* Store info about where to send the cell */ - cells[cid].sendto |= (1ULL << pid); + cells[cid].mpi.sendto |= (1ULL << pid); } /* Same for the symmetric case? */ @@ -6049,7 +3862,7 @@ void engine_makeproxies(struct engine *e) { proxy_addcell_out(&proxies[pid], &cells[cjd], proxy_type); /* Store info about where to send the cell */ - cells[cjd].sendto |= (1ULL << pid); + cells[cjd].mpi.sendto |= (1ULL << pid); } } } @@ -6225,6 +4038,42 @@ void engine_dump_snapshot(struct engine *e) { (float)clocks_diff(&time1, &time2), clocks_getunit()); } +/** + * @brief Writes an index file with the current state of the engine + * + * @param e The #engine. + */ +void engine_dump_index(struct engine *e) { + +#if defined(WITH_LOGGER) + struct clocks_time time1, time2; + clocks_gettime(&time1); + + if (e->verbose) { + if (e->policy & engine_policy_cosmology) + message("Writing index at a=%e", + exp(e->ti_current * e->time_base) * e->cosmology->a_begin); + else + message("Writing index at t=%e", + e->ti_current * e->time_base + e->time_begin); + } + + /* Dump... */ + write_index_single(e, e->logger->base_name, e->internal_units, + e->snapshot_units); + + /* Flag that we dumped a snapshot */ + e->step_props |= engine_step_prop_logger_index; + + clocks_gettime(&time2); + if (e->verbose) + message("writing particle indices took %.3f %s.", + (float)clocks_diff(&time1, &time2), clocks_getunit()); +#else + error("SWIFT was not compiled with the logger"); +#endif +} + #ifdef HAVE_SETAFFINITY /** * @brief Returns the initial affinity the main thread is using. @@ -6390,6 +4239,11 @@ void engine_init(struct engine *e, struct space *s, struct swift_params *params, e->last_repartition = 0; #endif +#if defined(WITH_LOGGER) + e->logger = (struct logger *)malloc(sizeof(struct logger)); + logger_init(e->logger, params); +#endif + /* Make the space link back to the engine. */ s->e = e; @@ -6425,8 +4279,8 @@ void engine_init(struct engine *e, struct space *s, struct swift_params *params, parser_get_opt_param_double(params, "StructureFinding:time_first", 0.); e->a_first_stf_output = parser_get_opt_param_double( params, "StructureFinding:scale_factor_first", 0.1); - e->stf_output_freq_format = - parser_get_param_int(params, "StructureFinding:output_time_format"); + e->stf_output_freq_format = (enum io_stf_output_format)parser_get_param_int( + params, "StructureFinding:output_time_format"); if (e->stf_output_freq_format == io_stf_steps) { e->delta_step_stf = @@ -6847,7 +4701,14 @@ void engine_config(int restart, struct engine *e, struct swift_params *params, MPI_COMM_WORLD); #endif - /* Find the time of the first snapshot output */ +#if defined(WITH_LOGGER) + if (e->nodeID == 0) + message( + "WARNING: There is currently no way of predicting the output " + "size, please use it carefully"); +#endif + + /* Find the time of the first snapshot output */ engine_compute_next_snapshot_time(e); /* Find the time of the first statistics output */ @@ -6887,6 +4748,7 @@ void engine_config(int restart, struct engine *e, struct swift_params *params, /* Construct types for MPI communications */ #ifdef WITH_MPI part_create_mpi_types(); + multipole_create_mpi_types(); stats_create_mpi_type(); proxy_create_mpi_type(); task_create_mpi_comms(); @@ -6991,7 +4853,12 @@ void engine_config(int restart, struct engine *e, struct swift_params *params, } } -/* Free the affinity stuff */ +#ifdef WITH_LOGGER + /* Write the particle logger header */ + logger_write_file_header(e->logger, e); +#endif + + /* Free the affinity stuff */ #if defined(HAVE_SETAFFINITY) if (with_aff) { free(cpuid); @@ -7403,20 +5270,17 @@ void engine_clean(struct engine *e) { } free(e->runners); free(e->snapshot_units); - if (e->output_list_snapshots) { - output_list_clean(e->output_list_snapshots); - free(e->output_list_snapshots); - } - if (e->output_list_stats) { - output_list_clean(e->output_list_stats); - free(e->output_list_stats); - } - if (e->output_list_stf) { - output_list_clean(e->output_list_stf); - free(e->output_list_stf); - } + + output_list_clean(&e->output_list_snapshots); + output_list_clean(&e->output_list_stats); + output_list_clean(&e->output_list_stf); + free(e->links); free(e->cell_loc); +#if defined(WITH_LOGGER) + logger_clean(e->logger); + free(e->logger); +#endif scheduler_clean(&e->sched); space_clean(e->s); threadpool_clean(&e->threadpool); diff --git a/src/engine.h b/src/engine.h index aed9c141d8ac5fc8bda155d27a78b0657ffe2118..4b924aef372c00ceec0d9ac3b36b20380b6f0d49 100644 --- a/src/engine.h +++ b/src/engine.h @@ -39,6 +39,7 @@ #include "collectgroup.h" #include "cooling_struct.h" #include "fof.h" +#include "dump.h" #include "gravity_properties.h" #include "mesh_gravity.h" #include "parser.h" @@ -50,6 +51,7 @@ #include "space.h" #include "task.h" #include "units.h" +#include "velociraptor_interface.h" /** * @brief The different policies the #engine can follow. @@ -73,11 +75,12 @@ enum engine_policy { engine_policy_sourceterms = (1 << 14), engine_policy_stars = (1 << 15), engine_policy_structure_finding = (1 << 16), - engine_policy_feedback = (1 << 17), - engine_policy_fof = (1 << 18) + engine_policy_star_formation = (1 << 17), + engine_policy_feedback = (1 << 18), + engine_policy_fof = (1 << 19) }; -#define engine_maxpolicy 18 -extern const char *engine_policy_names[]; +#define engine_maxpolicy 20 +extern const char *engine_policy_names[engine_maxpolicy + 1]; /** * @brief The different unusual events that can take place in a time-step. @@ -89,7 +92,8 @@ enum engine_step_properties { engine_step_prop_repartition = (1 << 2), engine_step_prop_statistics = (1 << 3), engine_step_prop_snapshot = (1 << 4), - engine_step_prop_restarts = (1 << 5) + engine_step_prop_restarts = (1 << 5), + engine_step_prop_logger_index = (1 << 6) }; /* Some constants */ @@ -205,6 +209,15 @@ struct engine { /* Total numbers of particles in the system. */ long long total_nr_parts, total_nr_gparts, total_nr_sparts; + /* The total number of inhibted particles in the system. */ + long long nr_inhibited_parts, nr_inhibited_gparts, nr_inhibited_sparts; + +#ifdef SWIFT_DEBUG_CHECKS + /* Total number of particles removed from the system since the last rebuild */ + long long count_inhibited_parts, count_inhibited_gparts, + count_inhibited_sparts; +#endif + /* Total mass in the simulation */ double total_mass; @@ -232,7 +245,7 @@ struct engine { int snapshot_output_count; /* Structure finding information */ - int stf_output_freq_format; + enum io_stf_output_format stf_output_freq_format; int delta_step_stf; double a_first_stf_output; double time_first_stf_output; @@ -306,6 +319,10 @@ struct engine { int forcerepart; struct repartition *reparttype; +#ifdef WITH_LOGGER + struct logger *logger; +#endif + /* How many steps have we done with the same set of tasks? */ int tasks_age; @@ -379,7 +396,7 @@ struct engine { int restart_max_tasks; }; -/* Function prototypes. */ +/* Function prototypes, engine.c. */ void engine_addlink(struct engine *e, struct link **l, struct task *t); void engine_barrier(struct engine *e); void engine_compute_next_snapshot_time(struct engine *e); @@ -409,19 +426,19 @@ void engine_init(struct engine *e, struct space *s, struct swift_params *params, 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); +void engine_dump_index(struct engine *e); void engine_launch(struct engine *e); void engine_prepare(struct engine *e); void engine_init_particles(struct engine *e, int flag_entropy_ICs, int clean_h_values, int compute_init_accel); void engine_step(struct engine *e); -void engine_maketasks(struct engine *e); void engine_split(struct engine *e, struct partition *initial_partition); -void engine_exchange_strays(struct engine *e, size_t offset_parts, - int *ind_part, size_t *Npart, size_t offset_gparts, - int *ind_gpart, size_t *Ngpart, - size_t offset_sparts, int *ind_spart, - size_t *Nspart); -void engine_rebuild(struct engine *e, int clean_h_values); +void engine_exchange_strays(struct engine *e, const size_t offset_parts, + const int *ind_part, size_t *Npart, + const size_t offset_gparts, const int *ind_gpart, + size_t *Ngpart, const size_t offset_sparts, + const int *ind_spart, size_t *Nspart); +void engine_rebuild(struct engine *e, int redistributed, int clean_h_values); void engine_repartition(struct engine *e); void engine_repartition_trigger(struct engine *e); void engine_makeproxies(struct engine *e); @@ -433,6 +450,12 @@ void engine_unpin(void); void engine_clean(struct engine *e); int engine_estimate_nr_tasks(struct engine *e); +/* Function prototypes, engine_maketasks.c. */ +void engine_maketasks(struct engine *e); + +/* Function prototypes, engine_marktasks.c. */ +int engine_marktasks(struct engine *e); + #ifdef HAVE_SETAFFINITY cpu_set_t *engine_entry_affinity(void); #endif diff --git a/src/engine_maketasks.c b/src/engine_maketasks.c new file mode 100644 index 0000000000000000000000000000000000000000..e4431a8cf14998774623e3575ecfdae08333e556 --- /dev/null +++ b/src/engine_maketasks.c @@ -0,0 +1,2090 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2012 Pedro Gonnet (pedro.gonnet@durham.ac.uk) + * Matthieu Schaller (matthieu.schaller@durham.ac.uk) + * 2015 Peter W. Draper (p.w.draper@durham.ac.uk) + * Angus Lepper (angus.lepper@ed.ac.uk) + * 2016 John A. Regan (john.a.regan@durham.ac.uk) + * 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" + +/* Some standard headers. */ +#include <stdlib.h> +#include <unistd.h> + +/* MPI headers. */ +#ifdef WITH_MPI +#include <mpi.h> +#endif + +/* Load the profiler header, if needed. */ +#ifdef WITH_PROFILER +#include <gperftools/profiler.h> +#endif + +/* This object's header. */ +#include "engine.h" + +/* Local headers. */ +#include "atomic.h" +#include "cell.h" +#include "clocks.h" +#include "cycle.h" +#include "debug.h" +#include "error.h" +#include "proxy.h" +#include "timers.h" + +/** + * @brief Add send tasks for the gravity pairs to a hierarchy of cells. + * + * @param e The #engine. + * @param ci The sending #cell. + * @param cj Dummy cell containing the nodeID of the receiving node. + * @param t_grav The send_grav #task, if it has already been created. + */ +void engine_addtasks_send_gravity(struct engine *e, struct cell *ci, + struct cell *cj, struct task *t_grav) { + +#ifdef WITH_MPI + struct link *l = NULL; + struct scheduler *s = &e->sched; + const int nodeID = cj->nodeID; + + /* Check if any of the gravity tasks are for the target node. */ + for (l = ci->grav.grav; l != NULL; l = l->next) + if (l->t->ci->nodeID == nodeID || + (l->t->cj != NULL && l->t->cj->nodeID == nodeID)) + break; + + /* If so, attach send tasks. */ + if (l != NULL) { + + /* Create the tasks and their dependencies? */ + if (t_grav == NULL) { + + /* Create a tag for this cell. */ + if (ci->mpi.tag < 0) cell_tag(ci); + + t_grav = scheduler_addtask(s, task_type_send, task_subtype_gpart, + ci->mpi.tag, 0, ci, cj); + + /* The sends should unlock the down pass. */ + scheduler_addunlock(s, t_grav, ci->grav.super->grav.down); + + /* Drift before you send */ + scheduler_addunlock(s, ci->grav.super->grav.drift, t_grav); + } + + /* Add them to the local cell. */ + engine_addlink(e, &ci->mpi.grav.send, t_grav); + } + + /* Recurse? */ + if (ci->split) + for (int k = 0; k < 8; k++) + if (ci->progeny[k] != NULL) + engine_addtasks_send_gravity(e, ci->progeny[k], cj, t_grav); + +#else + error("SWIFT was not compiled with MPI support."); +#endif +} + +/** + * @brief Add send tasks for the hydro pairs to a hierarchy of cells. + * + * @param e The #engine. + * @param ci The sending #cell. + * @param cj Dummy cell containing the nodeID of the receiving node. + * @param t_xv The send_xv #task, if it has already been created. + * @param t_rho The send_rho #task, if it has already been created. + * @param t_gradient The send_gradient #task, if already created. + */ +void engine_addtasks_send_hydro(struct engine *e, struct cell *ci, + struct cell *cj, struct task *t_xv, + struct task *t_rho, struct task *t_gradient) { + +#ifdef WITH_MPI + struct link *l = NULL; + struct scheduler *s = &e->sched; + const int nodeID = cj->nodeID; + + /* Check if any of the density tasks are for the target node. */ + for (l = ci->hydro.density; l != NULL; l = l->next) + if (l->t->ci->nodeID == nodeID || + (l->t->cj != NULL && l->t->cj->nodeID == nodeID)) + break; + + /* If so, attach send tasks. */ + if (l != NULL) { + + /* Create the tasks and their dependencies? */ + if (t_xv == NULL) { + + /* Create a tag for this cell. */ + if (ci->mpi.tag < 0) cell_tag(ci); + + t_xv = scheduler_addtask(s, task_type_send, task_subtype_xv, ci->mpi.tag, + 0, ci, cj); + t_rho = scheduler_addtask(s, task_type_send, task_subtype_rho, + ci->mpi.tag, 0, ci, cj); +#ifdef EXTRA_HYDRO_LOOP + t_gradient = scheduler_addtask(s, task_type_send, task_subtype_gradient, + ci->mpi.tag, 0, ci, cj); +#endif + +#ifdef EXTRA_HYDRO_LOOP + + scheduler_addunlock(s, t_gradient, ci->super->kick2); + + scheduler_addunlock(s, ci->hydro.super->hydro.extra_ghost, t_gradient); + + /* The send_rho task should unlock the super_hydro-cell's extra_ghost + * task. */ + scheduler_addunlock(s, t_rho, ci->hydro.super->hydro.extra_ghost); + + /* The send_rho task depends on the cell's ghost task. */ + scheduler_addunlock(s, ci->hydro.super->hydro.ghost_out, t_rho); + + /* The send_xv task should unlock the super_hydro-cell's ghost task. */ + scheduler_addunlock(s, t_xv, ci->hydro.super->hydro.ghost_in); + +#else + /* The send_rho task should unlock the super_hydro-cell's kick task. */ + scheduler_addunlock(s, t_rho, ci->super->end_force); + + /* The send_rho task depends on the cell's ghost task. */ + scheduler_addunlock(s, ci->hydro.super->hydro.ghost_out, t_rho); + + /* The send_xv task should unlock the super_hydro-cell's ghost task. */ + scheduler_addunlock(s, t_xv, ci->hydro.super->hydro.ghost_in); + +#endif + + /* Drift before you send */ + scheduler_addunlock(s, ci->hydro.super->hydro.drift, t_xv); + } + + /* Add them to the local cell. */ + engine_addlink(e, &ci->mpi.hydro.send_xv, t_xv); + engine_addlink(e, &ci->mpi.hydro.send_rho, t_rho); +#ifdef EXTRA_HYDRO_LOOP + engine_addlink(e, &ci->mpi.hydro.send_gradient, t_gradient); +#endif + } + + /* Recurse? */ + if (ci->split) + for (int k = 0; k < 8; k++) + if (ci->progeny[k] != NULL) + engine_addtasks_send_hydro(e, ci->progeny[k], cj, t_xv, t_rho, + t_gradient); + +#else + error("SWIFT was not compiled with MPI support."); +#endif +} + +/** + * @brief Add send tasks for the time-step to a hierarchy of cells. + * + * @param e The #engine. + * @param ci The sending #cell. + * @param cj Dummy cell containing the nodeID of the receiving node. + * @param t_ti The send_ti #task, if it has already been created. + */ +void engine_addtasks_send_timestep(struct engine *e, struct cell *ci, + struct cell *cj, struct task *t_ti) { + +#ifdef WITH_MPI + struct link *l = NULL; + struct scheduler *s = &e->sched; + const int nodeID = cj->nodeID; + + /* Check if any of the gravity tasks are for the target node. */ + for (l = ci->grav.grav; l != NULL; l = l->next) + if (l->t->ci->nodeID == nodeID || + (l->t->cj != NULL && l->t->cj->nodeID == nodeID)) + break; + + /* Check whether instead any of the hydro tasks are for the target node. */ + if (l == NULL) + for (l = ci->hydro.density; l != NULL; l = l->next) + if (l->t->ci->nodeID == nodeID || + (l->t->cj != NULL && l->t->cj->nodeID == nodeID)) + break; + + /* If found anything, attach send tasks. */ + if (l != NULL) { + + /* Create the tasks and their dependencies? */ + if (t_ti == NULL) { + + /* Create a tag for this cell. */ + if (ci->mpi.tag < 0) cell_tag(ci); + + t_ti = scheduler_addtask(s, task_type_send, task_subtype_tend, + ci->mpi.tag, 0, ci, cj); + + /* The super-cell's timestep task should unlock the send_ti task. */ + scheduler_addunlock(s, ci->super->timestep, t_ti); + } + + /* Add them to the local cell. */ + engine_addlink(e, &ci->mpi.send_ti, t_ti); + } + + /* Recurse? */ + if (ci->split) + for (int k = 0; k < 8; k++) + if (ci->progeny[k] != NULL) + engine_addtasks_send_timestep(e, ci->progeny[k], cj, t_ti); + +#else + error("SWIFT was not compiled with MPI support."); +#endif +} + +/** + * @brief Add recv tasks for hydro pairs to a hierarchy of cells. + * + * @param e The #engine. + * @param c The foreign #cell. + * @param t_xv The recv_xv #task, if it has already been created. + * @param t_rho The recv_rho #task, if it has already been created. + * @param t_gradient The recv_gradient #task, if it has already been created. + */ +void engine_addtasks_recv_hydro(struct engine *e, struct cell *c, + struct task *t_xv, struct task *t_rho, + struct task *t_gradient) { + +#ifdef WITH_MPI + struct scheduler *s = &e->sched; + + /* Have we reached a level where there are any hydro tasks ? */ + if (t_xv == NULL && c->hydro.density != NULL) { + +#ifdef SWIFT_DEBUG_CHECKS + /* Make sure this cell has a valid tag. */ + if (c->mpi.tag < 0) error("Trying to receive from untagged cell."); +#endif // SWIFT_DEBUG_CHECKS + + /* Create the tasks. */ + t_xv = scheduler_addtask(s, task_type_recv, task_subtype_xv, c->mpi.tag, 0, + c, NULL); + t_rho = scheduler_addtask(s, task_type_recv, task_subtype_rho, c->mpi.tag, + 0, c, NULL); +#ifdef EXTRA_HYDRO_LOOP + t_gradient = scheduler_addtask(s, task_type_recv, task_subtype_gradient, + c->mpi.tag, 0, c, NULL); +#endif + } + + c->mpi.hydro.recv_xv = t_xv; + c->mpi.hydro.recv_rho = t_rho; + c->mpi.hydro.recv_gradient = t_gradient; + + /* Add dependencies. */ + if (c->hydro.sorts != NULL) scheduler_addunlock(s, t_xv, c->hydro.sorts); + + for (struct link *l = c->hydro.density; l != NULL; l = l->next) { + scheduler_addunlock(s, t_xv, l->t); + scheduler_addunlock(s, l->t, t_rho); + } +#ifdef EXTRA_HYDRO_LOOP + for (struct link *l = c->hydro.gradient; l != NULL; l = l->next) { + scheduler_addunlock(s, t_rho, l->t); + scheduler_addunlock(s, l->t, t_gradient); + } + for (struct link *l = c->hydro.force; l != NULL; l = l->next) + scheduler_addunlock(s, t_gradient, l->t); +#else + for (struct link *l = c->hydro.force; l != NULL; l = l->next) + scheduler_addunlock(s, t_rho, l->t); +#endif + + /* Recurse? */ + if (c->split) + for (int k = 0; k < 8; k++) + if (c->progeny[k] != NULL) + engine_addtasks_recv_hydro(e, c->progeny[k], t_xv, t_rho, t_gradient); + +#else + error("SWIFT was not compiled with MPI support."); +#endif +} + +/** + * @brief Add recv tasks for gravity pairs to a hierarchy of cells. + * + * @param e The #engine. + * @param c The foreign #cell. + * @param t_grav The recv_gpart #task, if it has already been created. + */ +void engine_addtasks_recv_gravity(struct engine *e, struct cell *c, + struct task *t_grav) { + +#ifdef WITH_MPI + struct scheduler *s = &e->sched; + + /* Have we reached a level where there are any gravity tasks ? */ + if (t_grav == NULL && c->grav.grav != NULL) { + +#ifdef SWIFT_DEBUG_CHECKS + /* Make sure this cell has a valid tag. */ + if (c->mpi.tag < 0) error("Trying to receive from untagged cell."); +#endif // SWIFT_DEBUG_CHECKS + + /* Create the tasks. */ + t_grav = scheduler_addtask(s, task_type_recv, task_subtype_gpart, + c->mpi.tag, 0, c, NULL); + } + + c->mpi.grav.recv = t_grav; + + for (struct link *l = c->grav.grav; l != NULL; l = l->next) + scheduler_addunlock(s, t_grav, l->t); + + /* Recurse? */ + if (c->split) + for (int k = 0; k < 8; k++) + if (c->progeny[k] != NULL) + engine_addtasks_recv_gravity(e, c->progeny[k], t_grav); + +#else + error("SWIFT was not compiled with MPI support."); +#endif +} + +/** + * @brief Add recv tasks for gravity pairs to a hierarchy of cells. + * + * @param e The #engine. + * @param c The foreign #cell. + * @param t_ti The recv_ti #task, if already been created. + */ +void engine_addtasks_recv_timestep(struct engine *e, struct cell *c, + struct task *t_ti) { + +#ifdef WITH_MPI + struct scheduler *s = &e->sched; + + /* Have we reached a level where there are any self/pair tasks ? */ + if (t_ti == NULL && (c->grav.grav != NULL || c->hydro.density != NULL)) { + +#ifdef SWIFT_DEBUG_CHECKS + /* Make sure this cell has a valid tag. */ + if (c->mpi.tag < 0) error("Trying to receive from untagged cell."); +#endif // SWIFT_DEBUG_CHECKS + + t_ti = scheduler_addtask(s, task_type_recv, task_subtype_tend, c->mpi.tag, + 0, c, NULL); + } + + c->mpi.recv_ti = t_ti; + + for (struct link *l = c->grav.grav; l != NULL; l = l->next) + scheduler_addunlock(s, l->t, t_ti); + + for (struct link *l = c->hydro.force; l != NULL; l = l->next) + scheduler_addunlock(s, l->t, t_ti); + + /* Recurse? */ + if (c->split) + for (int k = 0; k < 8; k++) + if (c->progeny[k] != NULL) + engine_addtasks_recv_timestep(e, c->progeny[k], t_ti); + +#else + error("SWIFT was not compiled with MPI support."); +#endif +} + +/** + * @brief Generate the hydro hierarchical tasks for a hierarchy of cells - + * i.e. all the O(Npart) tasks -- timestep version + * + * Tasks are only created here. The dependencies will be added later on. + * + * Note that there is no need to recurse below the super-cell. Note also + * that we only add tasks if the relevant particles are present in the cell. + * + * @param e The #engine. + * @param c The #cell. + */ +void engine_make_hierarchical_tasks_common(struct engine *e, struct cell *c) { + + struct scheduler *s = &e->sched; + const int is_with_cooling = (e->policy & engine_policy_cooling); + const int is_with_star_formation = (e->policy & engine_policy_star_formation); + + /* Are we in a super-cell ? */ + if (c->super == c) { + + /* Local tasks only... */ + if (c->nodeID == e->nodeID) { + + /* Add the two half kicks */ + c->kick1 = scheduler_addtask(s, task_type_kick1, task_subtype_none, 0, 0, + c, NULL); + +#if defined(WITH_LOGGER) + c->logger = scheduler_addtask(s, task_type_logger, task_subtype_none, 0, + 0, c, NULL); +#endif + + c->kick2 = scheduler_addtask(s, task_type_kick2, task_subtype_none, 0, 0, + c, NULL); + + /* Add the time-step calculation task and its dependency */ + c->timestep = scheduler_addtask(s, task_type_timestep, task_subtype_none, + 0, 0, c, NULL); + + /* Add the task finishing the force calculation */ + c->end_force = scheduler_addtask(s, task_type_end_force, + task_subtype_none, 0, 0, c, NULL); + + if (is_with_cooling) { + + c->hydro.cooling = scheduler_addtask(s, task_type_cooling, + task_subtype_none, 0, 0, c, NULL); + + scheduler_addunlock(s, c->end_force, c->hydro.cooling); + scheduler_addunlock(s, c->hydro.cooling, c->kick2); + + } else { + scheduler_addunlock(s, c->end_force, c->kick2); + } + + if (is_with_star_formation) { + + c->hydro.star_formation = scheduler_addtask( + s, task_type_star_formation, task_subtype_none, 0, 0, c, NULL); + + scheduler_addunlock(s, c->kick2, c->hydro.star_formation); + scheduler_addunlock(s, c->hydro.star_formation, c->timestep); + + } else { + scheduler_addunlock(s, c->kick2, c->timestep); + } + scheduler_addunlock(s, c->timestep, c->kick1); + +#if defined(WITH_LOGGER) + scheduler_addunlock(s, c->kick1, c->logger); +#endif + } + + } else { /* We are above the super-cell so need to go deeper */ + + /* Recurse. */ + if (c->split) + for (int k = 0; k < 8; k++) + if (c->progeny[k] != NULL) + engine_make_hierarchical_tasks_common(e, c->progeny[k]); + } +} + +/** + * @brief Generate the hydro hierarchical tasks for a hierarchy of cells - + * i.e. all the O(Npart) tasks -- gravity version + * + * Tasks are only created here. The dependencies will be added later on. + * + * Note that there is no need to recurse below the super-cell. Note also + * that we only add tasks if the relevant particles are present in the cell. + * + * @param e The #engine. + * @param c The #cell. + */ +void engine_make_hierarchical_tasks_gravity(struct engine *e, struct cell *c) { + + struct scheduler *s = &e->sched; + const int periodic = e->s->periodic; + const int is_self_gravity = (e->policy & engine_policy_self_gravity); + + /* Are we in a super-cell ? */ + if (c->grav.super == c) { + + /* Local tasks only... */ + if (c->nodeID == e->nodeID) { + + c->grav.drift = scheduler_addtask(s, task_type_drift_gpart, + task_subtype_none, 0, 0, c, NULL); + + if (is_self_gravity) { + + /* Initialisation of the multipoles */ + c->grav.init = scheduler_addtask(s, task_type_init_grav, + task_subtype_none, 0, 0, c, NULL); + + /* Gravity non-neighbouring pm calculations */ + c->grav.long_range = scheduler_addtask( + s, task_type_grav_long_range, task_subtype_none, 0, 0, c, NULL); + + /* Gravity recursive down-pass */ + c->grav.down = scheduler_addtask(s, task_type_grav_down, + task_subtype_none, 0, 0, c, NULL); + + /* Implicit tasks for the up and down passes */ + c->grav.init_out = scheduler_addtask(s, task_type_init_grav_out, + task_subtype_none, 0, 1, c, NULL); + c->grav.down_in = scheduler_addtask(s, task_type_grav_down_in, + task_subtype_none, 0, 1, c, NULL); + + /* Gravity mesh force propagation */ + if (periodic) + c->grav.mesh = scheduler_addtask(s, task_type_grav_mesh, + task_subtype_none, 0, 0, c, NULL); + + if (periodic) scheduler_addunlock(s, c->grav.drift, c->grav.mesh); + if (periodic) scheduler_addunlock(s, c->grav.mesh, c->grav.down); + scheduler_addunlock(s, c->grav.init, c->grav.long_range); + scheduler_addunlock(s, c->grav.long_range, c->grav.down); + scheduler_addunlock(s, c->grav.down, c->super->end_force); + + /* Link in the implicit tasks */ + scheduler_addunlock(s, c->grav.init, c->grav.init_out); + scheduler_addunlock(s, c->grav.down_in, c->grav.down); + } + } + } + + /* We are below the super-cell but not below the maximal splitting depth */ + else if (c->grav.super != NULL && c->depth < space_subdepth_grav) { + + /* Local tasks only... */ + if (c->nodeID == e->nodeID) { + + if (is_self_gravity) { + + c->grav.init_out = scheduler_addtask(s, task_type_init_grav_out, + task_subtype_none, 0, 1, c, NULL); + + c->grav.down_in = scheduler_addtask(s, task_type_grav_down_in, + task_subtype_none, 0, 1, c, NULL); + + scheduler_addunlock(s, c->parent->grav.init_out, c->grav.init_out); + scheduler_addunlock(s, c->grav.down_in, c->parent->grav.down_in); + } + } + } + + /* Recurse but not below the maximal splitting depth */ + if (c->split && c->depth <= space_subdepth_grav) + for (int k = 0; k < 8; k++) + if (c->progeny[k] != NULL) + engine_make_hierarchical_tasks_gravity(e, c->progeny[k]); +} + +/** + * @brief Recursively add non-implicit star ghost tasks to a cell hierarchy. + */ +void engine_add_stars_ghosts(struct engine *e, struct cell *c, + struct task *stars_ghost_in, + struct task *stars_ghost_out) { + + /* If we have reached the leaf OR have to few particles to play with*/ + if (!c->split || c->stars.count < engine_max_sparts_per_ghost) { + + /* Add the ghost task and its dependencies */ + struct scheduler *s = &e->sched; + c->stars.ghost = scheduler_addtask(s, task_type_stars_ghost, + task_subtype_none, 0, 0, c, NULL); + scheduler_addunlock(s, stars_ghost_in, c->stars.ghost); + scheduler_addunlock(s, c->stars.ghost, stars_ghost_out); + } else { + /* Keep recursing */ + for (int k = 0; k < 8; k++) + if (c->progeny[k] != NULL) + engine_add_stars_ghosts(e, c->progeny[k], stars_ghost_in, + stars_ghost_out); + } +} + +/** + * @brief Recursively add non-implicit ghost tasks to a cell hierarchy. + */ +void engine_add_ghosts(struct engine *e, struct cell *c, struct task *ghost_in, + struct task *ghost_out) { + + /* If we have reached the leaf OR have to few particles to play with*/ + if (!c->split || c->hydro.count < engine_max_parts_per_ghost) { + + /* Add the ghost task and its dependencies */ + struct scheduler *s = &e->sched; + c->hydro.ghost = + scheduler_addtask(s, task_type_ghost, task_subtype_none, 0, 0, c, NULL); + scheduler_addunlock(s, ghost_in, c->hydro.ghost); + scheduler_addunlock(s, c->hydro.ghost, ghost_out); + } else { + /* Keep recursing */ + for (int k = 0; k < 8; k++) + if (c->progeny[k] != NULL) + engine_add_ghosts(e, c->progeny[k], ghost_in, ghost_out); + } +} + +/** + * @brief Generate the hydro hierarchical tasks for a hierarchy of cells - + * i.e. all the O(Npart) tasks -- hydro version + * + * Tasks are only created here. The dependencies will be added later on. + * + * Note that there is no need to recurse below the super-cell. Note also + * that we only add tasks if the relevant particles are present in the cell. + * + * @param e The #engine. + * @param c The #cell. + */ +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) { + + /* Add the sort task. */ + c->hydro.sorts = + scheduler_addtask(s, task_type_sort, task_subtype_none, 0, 0, c, NULL); + + /* Local tasks only... */ + if (c->nodeID == e->nodeID) { + + /* Add the drift task. */ + c->hydro.drift = scheduler_addtask(s, task_type_drift_part, + task_subtype_none, 0, 0, c, NULL); + + /* Generate the ghost tasks. */ + c->hydro.ghost_in = + scheduler_addtask(s, task_type_ghost_in, task_subtype_none, 0, + /* implicit = */ 1, c, NULL); + c->hydro.ghost_out = + scheduler_addtask(s, task_type_ghost_out, task_subtype_none, 0, + /* implicit = */ 1, c, NULL); + engine_add_ghosts(e, c, c->hydro.ghost_in, c->hydro.ghost_out); + +#ifdef EXTRA_HYDRO_LOOP + /* Generate the extra ghost task. */ + 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 */ + + /* Recurse. */ + if (c->split) + for (int k = 0; k < 8; k++) + if (c->progeny[k] != NULL) + engine_make_hierarchical_tasks_hydro(e, c->progeny[k]); + } +} + +/** + * @brief Generate the stars hierarchical tasks for a hierarchy of cells - + * i.e. all the O(Npart) tasks -- star version + * + * Tasks are only created here. The dependencies will be added later on. + * + * Note that there is no need to recurse below the super-cell. Note also + * that we only add tasks if the relevant particles are present in the cell. + * + * @param e The #engine. + * @param c The #cell. + */ +void engine_make_hierarchical_tasks_stars(struct engine *e, struct cell *c) { + + struct scheduler *s = &e->sched; + + /* Are we in a super-cell ? */ + if (c->super == c) { + + /* Local tasks only... */ + if (c->nodeID == e->nodeID) { + + /* Generate the ghost tasks. */ + c->stars.ghost_in = + scheduler_addtask(s, task_type_stars_ghost_in, task_subtype_none, 0, + /* implicit = */ 1, c, NULL); + c->stars.ghost_out = + scheduler_addtask(s, task_type_stars_ghost_out, task_subtype_none, 0, + /* implicit = */ 1, c, NULL); + engine_add_stars_ghosts(e, c, c->stars.ghost_in, c->stars.ghost_out); + } + } else { /* We are above the super-cell so need to go deeper */ + + /* Recurse. */ + if (c->split) + for (int k = 0; k < 8; k++) + if (c->progeny[k] != NULL) + engine_make_hierarchical_tasks_stars(e, c->progeny[k]); + } +} + +/** + * @brief Constructs the top-level tasks for the short-range gravity + * and long-range gravity interactions. + * + * - All top-cells get a self task. + * - All pairs within range according to the multipole acceptance + * criterion get a pair task. + */ +void engine_make_self_gravity_tasks_mapper(void *map_data, int num_elements, + void *extra_data) { + + struct engine *e = ((struct engine **)extra_data)[0]; + struct space *s = e->s; + struct scheduler *sched = &e->sched; + const int nodeID = e->nodeID; + const int periodic = s->periodic; + const double dim[3] = {s->dim[0], s->dim[1], s->dim[2]}; + const int cdim[3] = {s->cdim[0], s->cdim[1], s->cdim[2]}; + struct cell *cells = s->cells_top; + const double theta_crit = e->gravity_properties->theta_crit; + const double max_distance = e->mesh->r_cut_max; + + /* Compute how many cells away we need to walk */ + const double distance = 2.5 * cells[0].width[0] / theta_crit; + int delta = (int)(distance / cells[0].width[0]) + 1; + int delta_m = delta; + int delta_p = delta; + + /* Special case where every cell is in range of every other one */ + if (delta >= cdim[0] / 2) { + if (cdim[0] % 2 == 0) { + delta_m = cdim[0] / 2; + delta_p = cdim[0] / 2 - 1; + } else { + delta_m = cdim[0] / 2; + delta_p = cdim[0] / 2; + } + } + + /* Loop through the elements, which are just byte offsets from NULL. */ + for (int ind = 0; ind < num_elements; ind++) { + + /* Get the cell index. */ + const int cid = (size_t)(map_data) + ind; + + /* Integer indices of the cell in the top-level grid */ + const int i = cid / (cdim[1] * cdim[2]); + const int j = (cid / cdim[2]) % cdim[1]; + const int k = cid % cdim[2]; + + /* Get the cell */ + struct cell *ci = &cells[cid]; + + /* Skip cells without gravity particles */ + if (ci->grav.count == 0) continue; + + /* Is that cell local ? */ + if (ci->nodeID != nodeID) continue; + + /* If the cells is local build a self-interaction */ + scheduler_addtask(sched, task_type_self, task_subtype_grav, 0, 0, ci, NULL); + + /* Recover the multipole information */ + const struct gravity_tensors *const multi_i = ci->grav.multipole; + const double CoM_i[3] = {multi_i->CoM[0], multi_i->CoM[1], multi_i->CoM[2]}; + +#ifdef SWIFT_DEBUG_CHECKS + if (cell_getid(cdim, i, j, k) != cid) + error("Incorrect calculation of indices (i,j,k)=(%d,%d,%d) cid=%d", i, j, + k, cid); + + if (multi_i->r_max != multi_i->r_max_rebuild) + error( + "Multipole size not equal ot it's size after rebuild. But we just " + "rebuilt..."); +#endif + + /* Loop over every other cell within (Manhattan) range delta */ + for (int x = -delta_m; x <= delta_p; x++) { + int ii = i + x; + if (ii >= cdim[0]) + ii -= cdim[0]; + else if (ii < 0) + ii += cdim[0]; + for (int y = -delta_m; y <= delta_p; y++) { + int jj = j + y; + if (jj >= cdim[1]) + jj -= cdim[1]; + else if (jj < 0) + jj += cdim[1]; + for (int z = -delta_m; z <= delta_p; z++) { + int kk = k + z; + if (kk >= cdim[2]) + kk -= cdim[2]; + else if (kk < 0) + kk += cdim[2]; + + /* Get the cell */ + const int cjd = cell_getid(cdim, ii, jj, kk); + struct cell *cj = &cells[cjd]; + +#ifdef SWIFT_DEBUG_CHECKS + const int iii = cjd / (cdim[1] * cdim[2]); + const int jjj = (cjd / cdim[2]) % cdim[1]; + const int kkk = cjd % cdim[2]; + + if (ii != iii || jj != jjj || kk != kkk) + error( + "Incorrect calculation of indices (iii,jjj,kkk)=(%d,%d,%d) " + "cjd=%d", + iii, jjj, kkk, cjd); +#endif + + /* Avoid duplicates of local pairs*/ + if (cid <= cjd && cj->nodeID == nodeID) continue; + + /* Skip cells without gravity particles */ + if (cj->grav.count == 0) continue; + + /* Recover the multipole information */ + const struct gravity_tensors *const multi_j = cj->grav.multipole; + + /* Get the distance between the CoMs */ + double dx = CoM_i[0] - multi_j->CoM[0]; + double dy = CoM_i[1] - multi_j->CoM[1]; + double dz = CoM_i[2] - multi_j->CoM[2]; + + /* Apply BC */ + if (periodic) { + dx = nearest(dx, dim[0]); + dy = nearest(dy, dim[1]); + dz = nearest(dz, dim[2]); + } + const double r2 = dx * dx + dy * dy + dz * dz; + + /* Minimal distance between any pair of particles */ + const double min_radius = + sqrt(r2) - (multi_i->r_max + multi_j->r_max); + + /* Are we beyond the distance where the truncated forces are 0 ?*/ + if (periodic && min_radius > max_distance) continue; + + /* Are the cells too close for a MM interaction ? */ + if (!cell_can_use_pair_mm_rebuild(ci, cj, e, s)) { + + /* Ok, we need to add a direct pair calculation */ + scheduler_addtask(sched, task_type_pair, task_subtype_grav, 0, 0, + ci, cj); + } + } + } + } + } +} + +void engine_make_hierarchical_tasks_mapper(void *map_data, int num_elements, + void *extra_data) { + struct engine *e = (struct engine *)extra_data; + const int is_with_hydro = (e->policy & engine_policy_hydro); + const int is_with_self_gravity = (e->policy & engine_policy_self_gravity); + const int is_with_external_gravity = + (e->policy & engine_policy_external_gravity); + const int is_with_feedback = (e->policy & engine_policy_feedback); + + for (int ind = 0; ind < num_elements; ind++) { + struct cell *c = &((struct cell *)map_data)[ind]; + /* Make the common tasks (time integration) */ + engine_make_hierarchical_tasks_common(e, c); + /* Add the hydro stuff */ + if (is_with_hydro) engine_make_hierarchical_tasks_hydro(e, c); + /* And the gravity stuff */ + if (is_with_self_gravity || is_with_external_gravity) + engine_make_hierarchical_tasks_gravity(e, c); + if (is_with_feedback) engine_make_hierarchical_tasks_stars(e, c); + } +} + +/** + * @brief Constructs the top-level tasks for the short-range gravity + * interactions (master function). + * + * - Create the FFT task and the array of gravity ghosts. + * - Call the mapper function to create the other tasks. + * + * @param e The #engine. + */ +void engine_make_self_gravity_tasks(struct engine *e) { + + struct space *s = e->s; + struct task **ghosts = NULL; + + /* Create the multipole self and pair tasks. */ + void *extra_data[2] = {e, ghosts}; + threadpool_map(&e->threadpool, engine_make_self_gravity_tasks_mapper, NULL, + s->nr_cells, 1, 0, extra_data); +} + +/** + * @brief Constructs the top-level tasks for the external gravity. + * + * @param e The #engine. + */ +void engine_make_external_gravity_tasks(struct engine *e) { + + struct space *s = e->s; + struct scheduler *sched = &e->sched; + const int nodeID = e->nodeID; + struct cell *cells = s->cells_top; + const int nr_cells = s->nr_cells; + + for (int cid = 0; cid < nr_cells; ++cid) { + + struct cell *ci = &cells[cid]; + + /* Skip cells without gravity particles */ + if (ci->grav.count == 0) continue; + + /* Is that neighbour local ? */ + if (ci->nodeID != nodeID) continue; + + /* If the cell is local, build a self-interaction */ + scheduler_addtask(sched, task_type_self, task_subtype_external_grav, 0, 0, + ci, NULL); + } +} + +/** + * @brief Counts the tasks associated with one cell and constructs the links + * + * For each hydrodynamic and gravity task, construct the links with + * the corresponding cell. Similarly, construct the dependencies for + * all the sorting tasks. + */ +void engine_count_and_link_tasks_mapper(void *map_data, int num_elements, + void *extra_data) { + + struct engine *e = (struct engine *)extra_data; + struct scheduler *const sched = &e->sched; + + for (int ind = 0; ind < num_elements; ind++) { + struct task *t = &((struct task *)map_data)[ind]; + + struct cell *ci = t->ci; + struct cell *cj = t->cj; + const enum task_types t_type = t->type; + const enum task_subtypes t_subtype = t->subtype; + + /* Link sort tasks to all the higher sort task. */ + if (t_type == task_type_sort) { + for (struct cell *finger = t->ci->parent; finger != NULL; + finger = finger->parent) + if (finger->hydro.sorts != NULL) + scheduler_addunlock(sched, t, finger->hydro.sorts); + } + + /* Link self tasks to cells. */ + else if (t_type == task_type_self) { + atomic_inc(&ci->nr_tasks); + + if (t_subtype == task_subtype_density) { + engine_addlink(e, &ci->hydro.density, t); + } else if (t_subtype == task_subtype_grav) { + engine_addlink(e, &ci->grav.grav, t); + } else if (t_subtype == task_subtype_external_grav) { + engine_addlink(e, &ci->grav.grav, t); + } else if (t->subtype == task_subtype_stars_density) { + engine_addlink(e, &ci->stars.density, t); + } + + /* Link pair tasks to cells. */ + } else if (t_type == task_type_pair) { + atomic_inc(&ci->nr_tasks); + atomic_inc(&cj->nr_tasks); + + if (t_subtype == task_subtype_density) { + engine_addlink(e, &ci->hydro.density, t); + engine_addlink(e, &cj->hydro.density, t); + } else if (t_subtype == task_subtype_grav) { + engine_addlink(e, &ci->grav.grav, t); + engine_addlink(e, &cj->grav.grav, t); + } else if (t->subtype == task_subtype_stars_density) { + engine_addlink(e, &ci->stars.density, t); + engine_addlink(e, &cj->stars.density, t); + } +#ifdef SWIFT_DEBUG_CHECKS + else if (t_subtype == task_subtype_external_grav) { + error("Found a pair/external-gravity task..."); + } +#endif + + /* Link sub-self tasks to cells. */ + } else if (t_type == task_type_sub_self) { + atomic_inc(&ci->nr_tasks); + + if (t_subtype == task_subtype_density) { + engine_addlink(e, &ci->hydro.density, t); + } else if (t_subtype == task_subtype_grav) { + engine_addlink(e, &ci->grav.grav, t); + } else if (t_subtype == task_subtype_external_grav) { + engine_addlink(e, &ci->grav.grav, t); + } else if (t->subtype == task_subtype_stars_density) { + engine_addlink(e, &ci->stars.density, t); + } + + /* Link sub-pair tasks to cells. */ + } else if (t_type == task_type_sub_pair) { + atomic_inc(&ci->nr_tasks); + atomic_inc(&cj->nr_tasks); + + if (t_subtype == task_subtype_density) { + engine_addlink(e, &ci->hydro.density, t); + engine_addlink(e, &cj->hydro.density, t); + } else if (t_subtype == task_subtype_grav) { + engine_addlink(e, &ci->grav.grav, t); + engine_addlink(e, &cj->grav.grav, t); + } else if (t->subtype == task_subtype_stars_density) { + engine_addlink(e, &ci->stars.density, t); + engine_addlink(e, &cj->stars.density, t); + } +#ifdef SWIFT_DEBUG_CHECKS + else if (t_subtype == task_subtype_external_grav) { + error("Found a sub-pair/external-gravity task..."); + } +#endif + + /* Multipole-multipole interaction of progenies */ + } else if (t_type == task_type_grav_mm) { + + atomic_inc(&ci->grav.nr_mm_tasks); + atomic_inc(&cj->grav.nr_mm_tasks); + engine_addlink(e, &ci->grav.mm, t); + engine_addlink(e, &cj->grav.mm, t); + } + } +} + +/** + * @brief Creates all the task dependencies for the gravity + * + * @param e The #engine + */ +void engine_link_gravity_tasks(struct engine *e) { + + struct scheduler *sched = &e->sched; + const int nodeID = e->nodeID; + const int nr_tasks = sched->nr_tasks; + + for (int k = 0; k < nr_tasks; k++) { + + /* Get a pointer to the task. */ + struct task *t = &sched->tasks[k]; + + if (t->type == task_type_none) continue; + + /* Get the cells we act on */ + struct cell *ci = t->ci; + struct cell *cj = t->cj; + const enum task_types t_type = t->type; + const enum task_subtypes t_subtype = t->subtype; + + struct cell *ci_parent = (ci->parent != NULL) ? ci->parent : ci; + struct cell *cj_parent = + (cj != NULL && cj->parent != NULL) ? cj->parent : cj; + +/* Node ID (if running with MPI) */ +#ifdef WITH_MPI + const int ci_nodeID = ci->nodeID; + const int cj_nodeID = (cj != NULL) ? cj->nodeID : -1; +#else + const int ci_nodeID = nodeID; + const int cj_nodeID = nodeID; +#endif + + /* Self-interaction for self-gravity? */ + if (t_type == task_type_self && t_subtype == task_subtype_grav) { + +#ifdef SWIFT_DEBUG_CHECKS + if (ci_nodeID != nodeID) error("Non-local self task"); +#endif + + /* drift ---+-> gravity --> grav_down */ + /* init --/ */ + scheduler_addunlock(sched, ci->grav.super->grav.drift, t); + scheduler_addunlock(sched, ci_parent->grav.init_out, t); + scheduler_addunlock(sched, t, ci_parent->grav.down_in); + } + + /* Self-interaction for external gravity ? */ + if (t_type == task_type_self && t_subtype == task_subtype_external_grav) { + +#ifdef SWIFT_DEBUG_CHECKS + if (ci_nodeID != nodeID) error("Non-local self task"); +#endif + + /* drift -----> gravity --> end_force */ + scheduler_addunlock(sched, ci->grav.super->grav.drift, t); + scheduler_addunlock(sched, t, ci->super->end_force); + } + + /* Otherwise, pair interaction? */ + else if (t_type == task_type_pair && t_subtype == task_subtype_grav) { + + if (ci_nodeID == nodeID) { + + /* drift ---+-> gravity --> grav_down */ + /* init --/ */ + scheduler_addunlock(sched, ci->grav.super->grav.drift, t); + scheduler_addunlock(sched, ci_parent->grav.init_out, t); + scheduler_addunlock(sched, t, ci_parent->grav.down_in); + } + if (cj_nodeID == nodeID) { + + /* drift ---+-> gravity --> grav_down */ + /* init --/ */ + if (ci->grav.super != cj->grav.super) /* Avoid double unlock */ + scheduler_addunlock(sched, cj->grav.super->grav.drift, t); + + if (ci_parent != cj_parent) { /* Avoid double unlock */ + scheduler_addunlock(sched, cj_parent->grav.init_out, t); + scheduler_addunlock(sched, t, cj_parent->grav.down_in); + } + } + } + + /* Otherwise, sub-self interaction? */ + else if (t_type == task_type_sub_self && t_subtype == task_subtype_grav) { + +#ifdef SWIFT_DEBUG_CHECKS + if (ci_nodeID != nodeID) error("Non-local sub-self task"); +#endif + /* drift ---+-> gravity --> grav_down */ + /* init --/ */ + scheduler_addunlock(sched, ci->grav.super->grav.drift, t); + scheduler_addunlock(sched, ci_parent->grav.init_out, t); + scheduler_addunlock(sched, t, ci_parent->grav.down_in); + } + + /* Sub-self-interaction for external gravity ? */ + else if (t_type == task_type_sub_self && + t_subtype == task_subtype_external_grav) { + +#ifdef SWIFT_DEBUG_CHECKS + if (ci_nodeID != nodeID) error("Non-local sub-self task"); +#endif + + /* drift -----> gravity --> end_force */ + scheduler_addunlock(sched, ci->grav.super->grav.drift, t); + scheduler_addunlock(sched, t, ci->super->end_force); + } + + /* Otherwise, sub-pair interaction? */ + else if (t_type == task_type_sub_pair && t_subtype == task_subtype_grav) { + + if (ci_nodeID == nodeID) { + + /* drift ---+-> gravity --> grav_down */ + /* init --/ */ + scheduler_addunlock(sched, ci->grav.super->grav.drift, t); + scheduler_addunlock(sched, ci_parent->grav.init_out, t); + scheduler_addunlock(sched, t, ci_parent->grav.down_in); + } + if (cj_nodeID == nodeID) { + + /* drift ---+-> gravity --> grav_down */ + /* init --/ */ + if (ci->grav.super != cj->grav.super) /* Avoid double unlock */ + scheduler_addunlock(sched, cj->grav.super->grav.drift, t); + + if (ci_parent != cj_parent) { /* Avoid double unlock */ + scheduler_addunlock(sched, cj_parent->grav.init_out, t); + scheduler_addunlock(sched, t, cj_parent->grav.down_in); + } + } + } + + /* Otherwise M-M interaction? */ + else if (t_type == task_type_grav_mm) { + + if (ci_nodeID == nodeID) { + + /* init -----> gravity --> grav_down */ + scheduler_addunlock(sched, ci_parent->grav.init_out, t); + scheduler_addunlock(sched, t, ci_parent->grav.down_in); + } + if (cj_nodeID == nodeID) { + + /* init -----> gravity --> grav_down */ + if (ci_parent != cj_parent) { /* Avoid double unlock */ + scheduler_addunlock(sched, cj_parent->grav.init_out, t); + scheduler_addunlock(sched, t, cj_parent->grav.down_in); + } + } + } + } +} + +#ifdef EXTRA_HYDRO_LOOP + +/** + * @brief Creates the dependency network for the hydro tasks of a given cell. + * + * @param sched The #scheduler. + * @param density The density task to link. + * @param gradient The gradient task to link. + * @param force The force task to link. + * @param c The cell. + * @param with_cooling Do we have a cooling task ? + */ +static inline void engine_make_hydro_loops_dependencies( + struct scheduler *sched, struct task *density, struct task *gradient, + struct task *force, struct cell *c, int with_cooling) { + + /* density loop --> ghost --> gradient loop --> extra_ghost */ + /* extra_ghost --> force loop */ + scheduler_addunlock(sched, density, c->hydro.super->hydro.ghost_in); + scheduler_addunlock(sched, c->hydro.super->hydro.ghost_out, gradient); + scheduler_addunlock(sched, gradient, c->hydro.super->hydro.extra_ghost); + scheduler_addunlock(sched, c->hydro.super->hydro.extra_ghost, force); +} + +#else + +/** + * @brief Creates the dependency network for the hydro tasks of a given cell. + * + * @param sched The #scheduler. + * @param density The density task to link. + * @param force The force task to link. + * @param c The cell. + * @param with_cooling Are we running with cooling switched on ? + */ +static inline void engine_make_hydro_loops_dependencies(struct scheduler *sched, + struct task *density, + struct task *force, + struct cell *c, + int with_cooling) { + /* density loop --> ghost --> force loop */ + scheduler_addunlock(sched, density, c->hydro.super->hydro.ghost_in); + scheduler_addunlock(sched, c->hydro.super->hydro.ghost_out, force); +} + +#endif +/** + * @brief Creates the dependency network for the stars tasks of a given cell. + * + * @param sched The #scheduler. + * @param density The density task to link. + * @param c The cell. + */ +static inline void engine_make_stars_loops_dependencies(struct scheduler *sched, + struct task *density, + struct cell *c) { + /* density loop --> ghost */ + scheduler_addunlock(sched, density, c->super->stars.ghost_in); +} + +/** + * @brief Duplicates the first hydro loop and construct all the + * dependencies for the hydro part + * + * This is done by looping over all the previously constructed tasks + * and adding another task involving the same cells but this time + * corresponding to the second hydro loop over neighbours. + * With all the relevant tasks for a given cell available, we construct + * all the dependencies for that cell. + */ +void engine_make_extra_hydroloop_tasks_mapper(void *map_data, int num_elements, + void *extra_data) { + + struct engine *e = (struct engine *)extra_data; + struct scheduler *sched = &e->sched; + const int nodeID = e->nodeID; + const int with_cooling = (e->policy & engine_policy_cooling); + + for (int ind = 0; ind < num_elements; ind++) { + struct task *t = &((struct task *)map_data)[ind]; + + /* Sort tasks depend on the drift of the cell. */ + if (t->type == task_type_sort && t->ci->nodeID == engine_rank) { + scheduler_addunlock(sched, t->ci->hydro.super->hydro.drift, t); + } + + /* Self-interaction? */ + else if (t->type == task_type_self && t->subtype == task_subtype_density) { + + /* Make the self-density tasks depend on the drift only. */ + scheduler_addunlock(sched, t->ci->hydro.super->hydro.drift, t); + +#ifdef EXTRA_HYDRO_LOOP + /* Start by constructing the task for the second and third hydro loop. */ + struct task *t2 = scheduler_addtask( + sched, task_type_self, task_subtype_gradient, 0, 0, t->ci, NULL); + struct task *t3 = scheduler_addtask( + sched, task_type_self, task_subtype_force, 0, 0, t->ci, NULL); + + /* Add the link between the new loops and the cell */ + engine_addlink(e, &t->ci->hydro.gradient, t2); + engine_addlink(e, &t->ci->hydro.force, t3); + + /* Now, build all the dependencies for the hydro */ + engine_make_hydro_loops_dependencies(sched, t, t2, t3, t->ci, + with_cooling); + scheduler_addunlock(sched, t3, t->ci->super->end_force); +#else + + /* Start by constructing the task for the second hydro loop */ + struct task *t2 = scheduler_addtask( + sched, task_type_self, task_subtype_force, 0, 0, t->ci, NULL); + + /* Add the link between the new loop and the cell */ + engine_addlink(e, &t->ci->hydro.force, t2); + + /* Now, build all the dependencies for the hydro */ + engine_make_hydro_loops_dependencies(sched, t, t2, t->ci, with_cooling); + scheduler_addunlock(sched, t2, t->ci->super->end_force); +#endif + } + + /* Otherwise, pair interaction? */ + else if (t->type == task_type_pair && t->subtype == task_subtype_density) { + + /* Make all density tasks depend on the drift and the sorts. */ + if (t->ci->nodeID == engine_rank) + scheduler_addunlock(sched, t->ci->hydro.super->hydro.drift, t); + scheduler_addunlock(sched, t->ci->hydro.super->hydro.sorts, t); + if (t->ci->hydro.super != t->cj->hydro.super) { + if (t->cj->nodeID == engine_rank) + scheduler_addunlock(sched, t->cj->hydro.super->hydro.drift, t); + scheduler_addunlock(sched, t->cj->hydro.super->hydro.sorts, t); + } + +#ifdef EXTRA_HYDRO_LOOP + /* Start by constructing the task for the second and third hydro loop */ + struct task *t2 = scheduler_addtask( + sched, task_type_pair, task_subtype_gradient, 0, 0, t->ci, t->cj); + struct task *t3 = scheduler_addtask( + sched, task_type_pair, task_subtype_force, 0, 0, t->ci, t->cj); + + /* Add the link between the new loop and both cells */ + engine_addlink(e, &t->ci->hydro.gradient, t2); + engine_addlink(e, &t->cj->hydro.gradient, t2); + engine_addlink(e, &t->ci->hydro.force, t3); + engine_addlink(e, &t->cj->hydro.force, t3); + + /* Now, build all the dependencies for the hydro for the cells */ + /* that are local and are not descendant of the same super_hydro-cells */ + if (t->ci->nodeID == nodeID) { + engine_make_hydro_loops_dependencies(sched, t, t2, t3, t->ci, + with_cooling); + scheduler_addunlock(sched, t3, t->ci->super->end_force); + } + if (t->cj->nodeID == nodeID) { + if (t->ci->hydro.super != t->cj->hydro.super) + engine_make_hydro_loops_dependencies(sched, t, t2, t3, t->cj, + with_cooling); + if (t->ci->super != t->cj->super) + scheduler_addunlock(sched, t3, t->cj->super->end_force); + } + +#else + + /* Start by constructing the task for the second hydro loop */ + struct task *t2 = scheduler_addtask( + sched, task_type_pair, task_subtype_force, 0, 0, t->ci, t->cj); + + /* Add the link between the new loop and both cells */ + engine_addlink(e, &t->ci->hydro.force, t2); + engine_addlink(e, &t->cj->hydro.force, t2); + + /* Now, build all the dependencies for the hydro for the cells */ + /* that are local and are not descendant of the same super_hydro-cells */ + if (t->ci->nodeID == nodeID) { + engine_make_hydro_loops_dependencies(sched, t, t2, t->ci, with_cooling); + scheduler_addunlock(sched, t2, t->ci->super->end_force); + } + if (t->cj->nodeID == nodeID) { + if (t->ci->hydro.super != t->cj->hydro.super) + engine_make_hydro_loops_dependencies(sched, t, t2, t->cj, + with_cooling); + if (t->ci->super != t->cj->super) + scheduler_addunlock(sched, t2, t->cj->super->end_force); + } + +#endif + + } + + /* Otherwise, sub-self interaction? */ + else if (t->type == task_type_sub_self && + t->subtype == task_subtype_density) { + + /* Make all density tasks depend on the drift and sorts. */ + scheduler_addunlock(sched, t->ci->hydro.super->hydro.drift, t); + scheduler_addunlock(sched, t->ci->hydro.super->hydro.sorts, t); + +#ifdef EXTRA_HYDRO_LOOP + + /* Start by constructing the task for the second and third hydro loop */ + struct task *t2 = + scheduler_addtask(sched, task_type_sub_self, task_subtype_gradient, + t->flags, 0, t->ci, t->cj); + struct task *t3 = + scheduler_addtask(sched, task_type_sub_self, task_subtype_force, + t->flags, 0, t->ci, t->cj); + + /* Add the link between the new loop and the cell */ + engine_addlink(e, &t->ci->hydro.gradient, t2); + engine_addlink(e, &t->ci->hydro.force, t3); + + /* Now, build all the dependencies for the hydro for the cells */ + /* that are local and are not descendant of the same super_hydro-cells */ + if (t->ci->nodeID == nodeID) { + engine_make_hydro_loops_dependencies(sched, t, t2, t3, t->ci, + with_cooling); + scheduler_addunlock(sched, t3, t->ci->super->end_force); + } + +#else + /* Start by constructing the task for the second hydro loop */ + struct task *t2 = + scheduler_addtask(sched, task_type_sub_self, task_subtype_force, + t->flags, 0, t->ci, t->cj); + + /* Add the link between the new loop and the cell */ + engine_addlink(e, &t->ci->hydro.force, t2); + + /* Now, build all the dependencies for the hydro for the cells */ + /* that are local and are not descendant of the same super_hydro-cells */ + if (t->ci->nodeID == nodeID) { + engine_make_hydro_loops_dependencies(sched, t, t2, t->ci, with_cooling); + scheduler_addunlock(sched, t2, t->ci->super->end_force); + } +#endif + } + + /* Otherwise, sub-pair interaction? */ + else if (t->type == task_type_sub_pair && + t->subtype == task_subtype_density) { + + /* Make all density tasks depend on the drift. */ + if (t->ci->nodeID == engine_rank) + scheduler_addunlock(sched, t->ci->hydro.super->hydro.drift, t); + scheduler_addunlock(sched, t->ci->hydro.super->hydro.sorts, t); + if (t->ci->hydro.super != t->cj->hydro.super) { + if (t->cj->nodeID == engine_rank) + scheduler_addunlock(sched, t->cj->hydro.super->hydro.drift, t); + scheduler_addunlock(sched, t->cj->hydro.super->hydro.sorts, t); + } + +#ifdef EXTRA_HYDRO_LOOP + + /* Start by constructing the task for the second and third hydro loop */ + struct task *t2 = + scheduler_addtask(sched, task_type_sub_pair, task_subtype_gradient, + t->flags, 0, t->ci, t->cj); + struct task *t3 = + scheduler_addtask(sched, task_type_sub_pair, task_subtype_force, + t->flags, 0, t->ci, t->cj); + + /* Add the link between the new loop and both cells */ + engine_addlink(e, &t->ci->hydro.gradient, t2); + engine_addlink(e, &t->cj->hydro.gradient, t2); + engine_addlink(e, &t->ci->hydro.force, t3); + engine_addlink(e, &t->cj->hydro.force, t3); + + /* Now, build all the dependencies for the hydro for the cells */ + /* that are local and are not descendant of the same super_hydro-cells */ + if (t->ci->nodeID == nodeID) { + engine_make_hydro_loops_dependencies(sched, t, t2, t3, t->ci, + with_cooling); + scheduler_addunlock(sched, t3, t->ci->super->end_force); + } + if (t->cj->nodeID == nodeID) { + if (t->ci->hydro.super != t->cj->hydro.super) + engine_make_hydro_loops_dependencies(sched, t, t2, t3, t->cj, + with_cooling); + if (t->ci->super != t->cj->super) + scheduler_addunlock(sched, t3, t->cj->super->end_force); + } + +#else + /* Start by constructing the task for the second hydro loop */ + struct task *t2 = + scheduler_addtask(sched, task_type_sub_pair, task_subtype_force, + t->flags, 0, t->ci, t->cj); + + /* Add the link between the new loop and both cells */ + engine_addlink(e, &t->ci->hydro.force, t2); + engine_addlink(e, &t->cj->hydro.force, t2); + + /* Now, build all the dependencies for the hydro for the cells */ + /* that are local and are not descendant of the same super_hydro-cells */ + if (t->ci->nodeID == nodeID) { + engine_make_hydro_loops_dependencies(sched, t, t2, t->ci, with_cooling); + scheduler_addunlock(sched, t2, t->ci->super->end_force); + } + if (t->cj->nodeID == nodeID) { + if (t->ci->hydro.super != t->cj->hydro.super) + engine_make_hydro_loops_dependencies(sched, t, t2, t->cj, + with_cooling); + if (t->ci->super != t->cj->super) + scheduler_addunlock(sched, t2, t->cj->super->end_force); + } +#endif + } + } +} + +/** + * @brief Creates all the task dependencies for the stars + * + * @param map_data The tasks + * @param num_elements number of tasks + * @param extra_data The #engine + */ +void engine_link_stars_tasks_mapper(void *map_data, int num_elements, + void *extra_data) { + + struct engine *e = (struct engine *)extra_data; + struct scheduler *sched = &e->sched; + const int nodeID = e->nodeID; + + for (int ind = 0; ind < num_elements; ind++) { + struct task *t = &((struct task *)map_data)[ind]; + + /* Self-interaction? */ + if (t->type == task_type_self && t->subtype == task_subtype_stars_density) { + + /* Make the self-density tasks depend on the drifts. */ + scheduler_addunlock(sched, t->ci->super->hydro.drift, t); + + scheduler_addunlock(sched, t->ci->super->grav.drift, t); + + /* Now, build all the dependencies for the stars */ + engine_make_stars_loops_dependencies(sched, t, t->ci); + if (t->ci == t->ci->super) + scheduler_addunlock(sched, t->ci->super->stars.ghost_out, + t->ci->super->end_force); + } + + /* Otherwise, pair interaction? */ + else if (t->type == task_type_pair && + t->subtype == task_subtype_stars_density) { + + /* Make all density tasks depend on the drift and the sorts. */ + if (t->ci->nodeID == engine_rank) + scheduler_addunlock(sched, t->ci->super->hydro.drift, t); + scheduler_addunlock(sched, t->ci->super->hydro.sorts, t); + if (t->ci->super != t->cj->super) { + if (t->cj->nodeID == engine_rank) + scheduler_addunlock(sched, t->cj->super->hydro.drift, t); + scheduler_addunlock(sched, t->cj->super->hydro.sorts, t); + } + + /* Now, build all the dependencies for the stars for the cells */ + /* that are local and are not descendant of the same super-cells */ + if (t->ci->nodeID == nodeID) { + engine_make_stars_loops_dependencies(sched, t, t->ci); + } + if (t->cj->nodeID == nodeID) { + if (t->ci->super != t->cj->super) + engine_make_stars_loops_dependencies(sched, t, t->cj); + } + + } + + /* Otherwise, sub-self interaction? */ + else if (t->type == task_type_sub_self && + t->subtype == task_subtype_stars_density) { + + /* Make all density tasks depend on the drift and sorts. */ + scheduler_addunlock(sched, t->ci->super->hydro.drift, t); + scheduler_addunlock(sched, t->ci->super->hydro.sorts, t); + + /* Now, build all the dependencies for the stars for the cells */ + /* that are local and are not descendant of the same super-cells */ + if (t->ci->nodeID == nodeID) { + engine_make_stars_loops_dependencies(sched, t, t->ci); + } else + error("oo"); + } + + /* Otherwise, sub-pair interaction? */ + else if (t->type == task_type_sub_pair && + t->subtype == task_subtype_stars_density) { + + /* Make all density tasks depend on the drift. */ + if (t->ci->nodeID == engine_rank) + scheduler_addunlock(sched, t->ci->super->hydro.drift, t); + scheduler_addunlock(sched, t->ci->super->hydro.sorts, t); + if (t->ci->super != t->cj->super) { + if (t->cj->nodeID == engine_rank) + scheduler_addunlock(sched, t->cj->super->hydro.drift, t); + scheduler_addunlock(sched, t->cj->super->hydro.sorts, t); + } + + /* Now, build all the dependencies for the stars for the cells */ + /* that are local and are not descendant of the same super-cells */ + if (t->ci->nodeID == nodeID) { + engine_make_stars_loops_dependencies(sched, t, t->ci); + } + if (t->cj->nodeID == nodeID) { + if (t->ci->super != t->cj->super) + engine_make_stars_loops_dependencies(sched, t, t->cj); + } + } + } +} + +/** + * @brief Constructs the top-level pair tasks for the star loop over + * neighbours + * + * Here we construct all the tasks for all possible neighbouring non-empty + * local cells in the hierarchy. No dependencies are being added thus far. + * Additional loop over neighbours can later be added by simply duplicating + * all the tasks created by this function. + * + * @param map_data Offset of first two indices disguised as a pointer. + * @param num_elements Number of cells to traverse. + * @param extra_data The #engine. + */ +void engine_make_starsloop_tasks_mapper(void *map_data, int num_elements, + void *extra_data) { + + /* Extract the engine pointer. */ + struct engine *e = (struct engine *)extra_data; + + struct space *s = e->s; + struct scheduler *sched = &e->sched; + const int nodeID = e->nodeID; + const int *cdim = s->cdim; + struct cell *cells = s->cells_top; + + /* Loop through the elements, which are just byte offsets from NULL. */ + for (int ind = 0; ind < num_elements; ind++) { + + /* Get the cell index. */ + const int cid = (size_t)(map_data) + ind; + const int i = cid / (cdim[1] * cdim[2]); + const int j = (cid / cdim[2]) % cdim[1]; + const int k = cid % cdim[2]; + + /* Get the cell */ + struct cell *ci = &cells[cid]; + + /* Skip cells without star particles */ + if (ci->stars.count == 0) continue; + + /* If the cells is local build a self-interaction */ + if (ci->nodeID == nodeID) + scheduler_addtask(sched, task_type_self, task_subtype_stars_density, 0, 0, + ci, NULL); + + /* Now loop over all the neighbours of this cell */ + for (int ii = -1; ii < 2; ii++) { + int iii = i + ii; + if (!s->periodic && (iii < 0 || iii >= cdim[0])) continue; + iii = (iii + cdim[0]) % cdim[0]; + for (int jj = -1; jj < 2; jj++) { + int jjj = j + jj; + if (!s->periodic && (jjj < 0 || jjj >= cdim[1])) continue; + jjj = (jjj + cdim[1]) % cdim[1]; + for (int kk = -1; kk < 2; kk++) { + int kkk = k + kk; + if (!s->periodic && (kkk < 0 || kkk >= cdim[2])) continue; + kkk = (kkk + cdim[2]) % cdim[2]; + + /* Get the neighbouring cell */ + const int cjd = cell_getid(cdim, iii, jjj, kkk); + struct cell *cj = &cells[cjd]; + + /* Is that neighbour local and does it have particles ? */ + if (cid >= cjd || cj->hydro.count == 0 || + (ci->nodeID != nodeID && cj->nodeID != nodeID)) + continue; + + /* Construct the pair task */ + const int sid = sortlistID[(kk + 1) + 3 * ((jj + 1) + 3 * (ii + 1))]; + scheduler_addtask(sched, task_type_pair, task_subtype_stars_density, + sid, 0, ci, cj); + } + } + } + } +} + +/** + * @brief Constructs the top-level pair tasks for the first hydro loop over + * neighbours + * + * Here we construct all the tasks for all possible neighbouring non-empty + * local cells in the hierarchy. No dependencies are being added thus far. + * Additional loop over neighbours can later be added by simply duplicating + * all the tasks created by this function. + * + * @param map_data Offset of first two indices disguised as a pointer. + * @param num_elements Number of cells to traverse. + * @param extra_data The #engine. + */ +void engine_make_hydroloop_tasks_mapper(void *map_data, int num_elements, + void *extra_data) { + + /* Extract the engine pointer. */ + struct engine *e = (struct engine *)extra_data; + + struct space *s = e->s; + struct scheduler *sched = &e->sched; + const int nodeID = e->nodeID; + const int *cdim = s->cdim; + struct cell *cells = s->cells_top; + + /* Loop through the elements, which are just byte offsets from NULL. */ + for (int ind = 0; ind < num_elements; ind++) { + + /* Get the cell index. */ + const int cid = (size_t)(map_data) + ind; + const int i = cid / (cdim[1] * cdim[2]); + const int j = (cid / cdim[2]) % cdim[1]; + const int k = cid % cdim[2]; + + /* Get the cell */ + struct cell *ci = &cells[cid]; + + /* Skip cells without hydro particles */ + if (ci->hydro.count == 0) continue; + + /* If the cells is local build a self-interaction */ + if (ci->nodeID == nodeID) + scheduler_addtask(sched, task_type_self, task_subtype_density, 0, 0, ci, + NULL); + + /* Now loop over all the neighbours of this cell */ + for (int ii = -1; ii < 2; ii++) { + int iii = i + ii; + if (!s->periodic && (iii < 0 || iii >= cdim[0])) continue; + iii = (iii + cdim[0]) % cdim[0]; + for (int jj = -1; jj < 2; jj++) { + int jjj = j + jj; + if (!s->periodic && (jjj < 0 || jjj >= cdim[1])) continue; + jjj = (jjj + cdim[1]) % cdim[1]; + for (int kk = -1; kk < 2; kk++) { + int kkk = k + kk; + if (!s->periodic && (kkk < 0 || kkk >= cdim[2])) continue; + kkk = (kkk + cdim[2]) % cdim[2]; + + /* Get the neighbouring cell */ + const int cjd = cell_getid(cdim, iii, jjj, kkk); + struct cell *cj = &cells[cjd]; + + /* Is that neighbour local and does it have particles ? */ + if (cid >= cjd || cj->hydro.count == 0 || + (ci->nodeID != nodeID && cj->nodeID != nodeID)) + continue; + + /* Construct the pair task */ + const int sid = sortlistID[(kk + 1) + 3 * ((jj + 1) + 3 * (ii + 1))]; + scheduler_addtask(sched, task_type_pair, task_subtype_density, sid, 0, + ci, cj); + } + } + } + } +} + +/** + * @brief Fill the #space's task list. + * + * @param e The #engine we are working with. + */ +void engine_maketasks(struct engine *e) { + + struct space *s = e->s; + struct scheduler *sched = &e->sched; + struct cell *cells = s->cells_top; + const int nr_cells = s->nr_cells; + const ticks tic = getticks(); + + /* Re-set the scheduler. */ + scheduler_reset(sched, engine_estimate_nr_tasks(e)); + + ticks tic2 = getticks(); + + /* Construct the first hydro loop over neighbours */ + if (e->policy & engine_policy_hydro) + threadpool_map(&e->threadpool, engine_make_hydroloop_tasks_mapper, NULL, + s->nr_cells, 1, 0, e); + + if (e->verbose) + message("Making hydro tasks took %.3f %s.", + clocks_from_ticks(getticks() - tic2), clocks_getunit()); + + tic2 = getticks(); + + /* Construct the stars hydro loop over neighbours */ + if (e->policy & engine_policy_feedback) { + threadpool_map(&e->threadpool, engine_make_starsloop_tasks_mapper, NULL, + s->nr_cells, 1, 0, e); + } + + /* Add the self gravity tasks. */ + if (e->policy & engine_policy_self_gravity) engine_make_self_gravity_tasks(e); + + if (e->verbose) + message("Making gravity tasks took %.3f %s.", + clocks_from_ticks(getticks() - tic2), clocks_getunit()); + + /* Add the external gravity tasks. */ + if (e->policy & engine_policy_external_gravity) + engine_make_external_gravity_tasks(e); + + if (e->sched.nr_tasks == 0 && (s->nr_gparts > 0 || s->nr_parts > 0)) + error("We have particles but no hydro or gravity tasks were created."); + + /* Free the old list of cell-task links. */ + if (e->links != NULL) free(e->links); + e->size_links = 0; + +/* The maximum number of links is the + * number of cells (s->tot_cells) times the number of neighbours (26) times + * the number of interaction types, so 26 * 2 (density, force) pairs + * and 2 (density, force) self. + */ +#ifdef EXTRA_HYDRO_LOOP + const size_t hydro_tasks_per_cell = 27 * 3; +#else + const size_t hydro_tasks_per_cell = 27 * 2; +#endif + const size_t self_grav_tasks_per_cell = 125; + const size_t ext_grav_tasks_per_cell = 1; + const size_t stars_tasks_per_cell = 15; + + if (e->policy & engine_policy_hydro) + e->size_links += s->tot_cells * hydro_tasks_per_cell; + if (e->policy & engine_policy_external_gravity) + e->size_links += s->tot_cells * ext_grav_tasks_per_cell; + if (e->policy & engine_policy_self_gravity) + e->size_links += s->tot_cells * self_grav_tasks_per_cell; + if (e->policy & engine_policy_stars) + e->size_links += s->tot_cells * stars_tasks_per_cell; + + /* Allocate the new link list */ + if ((e->links = (struct link *)malloc(sizeof(struct link) * e->size_links)) == + NULL) + error("Failed to allocate cell-task links."); + e->nr_links = 0; + + tic2 = getticks(); + + /* Split the tasks. */ + scheduler_splittasks(sched); + + if (e->verbose) + message("Splitting tasks took %.3f %s.", + clocks_from_ticks(getticks() - tic2), clocks_getunit()); + +#ifdef SWIFT_DEBUG_CHECKS + /* Verify that we are not left with invalid tasks */ + for (int i = 0; i < e->sched.nr_tasks; ++i) { + const struct task *t = &e->sched.tasks[i]; + if (t->ci == NULL && t->cj != NULL && !t->skip) error("Invalid task"); + } +#endif + + tic2 = getticks(); + + /* Count the number of tasks associated with each cell and + store the density tasks in each cell, and make each sort + depend on the sorts of its progeny. */ + threadpool_map(&e->threadpool, engine_count_and_link_tasks_mapper, + sched->tasks, sched->nr_tasks, sizeof(struct task), 0, e); + + if (e->verbose) + message("Counting and linking tasks took %.3f %s.", + clocks_from_ticks(getticks() - tic2), clocks_getunit()); + + tic2 = getticks(); + + /* Re-set the tag counter. MPI tags are defined for top-level cells in + * cell_set_super_mapper. */ +#ifdef WITH_MPI + cell_next_tag = 0; +#endif + + /* Now that the self/pair tasks are at the right level, set the super + * pointers. */ + threadpool_map(&e->threadpool, cell_set_super_mapper, cells, nr_cells, + sizeof(struct cell), 0, e); + + if (e->verbose) + message("Setting super-pointers took %.3f %s.", + clocks_from_ticks(getticks() - tic2), clocks_getunit()); + + /* Append hierarchical tasks to each cell. */ + threadpool_map(&e->threadpool, engine_make_hierarchical_tasks_mapper, cells, + nr_cells, sizeof(struct cell), 0, e); + + tic2 = getticks(); + + /* Run through the tasks and make force tasks for each density task. + Each force task depends on the cell ghosts and unlocks the kick task + of its super-cell. */ + if (e->policy & engine_policy_hydro) + threadpool_map(&e->threadpool, engine_make_extra_hydroloop_tasks_mapper, + sched->tasks, sched->nr_tasks, sizeof(struct task), 0, e); + + if (e->verbose) + message("Making extra hydroloop tasks took %.3f %s.", + clocks_from_ticks(getticks() - tic2), clocks_getunit()); + + tic2 = getticks(); + + /* Add the dependencies for the gravity stuff */ + if (e->policy & (engine_policy_self_gravity | engine_policy_external_gravity)) + engine_link_gravity_tasks(e); + + if (e->verbose) + message("Linking gravity tasks took %.3f %s.", + clocks_from_ticks(getticks() - tic2), clocks_getunit()); + + tic2 = getticks(); + + if (e->policy & engine_policy_stars) + threadpool_map(&e->threadpool, engine_link_stars_tasks_mapper, sched->tasks, + sched->nr_tasks, sizeof(struct task), 0, e); + + if (e->verbose) + message("Linking stars tasks took %.3f %s (including reweight).", + clocks_from_ticks(getticks() - tic2), clocks_getunit()); + +#ifdef WITH_MPI + if (e->policy & engine_policy_feedback) + error("Cannot run stellar feedback with MPI (yet)."); + + /* Add the communication tasks if MPI is being used. */ + if (e->policy & engine_policy_mpi) { + + tic2 = getticks(); + + /* Loop over the proxies and add the send tasks, which also generates the + * cell tags for super-cells. */ + for (int pid = 0; pid < e->nr_proxies; pid++) { + + /* Get a handle on the proxy. */ + struct proxy *p = &e->proxies[pid]; + + for (int k = 0; k < p->nr_cells_out; k++) + engine_addtasks_send_timestep(e, p->cells_out[k], p->cells_in[0], NULL); + + /* Loop through the proxy's outgoing cells and add the + send tasks for the cells in the proxy that have a hydro connection. */ + if (e->policy & engine_policy_hydro) + for (int k = 0; k < p->nr_cells_out; k++) + if (p->cells_out_type[k] & proxy_cell_type_hydro) + engine_addtasks_send_hydro(e, p->cells_out[k], p->cells_in[0], NULL, + NULL, NULL); + + /* Loop through the proxy's outgoing cells and add the + send tasks for the cells in the proxy that have a gravity connection. + */ + if (e->policy & engine_policy_self_gravity) + for (int k = 0; k < p->nr_cells_out; k++) + if (p->cells_out_type[k] & proxy_cell_type_gravity) + engine_addtasks_send_gravity(e, p->cells_out[k], p->cells_in[0], + NULL); + } + + if (e->verbose) + message("Creating send tasks took %.3f %s.", + clocks_from_ticks(getticks() - tic2), clocks_getunit()); + + tic2 = getticks(); + + /* Exchange the cell tags. */ + proxy_tags_exchange(e->proxies, e->nr_proxies, s); + + if (e->verbose) + message("Exchanging cell tags took %.3f %s.", + clocks_from_ticks(getticks() - tic2), clocks_getunit()); + + tic2 = getticks(); + + /* Loop over the proxies and add the recv tasks, which relies on having the + * cell tags. */ + for (int pid = 0; pid < e->nr_proxies; pid++) { + + /* Get a handle on the proxy. */ + struct proxy *p = &e->proxies[pid]; + + for (int k = 0; k < p->nr_cells_in; k++) + engine_addtasks_recv_timestep(e, p->cells_in[k], NULL); + + /* Loop through the proxy's incoming cells and add the + recv tasks for the cells in the proxy that have a hydro connection. */ + if (e->policy & engine_policy_hydro) + for (int k = 0; k < p->nr_cells_in; k++) + if (p->cells_in_type[k] & proxy_cell_type_hydro) + engine_addtasks_recv_hydro(e, p->cells_in[k], NULL, NULL, NULL); + + /* Loop through the proxy's incoming cells and add the + recv tasks for the cells in the proxy that have a gravity connection. + */ + if (e->policy & engine_policy_self_gravity) + for (int k = 0; k < p->nr_cells_in; k++) + if (p->cells_in_type[k] & proxy_cell_type_gravity) + engine_addtasks_recv_gravity(e, p->cells_in[k], NULL); + } + + if (e->verbose) + message("Creating recv tasks took %.3f %s.", + clocks_from_ticks(getticks() - tic2), clocks_getunit()); + } +#endif + + tic2 = getticks(); + + /* Set the unlocks per task. */ + scheduler_set_unlocks(sched); + + if (e->verbose) + message("Setting unlocks took %.3f %s.", + clocks_from_ticks(getticks() - tic2), clocks_getunit()); + + tic2 = getticks(); + + /* Rank the tasks. */ + scheduler_ranktasks(sched); + + if (e->verbose) + message("Ranking the tasks took %.3f %s.", + clocks_from_ticks(getticks() - tic2), clocks_getunit()); + + /* Weight the tasks. */ + scheduler_reweight(sched, e->verbose); + + /* Set the tasks age. */ + e->tasks_age = 0; + + if (e->verbose) + message("took %.3f %s (including reweight).", + clocks_from_ticks(getticks() - tic), clocks_getunit()); +} diff --git a/src/engine_marktasks.c b/src/engine_marktasks.c new file mode 100644 index 0000000000000000000000000000000000000000..c891fb2ca7aa66538adbbb8e1fd694f3af6acf07 --- /dev/null +++ b/src/engine_marktasks.c @@ -0,0 +1,552 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2012 Pedro Gonnet (pedro.gonnet@durham.ac.uk) + * Matthieu Schaller (matthieu.schaller@durham.ac.uk) + * 2015 Peter W. Draper (p.w.draper@durham.ac.uk) + * Angus Lepper (angus.lepper@ed.ac.uk) + * 2016 John A. Regan (john.a.regan@durham.ac.uk) + * 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" + +/* Some standard headers. */ +#include <stdlib.h> +#include <unistd.h> + +/* MPI headers. */ +#ifdef WITH_MPI +#include <mpi.h> +#endif + +/* Load the profiler header, if needed. */ +#ifdef WITH_PROFILER +#include <gperftools/profiler.h> +#endif + +/* This object's header. */ +#include "engine.h" + +/* Local headers. */ +#include "active.h" +#include "atomic.h" +#include "cell.h" +#include "clocks.h" +#include "cycle.h" +#include "debug.h" +#include "error.h" +#include "proxy.h" +#include "timers.h" + +/** + * @brief Mark tasks to be un-skipped and set the sort flags accordingly. + * Threadpool mapper function. + * + * @param map_data pointer to the tasks + * @param num_elements number of tasks + * @param extra_data pointer to int that will define if a rebuild is needed. + */ +void engine_marktasks_mapper(void *map_data, int num_elements, + void *extra_data) { + /* Unpack the arguments. */ + struct task *tasks = (struct task *)map_data; + size_t *rebuild_space = &((size_t *)extra_data)[1]; + struct scheduler *s = (struct scheduler *)(((size_t *)extra_data)[2]); + struct engine *e = (struct engine *)((size_t *)extra_data)[0]; + const int nodeID = e->nodeID; + + for (int ind = 0; ind < num_elements; ind++) { + + /* Get basic task information */ + struct task *t = &tasks[ind]; + const enum task_types t_type = t->type; + const enum task_subtypes t_subtype = t->subtype; + + /* Single-cell task? */ + if (t_type == task_type_self || t_type == task_type_sub_self) { + + /* Local pointer. */ + struct cell *ci = t->ci; + + if (ci->nodeID != engine_rank) error("Non-local self task found"); + + /* Activate the hydro drift */ + if (t_type == task_type_self && t_subtype == task_subtype_density) { + if (cell_is_active_hydro(ci, e)) { + scheduler_activate(s, t); + cell_activate_drift_part(ci, s); + } + } + + /* Store current values of dx_max and h_max. */ + else if (t_type == task_type_sub_self && + t_subtype == task_subtype_density) { + if (cell_is_active_hydro(ci, e)) { + scheduler_activate(s, t); + cell_activate_subcell_hydro_tasks(ci, NULL, s); + } + } + + else if (t_type == task_type_self && t_subtype == task_subtype_force) { + if (cell_is_active_hydro(ci, e)) scheduler_activate(s, t); + } + + else if (t_type == task_type_sub_self && + t_subtype == task_subtype_force) { + if (cell_is_active_hydro(ci, e)) scheduler_activate(s, t); + } + +#ifdef EXTRA_HYDRO_LOOP + else if (t_type == task_type_self && t_subtype == task_subtype_gradient) { + if (cell_is_active_hydro(ci, e)) scheduler_activate(s, t); + } + + else if (t_type == task_type_sub_self && + t_subtype == task_subtype_gradient) { + if (cell_is_active_hydro(ci, e)) scheduler_activate(s, t); + } +#endif + + /* Activate the star density */ + else if (t_type == task_type_self && + t_subtype == task_subtype_stars_density) { + if (cell_is_active_stars(ci, e)) { + scheduler_activate(s, t); + cell_activate_drift_part(ci, s); + cell_activate_drift_gpart(ci, s); + } + } + + /* Store current values of dx_max and h_max. */ + else if (t_type == task_type_sub_self && + t_subtype == task_subtype_stars_density) { + if (cell_is_active_stars(ci, e)) { + scheduler_activate(s, t); + cell_activate_subcell_stars_tasks(ci, NULL, s); + } + } + + /* Activate the gravity drift */ + else if (t_type == task_type_self && t_subtype == task_subtype_grav) { + if (cell_is_active_gravity(ci, e)) { + scheduler_activate(s, t); + cell_activate_subcell_grav_tasks(t->ci, NULL, s); + } + } + + /* Activate the gravity drift */ + else if (t_type == task_type_self && + t_subtype == task_subtype_external_grav) { + if (cell_is_active_gravity(ci, e)) { + scheduler_activate(s, t); + cell_activate_drift_gpart(t->ci, s); + } + } + +#ifdef SWIFT_DEBUG_CHECKS + else { + error("Invalid task type / sub-type encountered"); + } +#endif + } + + /* Pair? */ + else if (t_type == task_type_pair || t_type == task_type_sub_pair) { + + /* Local pointers. */ + struct cell *ci = t->ci; + struct cell *cj = t->cj; +#ifdef WITH_MPI + const int ci_nodeID = ci->nodeID; + const int cj_nodeID = cj->nodeID; +#else + const int ci_nodeID = nodeID; + const int cj_nodeID = nodeID; +#endif + const int ci_active_hydro = cell_is_active_hydro(ci, e); + const int cj_active_hydro = cell_is_active_hydro(cj, e); + const int ci_active_gravity = cell_is_active_gravity(ci, e); + const int cj_active_gravity = cell_is_active_gravity(cj, e); + const int ci_active_stars = cell_is_active_stars(ci, e); + const int cj_active_stars = cell_is_active_stars(cj, e); + + /* Only activate tasks that involve a local active cell. */ + if ((t_subtype == task_subtype_density || + t_subtype == task_subtype_gradient || + t_subtype == task_subtype_force) && + ((ci_active_hydro && ci_nodeID == nodeID) || + (cj_active_hydro && cj_nodeID == nodeID))) { + + scheduler_activate(s, t); + + /* Set the correct sorting flags */ + if (t_type == task_type_pair && + (t_subtype == task_subtype_density || + t_subtype == task_subtype_stars_density)) { + + /* Store some values. */ + atomic_or(&ci->hydro.requires_sorts, 1 << t->flags); + atomic_or(&cj->hydro.requires_sorts, 1 << t->flags); + ci->hydro.dx_max_sort_old = ci->hydro.dx_max_sort; + cj->hydro.dx_max_sort_old = cj->hydro.dx_max_sort; + + /* Activate the hydro drift tasks. */ + if (ci_nodeID == nodeID) cell_activate_drift_part(ci, s); + if (cj_nodeID == nodeID) cell_activate_drift_part(cj, s); + + /* Check the sorts and activate them if needed. */ + cell_activate_sorts(ci, t->flags, s); + cell_activate_sorts(cj, t->flags, s); + + } + + /* Store current values of dx_max and h_max. */ + else if (t_type == task_type_sub_pair && + (t_subtype == task_subtype_density || + t_subtype == task_subtype_stars_density)) { + cell_activate_subcell_hydro_tasks(t->ci, t->cj, s); + } + } + + /* Stars */ + if (t_subtype == task_subtype_stars_density && + ((ci_active_stars && ci->nodeID == engine_rank) || + (cj_active_stars && cj->nodeID == engine_rank))) { + + scheduler_activate(s, t); + + /* Set the correct sorting flags */ + if (t_type == task_type_pair) { + + /* Store some values. */ + atomic_or(&ci->hydro.requires_sorts, 1 << t->flags); + atomic_or(&cj->hydro.requires_sorts, 1 << t->flags); + ci->hydro.dx_max_sort_old = ci->hydro.dx_max_sort; + cj->hydro.dx_max_sort_old = cj->hydro.dx_max_sort; + + /* Activate the hydro drift tasks. */ + if (ci_nodeID == nodeID) { + cell_activate_drift_part(ci, s); + cell_activate_drift_gpart(ci, s); + } + if (cj_nodeID == nodeID) { + cell_activate_drift_part(cj, s); + cell_activate_drift_gpart(cj, s); + } + + /* Check the sorts and activate them if needed. */ + cell_activate_sorts(ci, t->flags, s); + cell_activate_sorts(cj, t->flags, s); + + } + + /* Store current values of dx_max and h_max. */ + else if (t_type == task_type_sub_pair) { + cell_activate_subcell_stars_tasks(t->ci, t->cj, s); + } + } + + if ((t_subtype == task_subtype_grav) && + ((ci_active_gravity && ci_nodeID == nodeID) || + (cj_active_gravity && cj_nodeID == nodeID))) { + + scheduler_activate(s, t); + + if (t_type == task_type_pair && t_subtype == task_subtype_grav) { + /* Activate the gravity drift */ + cell_activate_subcell_grav_tasks(t->ci, t->cj, s); + } + +#ifdef SWIFT_DEBUG_CHECKS + else if (t_type == task_type_sub_pair && + t_subtype == task_subtype_grav) { + error("Invalid task sub-type encountered"); + } +#endif + } + + /* Only interested in density tasks as of here. */ + if (t_subtype == task_subtype_density) { + + /* Too much particle movement? */ + if (cell_need_rebuild_for_pair(ci, cj)) *rebuild_space = 1; + +#ifdef WITH_MPI + /* Activate the send/recv tasks. */ + if (ci_nodeID != nodeID) { + + /* If the local cell is active, receive data from the foreign cell. */ + if (cj_active_hydro) { + scheduler_activate(s, ci->mpi.hydro.recv_xv); + if (ci_active_hydro) { + scheduler_activate(s, ci->mpi.hydro.recv_rho); +#ifdef EXTRA_HYDRO_LOOP + scheduler_activate(s, ci->mpi.hydro.recv_gradient); +#endif + } + } + + /* If the foreign cell is active, we want its ti_end values. */ + if (ci_active_hydro) scheduler_activate(s, ci->mpi.recv_ti); + + /* Is the foreign cell active and will need stuff from us? */ + if (ci_active_hydro) { + + struct link *l = + scheduler_activate_send(s, cj->mpi.hydro.send_xv, ci_nodeID); + + /* Drift the cell which will be sent at the level at which it is + sent, i.e. drift the cell specified in the send task (l->t) + itself. */ + cell_activate_drift_part(l->t->ci, s); + + /* If the local cell is also active, more stuff will be needed. */ + if (cj_active_hydro) { + scheduler_activate_send(s, cj->mpi.hydro.send_rho, ci_nodeID); + +#ifdef EXTRA_HYDRO_LOOP + scheduler_activate_send(s, cj->mpi.hydro.send_gradient, + ci_nodeID); +#endif + } + } + + /* If the local cell is active, send its ti_end values. */ + if (cj_active_hydro) + scheduler_activate_send(s, cj->mpi.send_ti, ci_nodeID); + + } else if (cj_nodeID != nodeID) { + + /* If the local cell is active, receive data from the foreign cell. */ + if (ci_active_hydro) { + scheduler_activate(s, cj->mpi.hydro.recv_xv); + if (cj_active_hydro) { + scheduler_activate(s, cj->mpi.hydro.recv_rho); +#ifdef EXTRA_HYDRO_LOOP + scheduler_activate(s, cj->mpi.hydro.recv_gradient); +#endif + } + } + + /* If the foreign cell is active, we want its ti_end values. */ + if (cj_active_hydro) scheduler_activate(s, cj->mpi.recv_ti); + + /* Is the foreign cell active and will need stuff from us? */ + if (cj_active_hydro) { + + struct link *l = + scheduler_activate_send(s, ci->mpi.hydro.send_xv, cj_nodeID); + + /* Drift the cell which will be sent at the level at which it is + sent, i.e. drift the cell specified in the send task (l->t) + itself. */ + cell_activate_drift_part(l->t->ci, s); + + /* If the local cell is also active, more stuff will be needed. */ + if (ci_active_hydro) { + + scheduler_activate_send(s, ci->mpi.hydro.send_rho, cj_nodeID); + +#ifdef EXTRA_HYDRO_LOOP + scheduler_activate_send(s, ci->mpi.hydro.send_gradient, + cj_nodeID); +#endif + } + } + + /* If the local cell is active, send its ti_end values. */ + if (ci_active_hydro) + scheduler_activate_send(s, ci->mpi.send_ti, cj_nodeID); + } +#endif + } + + /* Only interested in stars_density tasks as of here. */ + if (t->subtype == task_subtype_stars_density) { + + /* Too much particle movement? */ + if (cell_need_rebuild_for_pair(ci, cj)) *rebuild_space = 1; + + // LOIC: Need implementing MPI case + } + + /* Only interested in gravity tasks as of here. */ + if (t_subtype == task_subtype_grav) { + +#ifdef WITH_MPI + /* Activate the send/recv tasks. */ + if (ci_nodeID != nodeID) { + + /* If the local cell is active, receive data from the foreign cell. */ + if (cj_active_gravity) scheduler_activate(s, ci->mpi.grav.recv); + + /* If the foreign cell is active, we want its ti_end values. */ + if (ci_active_gravity) scheduler_activate(s, ci->mpi.recv_ti); + + /* Is the foreign cell active and will need stuff from us? */ + if (ci_active_gravity) { + + struct link *l = + scheduler_activate_send(s, cj->mpi.grav.send, ci_nodeID); + + /* Drift the cell which will be sent at the level at which it is + sent, i.e. drift the cell specified in the send task (l->t) + itself. */ + cell_activate_drift_gpart(l->t->ci, s); + } + + /* If the local cell is active, send its ti_end values. */ + if (cj_active_gravity) + scheduler_activate_send(s, cj->mpi.send_ti, ci_nodeID); + + } else if (cj_nodeID != nodeID) { + + /* If the local cell is active, receive data from the foreign cell. */ + if (ci_active_gravity) scheduler_activate(s, cj->mpi.grav.recv); + + /* If the foreign cell is active, we want its ti_end values. */ + if (cj_active_gravity) scheduler_activate(s, cj->mpi.recv_ti); + + /* Is the foreign cell active and will need stuff from us? */ + if (cj_active_gravity) { + + struct link *l = + scheduler_activate_send(s, ci->mpi.grav.send, cj_nodeID); + + /* Drift the cell which will be sent at the level at which it is + sent, i.e. drift the cell specified in the send task (l->t) + itself. */ + cell_activate_drift_gpart(l->t->ci, s); + } + + /* If the local cell is active, send its ti_end values. */ + if (ci_active_gravity) + scheduler_activate_send(s, ci->mpi.send_ti, cj_nodeID); + } +#endif + } + } + + /* End force ? */ + else if (t_type == task_type_end_force) { + + if (cell_is_active_hydro(t->ci, e) || cell_is_active_gravity(t->ci, e)) + scheduler_activate(s, t); + } + + /* Kick ? */ + else if (t_type == task_type_kick1 || t_type == task_type_kick2) { + + if (cell_is_active_hydro(t->ci, e) || cell_is_active_gravity(t->ci, e)) + scheduler_activate(s, t); + } + + /* Hydro ghost tasks ? */ + else if (t_type == task_type_ghost || t_type == task_type_extra_ghost || + t_type == task_type_ghost_in || t_type == task_type_ghost_out) { + if (cell_is_active_hydro(t->ci, e)) scheduler_activate(s, t); + } + + /* logger tasks ? */ + else if (t->type == task_type_logger) { + if (cell_is_active_hydro(t->ci, e) || cell_is_active_gravity(t->ci, e) || + cell_is_active_stars(t->ci, e)) + scheduler_activate(s, t); + } + + /* Gravity stuff ? */ + else if (t_type == task_type_grav_down || t_type == task_type_grav_mesh || + t_type == task_type_grav_long_range || + t_type == task_type_init_grav || + t_type == task_type_init_grav_out || + t_type == task_type_grav_down_in) { + if (cell_is_active_gravity(t->ci, e)) scheduler_activate(s, t); + } + + /* Multipole - Multipole interaction task */ + else if (t_type == task_type_grav_mm) { + + /* Local pointers. */ + const struct cell *ci = t->ci; + const struct cell *cj = t->cj; +#ifdef WITH_MPI + const int ci_nodeID = ci->nodeID; + const int cj_nodeID = (cj != NULL) ? cj->nodeID : -1; +#else + const int ci_nodeID = nodeID; + const int cj_nodeID = nodeID; +#endif + const int ci_active_gravity = cell_is_active_gravity_mm(ci, e); + const int cj_active_gravity = cell_is_active_gravity_mm(cj, e); + + if ((ci_active_gravity && ci_nodeID == nodeID) || + (cj_active_gravity && cj_nodeID == nodeID)) + scheduler_activate(s, t); + } + + /* Star ghost tasks ? */ + else if (t_type == task_type_stars_ghost || + t_type == task_type_stars_ghost_in || + t_type == task_type_stars_ghost_out) { + if (cell_is_active_stars(t->ci, e)) scheduler_activate(s, t); + } + + /* Time-step? */ + else if (t_type == task_type_timestep) { + t->ci->hydro.updated = 0; + t->ci->grav.updated = 0; + t->ci->stars.updated = 0; + if (cell_is_active_hydro(t->ci, e) || cell_is_active_gravity(t->ci, e)) + scheduler_activate(s, t); + } + + /* Subgrid tasks */ + else if (t_type == task_type_cooling) { + if (cell_is_active_hydro(t->ci, e) || cell_is_active_gravity(t->ci, e)) + scheduler_activate(s, t); + } else if (t_type == task_type_star_formation) { + if (cell_is_active_hydro(t->ci, e) || cell_is_active_gravity(t->ci, e)) + scheduler_activate(s, t); + } + } +} + +/** + * @brief Mark tasks to be un-skipped and set the sort flags accordingly. + * + * @return 1 if the space has to be rebuilt, 0 otherwise. + */ +int engine_marktasks(struct engine *e) { + + struct scheduler *s = &e->sched; + const ticks tic = getticks(); + int rebuild_space = 0; + + /* Run through the tasks and mark as skip or not. */ + size_t extra_data[3] = {(size_t)e, (size_t)rebuild_space, (size_t)&e->sched}; + threadpool_map(&e->threadpool, engine_marktasks_mapper, s->tasks, s->nr_tasks, + sizeof(struct task), 0, extra_data); + rebuild_space = extra_data[1]; + + if (e->verbose) + message("took %.3f %s.", clocks_from_ticks(getticks() - tic), + clocks_getunit()); + + /* All is well... */ + return rebuild_space; +} diff --git a/src/equation_of_state/planetary/hm80.h b/src/equation_of_state/planetary/hm80.h index 5e80c240018756cb57cc8974df4974a6cc53724a..38e2c9e4022387ee5ab79fafbedc6fc0dc47f49d 100644 --- a/src/equation_of_state/planetary/hm80.h +++ b/src/equation_of_state/planetary/hm80.h @@ -86,21 +86,19 @@ INLINE static void load_table_HM80(struct HM80_params *mat, char *table_file) { // Load table contents from file FILE *f = fopen(table_file, "r"); - int c; + if (f == NULL) error("Failed to open the HM80 EoS file '%s'", table_file); // Ignore header lines char buffer[100]; for (int i = 0; i < 4; i++) { if (fgets(buffer, 100, f) == NULL) - error("Something incorrect happening with the file header."); + error("Failed to read the HM80 EoS file header %s", table_file); } // Table properties - c = fscanf(f, "%f %f %d %f %f %d", &mat->log_rho_min, &mat->log_rho_max, - &mat->num_rho, &mat->log_u_min, &mat->log_u_max, &mat->num_u); - if (c != 6) { - error("Failed to read EOS table %s", table_file); - } + int c = fscanf(f, "%f %f %d %f %f %d", &mat->log_rho_min, &mat->log_rho_max, + &mat->num_rho, &mat->log_u_min, &mat->log_u_max, &mat->num_u); + if (c != 6) error("Failed to read the HM80 EoS table %s", table_file); mat->log_rho_step = (mat->log_rho_max - mat->log_rho_min) / (mat->num_rho - 1); mat->log_u_step = (mat->log_u_max - mat->log_u_min) / (mat->num_u - 1); @@ -115,9 +113,7 @@ INLINE static void load_table_HM80(struct HM80_params *mat, char *table_file) { for (int i_rho = 0; i_rho < mat->num_rho; i_rho++) { for (int i_u = 0; i_u < mat->num_u; i_u++) { c = fscanf(f, "%f", &mat->table_log_P_rho_u[i_rho * mat->num_u + i_u]); - if (c != 1) { - error("Failed to read EOS table"); - } + if (c != 1) error("Failed to read the HM80 EoS table %s", table_file); } } fclose(f); diff --git a/src/equation_of_state/planetary/sesame.h b/src/equation_of_state/planetary/sesame.h index d958c9b9d09ffe37eefd77ad0384d85bf8c055dd..11c16964602b28c0d1a080b6c262ff20c1f5b9cb 100644 --- a/src/equation_of_state/planetary/sesame.h +++ b/src/equation_of_state/planetary/sesame.h @@ -82,21 +82,19 @@ INLINE static void load_table_SESAME(struct SESAME_params *mat, // Load table contents from file FILE *f = fopen(table_file, "r"); - int c; + if (f == NULL) error("Failed to open the SESAME EoS file '%s'", table_file); // Ignore header lines char buffer[100]; for (int i = 0; i < 5; i++) { if (fgets(buffer, 100, f) == NULL) - error("Something incorrect happening with the file header."); + error("Failed to read the SESAME EoS file header %s", table_file); } float ignore; // Table properties - c = fscanf(f, "%d %d", &mat->num_rho, &mat->num_T); - if (c != 2) { - error("Failed to read EOS table %s", table_file); - } + int c = fscanf(f, "%d %d", &mat->num_rho, &mat->num_T); + if (c != 2) error("Failed to read the SESAME EoS table %s", table_file); // Ignore the first elements of rho = 0, T = 0 mat->num_rho--; @@ -118,23 +116,17 @@ INLINE static void load_table_SESAME(struct SESAME_params *mat, // Ignore the first elements of rho = 0, T = 0 if (i_rho == -1) { c = fscanf(f, "%f", &ignore); - if (c != 1) { - error("Failed to read EOS table %s", table_file); - } + if (c != 1) error("Failed to read the SESAME EoS table %s", table_file); } else { c = fscanf(f, "%f", &mat->table_log_rho[i_rho]); - if (c != 1) { - error("Failed to read EOS table %s", table_file); - } + if (c != 1) error("Failed to read the SESAME EoS table %s", table_file); } } // Temperatures (ignored) for (int i_T = -1; i_T < mat->num_T; i_T++) { c = fscanf(f, "%f", &ignore); - if (c != 1) { - error("Failed to read EOS table %s", table_file); - } + if (c != 1) error("Failed to read the SESAME EoS table %s", table_file); } // Sp. int. energies (not log yet), pressures, sound speeds, and entropies @@ -143,18 +135,14 @@ INLINE static void load_table_SESAME(struct SESAME_params *mat, // Ignore the first elements of rho = 0, T = 0 if ((i_T == -1) || (i_rho == -1)) { c = fscanf(f, "%f %f %f %f", &ignore, &ignore, &ignore, &ignore); - if (c != 4) { - error("Failed to read EOS table %s", table_file); - } + if (c != 4) error("Failed to read the SESAME EoS table %s", table_file); } else { c = fscanf(f, "%f %f %f %f", &mat->table_log_u_rho_T[i_rho * mat->num_T + i_T], &mat->table_P_rho_T[i_rho * mat->num_T + i_T], &mat->table_c_rho_T[i_rho * mat->num_T + i_T], &mat->table_s_rho_T[i_rho * mat->num_T + i_T]); - if (c != 4) { - error("Failed to read EOS table %s", table_file); - } + if (c != 4) error("Failed to read the SESAME EoS table %s", table_file); } } } diff --git a/src/gravity/Default/gravity.h b/src/gravity/Default/gravity.h index 83decb0cfb189316018a465796de8377d8749bec..d446844e8ffc862fd3be0688302ebb3a2efab8fa 100644 --- a/src/gravity/Default/gravity.h +++ b/src/gravity/Default/gravity.h @@ -22,6 +22,7 @@ #include <float.h> +/* Local includes. */ #include "cosmology.h" #include "gravity_properties.h" #include "kernel_gravity.h" diff --git a/src/gravity_cache.h b/src/gravity_cache.h index 821f044429b445c28ff8ae39b8dc65304dd2b42d..6453d1eb92814f0e20cf25fa5996b920e523812d 100644 --- a/src/gravity_cache.h +++ b/src/gravity_cache.h @@ -208,12 +208,20 @@ __attribute__((always_inline)) INLINE static void gravity_cache_populate( /* Fill the input caches */ for (int i = 0; i < gcount; ++i) { + x[i] = (float)(gparts[i].x[0] - shift[0]); y[i] = (float)(gparts[i].x[1] - shift[1]); z[i] = (float)(gparts[i].x[2] - shift[2]); epsilon[i] = gravity_get_softening(&gparts[i], grav_props); - m[i] = gparts[i].mass; - active[i] = (int)(gparts[i].time_bin <= max_active_bin); + + /* Make a dummy particle out of the inhibted ones */ + if (gparts[i].time_bin == time_bin_inhibited) { + m[i] = 0.f; + active[i] = 0; + } else { + m[i] = gparts[i].mass; + active[i] = (int)(gparts[i].time_bin <= max_active_bin); + } /* Distance to the CoM of the other cell. */ float dx = x[i] - CoM[0]; @@ -294,8 +302,15 @@ gravity_cache_populate_no_mpole(const timebin_t max_active_bin, y[i] = (float)(gparts[i].x[1] - shift[1]); z[i] = (float)(gparts[i].x[2] - shift[2]); epsilon[i] = gravity_get_softening(&gparts[i], grav_props); - m[i] = gparts[i].mass; - active[i] = (int)(gparts[i].time_bin <= max_active_bin); + + /* Make a dummy particle out of the inhibted ones */ + if (gparts[i].time_bin == time_bin_inhibited) { + m[i] = 0.f; + active[i] = 0; + } else { + m[i] = gparts[i].mass; + active[i] = (int)(gparts[i].time_bin <= max_active_bin); + } } #ifdef SWIFT_DEBUG_CHECKS diff --git a/src/gravity_properties.c b/src/gravity_properties.c index 40cd7cecb10eab7ebbe7b59d34fb15dccac8b620..fffbf22ec187f179f0e80b7121beaa3a96de0260 100644 --- a/src/gravity_properties.c +++ b/src/gravity_properties.c @@ -39,7 +39,8 @@ #define gravity_props_default_rebuild_frequency 0.01f void gravity_props_init(struct gravity_props *p, struct swift_params *params, - const struct cosmology *cosmo, int with_cosmology) { + const struct cosmology *cosmo, int with_cosmology, + int periodic) { /* Tree updates */ p->rebuild_frequency = @@ -50,24 +51,31 @@ void gravity_props_init(struct gravity_props *p, struct swift_params *params, error("Invalid tree rebuild frequency. Must be in [0., 1.]"); /* Tree-PM parameters */ - p->mesh_size = parser_get_param_int(params, "Gravity:mesh_side_length"); - p->a_smooth = parser_get_opt_param_float(params, "Gravity:a_smooth", - gravity_props_default_a_smooth); - p->r_cut_max_ratio = parser_get_opt_param_float( - params, "Gravity:r_cut_max", gravity_props_default_r_cut_max); - p->r_cut_min_ratio = parser_get_opt_param_float( - params, "Gravity:r_cut_min", gravity_props_default_r_cut_min); - - /* Some basic checks */ - if (p->mesh_size % 2 != 0) - error("The mesh side-length must be an even number."); - - if (p->a_smooth <= 0.) - error("The mesh smoothing scale 'a_smooth' must be > 0."); - - if (2. * p->a_smooth * p->r_cut_max_ratio > p->mesh_size) - error("Mesh too small given r_cut_max. Should be at least %d cells wide.", - (int)(2. * p->a_smooth * p->r_cut_max_ratio) + 1); + if (periodic) { + p->mesh_size = parser_get_param_int(params, "Gravity:mesh_side_length"); + p->a_smooth = parser_get_opt_param_float(params, "Gravity:a_smooth", + gravity_props_default_a_smooth); + p->r_cut_max_ratio = parser_get_opt_param_float( + params, "Gravity:r_cut_max", gravity_props_default_r_cut_max); + p->r_cut_min_ratio = parser_get_opt_param_float( + params, "Gravity:r_cut_min", gravity_props_default_r_cut_min); + + /* Some basic checks of what we read */ + if (p->mesh_size % 2 != 0) + error("The mesh side-length must be an even number."); + + if (p->a_smooth <= 0.) + error("The mesh smoothing scale 'a_smooth' must be > 0."); + + if (2. * p->a_smooth * p->r_cut_max_ratio > p->mesh_size) + error("Mesh too small given r_cut_max. Should be at least %d cells wide.", + (int)(2. * p->a_smooth * p->r_cut_max_ratio) + 1); + } else { + p->mesh_size = 0; + p->a_smooth = 0.f; + p->r_cut_min_ratio = 0.f; + p->r_cut_max_ratio = 0.f; + } /* Time integration */ p->eta = parser_get_param_float(params, "Gravity:eta"); diff --git a/src/gravity_properties.h b/src/gravity_properties.h index 62dbab3605fb2dcfc4ae65e54c0b5f913d714c16..0cabd9958efa2bb23524d03632f90fdd1f1c8306 100644 --- a/src/gravity_properties.h +++ b/src/gravity_properties.h @@ -88,7 +88,8 @@ struct gravity_props { void gravity_props_print(const struct gravity_props *p); void gravity_props_init(struct gravity_props *p, struct swift_params *params, - const struct cosmology *cosmo, int with_cosmology); + const struct cosmology *cosmo, int with_cosmology, + int periodic); void gravity_update(struct gravity_props *p, const struct cosmology *cosmo); #if defined(HAVE_HDF5) diff --git a/src/hydro/Default/hydro.h b/src/hydro/Default/hydro.h index f5e71a8762c54faca7d165eb26199d0e30b486ac..4252f2787aefcec058b8fa956eaa0351b8f41d57 100644 --- a/src/hydro/Default/hydro.h +++ b/src/hydro/Default/hydro.h @@ -32,27 +32,59 @@ #include <float.h> /** - * @brief Returns the comoving internal energy of a particle + * @brief Returns the comoving internal energy of a particle at the last + * time the particle was kicked. * * @param p The particle of interest + * @param xp The extended data of the particle of interest. */ __attribute__((always_inline)) INLINE static float -hydro_get_comoving_internal_energy(const struct part *restrict p) { +hydro_get_comoving_internal_energy(const struct part *restrict p, + const struct xpart *restrict xp) { - return p->u; + return xp->u_full; } /** - * @brief Returns the physical internal energy of a particle + * @brief Returns the physical internal energy of a particle at the last + * time the particle was kicked. * - * @param p The particle of interest + * @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 * p->u; + return xp->u_full * cosmo->a_factor_internal_energy; +} + +/** + * @brief Returns the comoving internal energy of a particle drifted to the + * current time. + * + * @param p The particle of interest + */ +__attribute__((always_inline)) INLINE static float +hydro_get_drifted_comoving_internal_energy(const struct part *restrict p) { + + return p->u; +} + +/** + * @brief Returns the physical internal energy of a particle drifted to the + * current time. + * + * @param p The particle of interest. + * @param cosmo The cosmological model. + */ +__attribute__((always_inline)) INLINE static float +hydro_get_drifted_physical_internal_energy(const struct part *restrict p, + const struct cosmology *cosmo) { + + return p->u * cosmo->a_factor_internal_energy; } /** @@ -80,24 +112,57 @@ __attribute__((always_inline)) INLINE static float hydro_get_physical_pressure( } /** - * @brief Returns the comoving entropy of a particle + * @brief Returns the comoving entropy of a particle at the last + * time the particle was kicked. * - * @param p The particle of interest + * @param p The particle of interest. + * @param xp The extended data of the particle of interest. */ __attribute__((always_inline)) INLINE static float hydro_get_comoving_entropy( - const struct part *restrict p) { + const struct part *restrict p, const struct xpart *restrict xp) { - return gas_entropy_from_internal_energy(p->rho, p->u); + return gas_entropy_from_internal_energy(p->rho, xp->u_full); } /** - * @brief Returns the physical entropy of a particle + * @brief Returns the physical entropy of a particle at the last + * time the particle was kicked. * - * @param p The particle of interest + * @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. */ + return gas_entropy_from_internal_energy(p->rho, xp->u_full); +} + +/** + * @brief Returns the comoving entropy of a particle drifted to the + * current time. + * + * @param p The particle of interest. + */ +__attribute__((always_inline)) INLINE static float +hydro_get_drifted_comoving_entropy(const struct part *restrict p) { + + return gas_entropy_from_internal_energy(p->rho, p->u); +} + +/** + * @brief Returns the physical entropy of a particle drifted to the + * current time. + * + * @param p The particle of interest. + * @param cosmo The cosmological model. + */ +__attribute__((always_inline)) INLINE static float +hydro_get_drifted_physical_entropy(const struct part *restrict p, + const struct cosmology *cosmo) { /* Note: no cosmological conversion required here with our choice of * coordinates. */ @@ -201,12 +266,27 @@ __attribute__((always_inline)) INLINE static void hydro_get_drifted_velocities( * * @param p The particle of interest */ -__attribute__((always_inline)) INLINE static float hydro_get_internal_energy_dt( - const struct part *restrict p) { +__attribute__((always_inline)) INLINE static float +hydro_get_comoving_internal_energy_dt(const struct part *restrict p) { return p->force.u_dt; } +/** + * @brief Returns the time derivative of internal energy of a particle + * + * We assume a constant density. + * + * @param p The particle of interest + * @param cosmo Cosmology data structure + */ +__attribute__((always_inline)) INLINE static float +hydro_get_physical_internal_energy_dt(const struct part *restrict p, + const struct cosmology *cosmo) { + + return p->force.u_dt * cosmo->a_factor_internal_energy; +} + /** * @brief Returns the time derivative of internal energy of a particle * @@ -215,12 +295,29 @@ __attribute__((always_inline)) INLINE static float hydro_get_internal_energy_dt( * @param p The particle of interest. * @param du_dt The new time derivative of the internal energy. */ -__attribute__((always_inline)) INLINE static void hydro_set_internal_energy_dt( - struct part *restrict p, float du_dt) { +__attribute__((always_inline)) INLINE static void +hydro_set_comoving_internal_energy_dt(struct part *restrict p, float du_dt) { p->force.u_dt = du_dt; } +/** + * @brief Returns the time derivative of internal energy of a particle + * + * We assume a constant density. + * + * @param p The particle of interest. + * @param cosmo Cosmology data structure + * @param du_dt The new time derivative of the internal energy. + */ +__attribute__((always_inline)) INLINE static void +hydro_set_physical_internal_energy_dt(struct part *restrict p, + const struct cosmology *cosmo, + float du_dt) { + + p->force.u_dt = du_dt * cosmo->a_factor_internal_energy; +} + /** * @brief Computes the hydro time-step of a given particle * @@ -361,12 +458,14 @@ __attribute__((always_inline)) INLINE static void hydro_part_has_no_neighbours( * @param p The particle to act upon * @param xp The extended particle data to act upon * @param cosmo The current cosmological model. + * @param hydro_props Hydrodynamic properties. * @param dt_alpha The time-step used to evolve non-cosmological quantities such * as the artificial viscosity. */ __attribute__((always_inline)) INLINE static void hydro_prepare_force( struct part *restrict p, struct xpart *restrict xp, - const struct cosmology *cosmo, const float dt_alpha) { + const struct cosmology *cosmo, const struct hydro_props *hydro_props, + const float dt_alpha) { const float fac_mu = cosmo->a_factor_mu; /* Some smoothing length multiples. */ @@ -395,6 +494,9 @@ __attribute__((always_inline)) INLINE static void hydro_prepare_force( p->force.balsara = normDiv_v / (normDiv_v + normRot_v + 0.0001f * fac_mu * fc * h_inv); + /* Set the AV property */ + p->alpha = hydro_props->viscosity.alpha; + /* Viscosity parameter decay time */ /* const float tau = h / (2.f * const_viscosity_length * p->force.soundspeed); */ @@ -403,8 +505,10 @@ __attribute__((always_inline)) INLINE static void hydro_prepare_force( /* const float S = max(-normDiv_v, 0.f); */ /* Compute the particle's viscosity parameter time derivative */ - /* const float alpha_dot = (const_viscosity_alpha_min - p->alpha) / tau + */ - /* (const_viscosity_alpha_max - p->alpha) * S; */ + /* const float alpha_dot = (hydro_props->viscosity.alpha_max) - p->alpha) / + * tau + */ + /* (hydro_props->viscosity.alpha_max - p->alpha) * S; + */ /* Update particle's viscosity paramter */ /* p->alpha += alpha_dot * (p->ti_end - p->ti_begin) * timeBase; */ // MATTHIEU diff --git a/src/hydro/Default/hydro_iact.h b/src/hydro/Default/hydro_iact.h index 658b4aba83085610a49bb9d2579d4f20c70d6c5b..72808874c3fc6b58005d0e3ad450eafea8aa4b4d 100644 --- a/src/hydro/Default/hydro_iact.h +++ b/src/hydro/Default/hydro_iact.h @@ -226,7 +226,8 @@ __attribute__((always_inline)) INLINE static void runner_iact_force( omega_ij = min(fac_mu * dvdr, 0.f); /* Compute signal velocity */ - v_sig = pi->force.soundspeed + pj->force.soundspeed - 2.0f * omega_ij; + v_sig = pi->force.soundspeed + pj->force.soundspeed - + const_viscosity_beta * omega_ij; /* Compute viscosity parameter */ alpha_ij = -0.5f * (pi->alpha + pj->alpha); @@ -335,7 +336,8 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force( omega_ij = min(fac_mu * dvdr, 0.f); /* Compute signal velocity */ - v_sig = pi->force.soundspeed + pj->force.soundspeed - 2.0f * omega_ij; + v_sig = pi->force.soundspeed + pj->force.soundspeed - + const_viscosity_beta * omega_ij; /* Compute viscosity parameter */ alpha_ij = -0.5f * (pi->alpha + pj->alpha); diff --git a/src/hydro/Default/hydro_io.h b/src/hydro/Default/hydro_io.h index d47c96fbf32e1ee00346888aaf2e8afabc22abc3..69919c202223fdecc197a87178e59767c02ee16e 100644 --- a/src/hydro/Default/hydro_io.h +++ b/src/hydro/Default/hydro_io.h @@ -55,6 +55,17 @@ INLINE static void hydro_read_particles(struct part* parts, list[7] = io_make_input_field("Density", FLOAT, 1, OPTIONAL, UNIT_CONV_DENSITY, parts, rho); } +INLINE static void convert_S(const struct engine* e, const struct part* p, + const struct xpart* xp, float* ret) { + + ret[0] = hydro_get_comoving_entropy(p, xp); +} + +INLINE static void convert_P(const struct engine* e, const struct part* p, + const struct xpart* xp, float* ret) { + + ret[0] = hydro_get_comoving_pressure(p); +} INLINE static void convert_part_pos(const struct engine* e, const struct part* p, @@ -128,7 +139,7 @@ INLINE static void hydro_write_particles(const struct part* parts, struct io_props* list, int* num_fields) { - *num_fields = 8; + *num_fields = 10; /* List what we want to write */ list[0] = io_make_output_field_convert_part("Coordinates", DOUBLE, 3, @@ -146,7 +157,13 @@ INLINE static void hydro_write_particles(const struct part* parts, UNIT_CONV_NO_UNITS, parts, id); list[6] = io_make_output_field("Density", FLOAT, 1, UNIT_CONV_DENSITY, parts, rho); - list[7] = io_make_output_field_convert_part("Potential", FLOAT, 1, + list[7] = io_make_output_field_convert_part("Entropy", FLOAT, 1, + UNIT_CONV_ENTROPY_PER_UNIT_MASS, + parts, xparts, convert_S); + list[8] = io_make_output_field_convert_part( + "Pressure", FLOAT, 1, UNIT_CONV_PRESSURE, parts, xparts, convert_P); + + list[0] = io_make_output_field_convert_part("Potential", FLOAT, 1, UNIT_CONV_POTENTIAL, parts, xparts, convert_part_potential); } @@ -166,13 +183,6 @@ INLINE static void hydro_write_flavour(hid_t h_grpsph) { h_grpsph, "Viscosity Model", "Morris & Monaghan (1997), Rosswog, Davies, Thielemann & " "Piran (2000) with additional Balsara (1995) switch"); - io_write_attribute_f(h_grpsph, "Viscosity alpha_min", - const_viscosity_alpha_min); - io_write_attribute_f(h_grpsph, "Viscosity alpha_max", - const_viscosity_alpha_max); - io_write_attribute_f(h_grpsph, "Viscosity beta", 2.f); - io_write_attribute_f(h_grpsph, "Viscosity decay length", - const_viscosity_length); /* Time integration properties */ io_write_attribute_f(h_grpsph, "Maximal Delta u change over dt", diff --git a/src/hydro/Gadget2/hydro.h b/src/hydro/Gadget2/hydro.h index 0dcd2cf01e9d3b93194fab96af836b6dd045d1f9..9765ced22bb8e6291c2a189fc0e0f27419239c08 100644 --- a/src/hydro/Gadget2/hydro.h +++ b/src/hydro/Gadget2/hydro.h @@ -42,26 +42,59 @@ #include "minmax.h" /** - * @brief Returns the comoving internal energy of a particle + * @brief Returns the comoving internal energy of a particle at the last + * time the particle was kicked. * * @param p The particle of interest + * @param xp The extended data of the particle of interest. */ __attribute__((always_inline)) INLINE static float -hydro_get_comoving_internal_energy(const struct part *restrict p) { +hydro_get_comoving_internal_energy(const struct part *restrict p, + const struct xpart *restrict xp) { - return gas_internal_energy_from_entropy(p->rho, p->entropy); + return gas_internal_energy_from_entropy(p->rho, xp->entropy_full); } /** - * @brief Returns the physical internal energy of a particle + * @brief Returns the physical internal energy of a particle at the last + * time the particle was kicked. * * @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 gas_internal_energy_from_entropy(p->rho * cosmo->a3_inv, + xp->entropy_full); +} + +/** + * @brief Returns the comoving internal energy of a particle drifted to the + * current time. + * + * @param p The particle of interest + */ +__attribute__((always_inline)) INLINE static float +hydro_get_drifted_comoving_internal_energy(const struct part *restrict p) { + + return gas_internal_energy_from_entropy(p->rho, p->entropy); +} + +/** + * @brief Returns the physical internal energy of a particle drifted to the + * current time. + * + * @param p The particle of interest. + * @param cosmo The cosmological model. + */ +__attribute__((always_inline)) INLINE static float +hydro_get_drifted_physical_internal_energy(const struct part *restrict p, + const struct cosmology *cosmo) { + return gas_internal_energy_from_entropy(p->rho * cosmo->a3_inv, p->entropy); } @@ -79,7 +112,8 @@ __attribute__((always_inline)) INLINE static float hydro_get_comoving_pressure( /** * @brief Returns the physical pressure of a particle * - * @param p The particle of interest + * @param p The particle of interest. + * @param cosmo The cosmological model. */ __attribute__((always_inline)) INLINE static float hydro_get_physical_pressure( const struct part *restrict p, const struct cosmology *cosmo) { @@ -88,24 +122,57 @@ __attribute__((always_inline)) INLINE static float hydro_get_physical_pressure( } /** - * @brief Returns the comoving entropy of a particle + * @brief Returns the comoving entropy of a particle at the last + * time the particle was kicked. * * @param p The particle of interest. + * @param xp The extended data of the particle of interest. */ __attribute__((always_inline)) INLINE static float hydro_get_comoving_entropy( - const struct part *restrict p) { + const struct part *restrict p, const struct xpart *restrict xp) { - return p->entropy; + return xp->entropy_full; } /** - * @brief Returns the physical entropy of a particle + * @brief Returns the physical entropy of a particl at the last + * time the particle was kicked. * * @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. */ + return xp->entropy_full; +} + +/** + * @brief Returns the comoving entropy of a particle drifted to the + * current time. + * + * @param p The particle of interest. + */ +__attribute__((always_inline)) INLINE static float +hydro_get_drifted_comoving_entropy(const struct part *restrict p) { + + return p->entropy; +} + +/** + * @brief Returns the physical entropy of a particle drifted to the + * current time. + * + * @param p The particle of interest. + * @param cosmo The cosmological model. + */ +__attribute__((always_inline)) INLINE static float +hydro_get_drifted_physical_entropy(const struct part *restrict p, + const struct cosmology *cosmo) { /* Note: no cosmological conversion required here with our choice of * coordinates. */ @@ -204,32 +271,66 @@ __attribute__((always_inline)) INLINE static void hydro_get_drifted_velocities( } /** - * @brief Returns the time derivative of internal energy of a particle + * @brief Returns the time derivative of co-moving internal energy of a particle * * We assume a constant density. * * @param p The particle of interest */ -__attribute__((always_inline)) INLINE static float hydro_get_internal_energy_dt( - const struct part *restrict p) { +__attribute__((always_inline)) INLINE static float +hydro_get_comoving_internal_energy_dt(const struct part *restrict p) { return gas_internal_energy_from_entropy(p->rho, p->entropy_dt); } /** - * @brief Returns the time derivative of internal energy of a particle + * @brief Returns the time derivative of physical internal energy of a particle * * We assume a constant density. * * @param p The particle of interest. + * @param cosmo The cosmological model. + */ +__attribute__((always_inline)) INLINE static float +hydro_get_physical_internal_energy_dt(const struct part *restrict p, + const struct cosmology *cosmo) { + + return gas_internal_energy_from_entropy(p->rho * cosmo->a3_inv, + p->entropy_dt); +} + +/** + * @brief Sets the time derivative of the co-moving internal energy of a + * particle + * + * We assume a constant density for the conversion to entropy. + * + * @param p The particle of interest. * @param du_dt The new time derivative of the internal energy. */ -__attribute__((always_inline)) INLINE static void hydro_set_internal_energy_dt( - struct part *restrict p, float du_dt) { +__attribute__((always_inline)) INLINE static void +hydro_set_comoving_internal_energy_dt(struct part *restrict p, float du_dt) { p->entropy_dt = gas_entropy_from_internal_energy(p->rho, du_dt); } +/** + * @brief Sets the time derivative of the physical internal energy of a particle + * + * We assume a constant density for the conversion to entropy. + * + * @param p The particle of interest. + * @param cosmo Cosmology data structure + * @param du_dt The time derivative of the internal energy. + */ +__attribute__((always_inline)) INLINE static void +hydro_set_physical_internal_energy_dt(struct part *restrict p, + const struct cosmology *restrict cosmo, + float du_dt) { + p->entropy_dt = + gas_entropy_from_internal_energy(p->rho * cosmo->a3_inv, du_dt); +} + /** * @brief Computes the hydro time-step of a given particle * @@ -371,25 +472,31 @@ __attribute__((always_inline)) INLINE static void hydro_part_has_no_neighbours( * @param p The particle to act upon * @param xp The extended particle data to act upon * @param cosmo The current cosmological model. + * @param hydro_props Hydrodynamic properties. * @param dt_alpha The time-step used to evolve non-cosmological quantities such * as the artificial viscosity. */ __attribute__((always_inline)) INLINE static void hydro_prepare_force( struct part *restrict p, struct xpart *restrict xp, - const struct cosmology *cosmo, const float dt_alpha) { + const struct cosmology *cosmo, const struct hydro_props *hydro_props, + const float dt_alpha) { - const float fac_mu = cosmo->a_factor_mu; + const float fac_Balsara_eps = cosmo->a_factor_Balsara_eps; - /* Inverse of the physical density */ + /* Inverse of the co-moving density */ const float rho_inv = 1.f / p->rho; + /* Inverse of the smoothing length */ + const float h_inv = 1.f / p->h; + /* Compute the norm of the curl */ const float curl_v = sqrtf(p->density.rot_v[0] * p->density.rot_v[0] + p->density.rot_v[1] * p->density.rot_v[1] + p->density.rot_v[2] * p->density.rot_v[2]); - /* Compute the norm of div v */ - const float abs_div_v = fabsf(p->density.div_v); + /* Compute the norm of div v including the Hubble flow term */ + const float div_physical_v = p->density.div_v + 3.f * cosmo->H; + const float abs_div_physical_v = fabsf(div_physical_v); /* Compute the pressure */ const float pressure = gas_pressure_from_entropy(p->rho, p->entropy); @@ -401,8 +508,11 @@ __attribute__((always_inline)) INLINE static void hydro_prepare_force( const float P_over_rho2 = pressure * rho_inv * rho_inv; /* Compute the Balsara switch */ - const float balsara = - abs_div_v / (abs_div_v + curl_v + 0.0001f * fac_mu * soundspeed / p->h); + /* Pre-multiply in the AV factor; hydro_props are not passed to the iact + * functions */ + const float balsara = hydro_props->viscosity.alpha * abs_div_physical_v / + (abs_div_physical_v + curl_v + + 0.0001f * fac_Balsara_eps * soundspeed * h_inv); /* Compute the "grad h" term */ const float omega_inv = @@ -532,6 +642,9 @@ __attribute__((always_inline)) INLINE static void hydro_end_force( * @param p The particle to act upon * @param xp The particle extended data to act upon * @param dt_therm The time-step for this kick (for thermodynamic quantities) + * @param dt_grav The time-step for this kick (for gravity forces) + * @param dt_hydro The time-step for this kick (for hydro forces) + * @param dt_kick_corr The time-step for this kick (for correction of the kick) * @param cosmo The cosmological model. * @param hydro_props The constants used in the scheme */ @@ -547,12 +660,13 @@ __attribute__((always_inline)) INLINE static void hydro_kick_extra( xp->entropy_full += p->entropy_dt * dt_therm; /* Apply the minimal energy limit */ - const float density = p->rho * cosmo->a3_inv; - const float min_energy = hydro_props->minimal_internal_energy; - const float min_entropy = - gas_entropy_from_internal_energy(density, min_energy); - if (xp->entropy_full < min_entropy) { - xp->entropy_full = min_entropy; + const float physical_density = p->rho * cosmo->a3_inv; + const float min_physical_energy = hydro_props->minimal_internal_energy; + const float min_physical_entropy = + gas_entropy_from_internal_energy(physical_density, min_physical_energy); + const float min_comoving_entropy = min_physical_entropy; /* A' = A */ + if (xp->entropy_full < min_comoving_entropy) { + xp->entropy_full = min_comoving_entropy; p->entropy_dt = 0.f; } @@ -584,20 +698,21 @@ __attribute__((always_inline)) INLINE static void hydro_convert_quantities( struct part *restrict p, struct xpart *restrict xp, const struct cosmology *cosmo, const struct hydro_props *hydro_props) { - /* We read u in the entropy field. We now get (comoving) S from (physical) u - * and (physical) rho. Note that comoving S == physical S */ + /* We read u in the entropy field. We now get (comoving) A from (physical) u + * and (physical) rho. Note that comoving A (A') == physical A */ xp->entropy_full = gas_entropy_from_internal_energy(p->rho * cosmo->a3_inv, p->entropy); p->entropy = xp->entropy_full; /* Apply the minimal energy limit */ - const float density = p->rho * cosmo->a3_inv; - const float min_energy = hydro_props->minimal_internal_energy; - const float min_entropy = - gas_entropy_from_internal_energy(density, min_energy); - if (xp->entropy_full < min_entropy) { - xp->entropy_full = min_entropy; - p->entropy = min_entropy; + const float physical_density = p->rho * cosmo->a3_inv; + const float min_physical_energy = hydro_props->minimal_internal_energy; + const float min_physical_entropy = + gas_entropy_from_internal_energy(physical_density, min_physical_energy); + const float min_comoving_entropy = min_physical_entropy; /* A' = A */ + if (xp->entropy_full < min_comoving_entropy) { + xp->entropy_full = min_comoving_entropy; + p->entropy = min_comoving_entropy; p->entropy_dt = 0.f; } diff --git a/src/hydro/Gadget2/hydro_iact.h b/src/hydro/Gadget2/hydro_iact.h index b2d77a261e91a4f8460189cfce99951a820ef8f1..746fd4778563aeaab43bafcc7904683ed5b6811c 100644 --- a/src/hydro/Gadget2/hydro_iact.h +++ b/src/hydro/Gadget2/hydro_iact.h @@ -493,12 +493,11 @@ __attribute__((always_inline)) INLINE static void runner_iact_force( const float mu_ij = fac_mu * r_inv * omega_ij; /* This is 0 or negative */ /* Signal velocity */ - const float v_sig = ci + cj - 3.f * mu_ij; + const float v_sig = ci + cj - const_viscosity_beta * mu_ij; /* Now construct the full viscosity term */ const float rho_ij = 0.5f * (rhoi + rhoj); - const float visc = -0.25f * const_viscosity_alpha * v_sig * mu_ij * - (balsara_i + balsara_j) / rho_ij; + const float visc = -0.25f * v_sig * mu_ij * (balsara_i + balsara_j) / rho_ij; /* Now, convolve with the kernel */ const float visc_term = 0.5f * visc * (wi_dr + wj_dr) * r_inv; @@ -526,8 +525,8 @@ __attribute__((always_inline)) INLINE static void runner_iact_force( pj->force.v_sig = max(pj->force.v_sig, v_sig); /* Change in entropy */ - pi->entropy_dt += mj * visc_term * dvdr; - pj->entropy_dt += mi * visc_term * dvdr; + pi->entropy_dt += mj * visc_term * dvdr_Hubble; + pj->entropy_dt += mi * visc_term * dvdr_Hubble; #ifdef DEBUG_INTERACTIONS_SPH /* Update ngb counters */ @@ -616,12 +615,11 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force( const float mu_ij = fac_mu * r_inv * omega_ij; /* This is 0 or negative */ /* Signal velocity */ - const float v_sig = ci + cj - 3.f * mu_ij; + const float v_sig = ci + cj - const_viscosity_beta * mu_ij; /* Now construct the full viscosity term */ const float rho_ij = 0.5f * (rhoi + rhoj); - const float visc = -0.25f * const_viscosity_alpha * v_sig * mu_ij * - (balsara_i + balsara_j) / rho_ij; + const float visc = -0.25f * v_sig * mu_ij * (balsara_i + balsara_j) / rho_ij; /* Now, convolve with the kernel */ const float visc_term = 0.5f * visc * (wi_dr + wj_dr) * r_inv; @@ -643,7 +641,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force( pi->force.v_sig = max(pi->force.v_sig, v_sig); /* Change in entropy */ - pi->entropy_dt += mj * visc_term * dvdr; + pi->entropy_dt += mj * visc_term * dvdr_Hubble; #ifdef DEBUG_INTERACTIONS_SPH /* Update ngb counters */ @@ -654,8 +652,6 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force( } #ifdef WITH_VECTORIZATION -static const vector const_viscosity_alpha_fac = - FILL_VEC(-0.25f * const_viscosity_alpha); /** * @brief Force interaction computed using 1 vector @@ -741,13 +737,14 @@ runner_iact_nonsym_1_vec_force( vec_mul(ri.v, omega_ij.v)); /* This is 0 or negative */ /* Compute signal velocity */ - v_sig.v = vec_fnma(vec_set1(3.f), mu_ij.v, vec_add(ci.v, cj.v)); + v_sig.v = + vec_fnma(vec_set1(const_viscosity_beta), mu_ij.v, vec_add(ci.v, cj.v)); /* Now construct the full viscosity term */ rho_ij.v = vec_mul(vec_set1(0.5f), vec_add(pirho.v, pjrho.v)); - visc.v = vec_div(vec_mul(const_viscosity_alpha_fac.v, - vec_mul(v_sig.v, vec_mul(mu_ij.v, balsara.v))), - rho_ij.v); + visc.v = vec_div( + vec_mul(vec_set1(-0.25f), vec_mul(v_sig.v, vec_mul(mu_ij.v, balsara.v))), + rho_ij.v); /* Now, convolve with the kernel */ visc_term.v = @@ -772,7 +769,7 @@ runner_iact_nonsym_1_vec_force( vec_div(vec_mul(mj.v, vec_mul(dvdr.v, vec_mul(ri.v, wi_dr.v))), pjrho.v); /* Change in entropy */ - entropy_dt.v = vec_mul(mj.v, vec_mul(visc_term.v, dvdr.v)); + entropy_dt.v = vec_mul(mj.v, vec_mul(visc_term.v, dvdr_Hubble.v)); /* Store the forces back on the particles. */ a_hydro_xSum->v = vec_mask_sub(a_hydro_xSum->v, piax.v, mask); @@ -927,18 +924,20 @@ runner_iact_nonsym_2_vec_force( v_fac_mu.v, vec_mul(ri_2.v, omega_ij_2.v)); /* This is 0 or negative */ /* Compute signal velocity */ - v_sig.v = vec_fnma(vec_set1(3.f), mu_ij.v, vec_add(ci.v, cj.v)); - v_sig_2.v = vec_fnma(vec_set1(3.f), mu_ij_2.v, vec_add(ci.v, cj_2.v)); + v_sig.v = + vec_fnma(vec_set1(const_viscosity_beta), mu_ij.v, vec_add(ci.v, cj.v)); + v_sig_2.v = vec_fnma(vec_set1(const_viscosity_beta), mu_ij_2.v, + vec_add(ci.v, cj_2.v)); /* Now construct the full viscosity term */ rho_ij.v = vec_mul(vec_set1(0.5f), vec_add(pirho.v, pjrho.v)); rho_ij_2.v = vec_mul(vec_set1(0.5f), vec_add(pirho.v, pjrho_2.v)); - visc.v = vec_div(vec_mul(const_viscosity_alpha_fac.v, - vec_mul(v_sig.v, vec_mul(mu_ij.v, balsara.v))), - rho_ij.v); + visc.v = vec_div( + vec_mul(vec_set1(-0.25f), vec_mul(v_sig.v, vec_mul(mu_ij.v, balsara.v))), + rho_ij.v); visc_2.v = - vec_div(vec_mul(const_viscosity_alpha_fac.v, + vec_div(vec_mul(vec_set1(-0.25f), vec_mul(v_sig_2.v, vec_mul(mu_ij_2.v, balsara_2.v))), rho_ij_2.v); @@ -982,8 +981,8 @@ runner_iact_nonsym_2_vec_force( pjrho_2.v); /* Change in entropy */ - entropy_dt.v = vec_mul(mj.v, vec_mul(visc_term.v, dvdr.v)); - entropy_dt_2.v = vec_mul(mj_2.v, vec_mul(visc_term_2.v, dvdr_2.v)); + entropy_dt.v = vec_mul(mj.v, vec_mul(visc_term.v, dvdr_Hubble.v)); + entropy_dt_2.v = vec_mul(mj_2.v, vec_mul(visc_term_2.v, dvdr_Hubble_2.v)); /* Store the forces back on the particles. */ if (mask_cond) { diff --git a/src/hydro/Gadget2/hydro_io.h b/src/hydro/Gadget2/hydro_io.h index 3f2af41dc7f0cc8f60992a15a0f09f3c90f764fe..ec7d34f7ad8697f1d639ea4951011ddb06ec8833 100644 --- a/src/hydro/Gadget2/hydro_io.h +++ b/src/hydro/Gadget2/hydro_io.h @@ -59,7 +59,7 @@ INLINE static void hydro_read_particles(struct part* parts, INLINE static void convert_part_u(const struct engine* e, const struct part* p, const struct xpart* xp, float* ret) { - ret[0] = hydro_get_comoving_internal_energy(p); + ret[0] = hydro_get_comoving_internal_energy(p, xp); } INLINE static void convert_part_P(const struct engine* e, const struct part* p, @@ -132,6 +132,7 @@ INLINE static void convert_part_potential(const struct engine* e, * @brief Specifies which particle fields to write to a dataset * * @param parts The particle array. + * @param xparts The extended particle data array. * @param list The list of i/o properties to write. * @param num_fields The number of i/o fields to write. */ @@ -199,8 +200,6 @@ INLINE static void hydro_write_flavour(hid_t h_grpsph) { io_write_attribute_s( h_grpsph, "Viscosity Model", "as in Springel (2005), i.e. Monaghan (1992) with Balsara (1995) switch"); - io_write_attribute_f(h_grpsph, "Viscosity alpha", const_viscosity_alpha); - io_write_attribute_f(h_grpsph, "Viscosity beta", 3.f); } /** diff --git a/src/hydro/Gadget2/hydro_part.h b/src/hydro/Gadget2/hydro_part.h index 90f73571701b37b3377601655330d8d25f862a05..bcb40243362dc57d47a3832c1d9330cb68d93fb8 100644 --- a/src/hydro/Gadget2/hydro_part.h +++ b/src/hydro/Gadget2/hydro_part.h @@ -33,6 +33,7 @@ #include "chemistry_struct.h" #include "cooling_struct.h" +#include "logger.h" /* Extra particle data not needed during the SPH loops over neighbours. */ struct xpart { @@ -55,6 +56,11 @@ struct xpart { /* Additional data used to record cooling information */ struct cooling_xpart_data cooling_data; +#ifdef WITH_LOGGER + /* Additional data for the particle logger */ + struct logger_part_data logger_data; +#endif + } SWIFT_STRUCT_ALIGN; /* Data of a single particle. */ diff --git a/src/hydro/GizmoMFM/hydro.h b/src/hydro/GizmoMFM/hydro.h index d6b44e19899fdb74ee32f699665ec6e706d718b1..8e466daabb59482a1c2ebbaf80af30c64c4abdfe 100644 --- a/src/hydro/GizmoMFM/hydro.h +++ b/src/hydro/GizmoMFM/hydro.h @@ -451,12 +451,14 @@ __attribute__((always_inline)) INLINE static void hydro_end_gradient( * @param p The particle to act upon * @param xp The extended particle data to act upon * @param cosmo The current cosmological model. + * @param hydro_props Hydrodynamic properties. * @param dt_alpha The time-step used to evolve non-cosmological quantities such * as the artificial viscosity. */ __attribute__((always_inline)) INLINE static void hydro_prepare_force( struct part* restrict p, struct xpart* restrict xp, - const struct cosmology* cosmo, const float dt_alpha) { + const struct cosmology* cosmo, const struct hydro_props* hydro_props, + const float dt_alpha) { /* Initialise values that are used in the force loop */ p->flux.momentum[0] = 0.0f; @@ -730,6 +732,33 @@ hydro_get_physical_internal_energy(const struct part* restrict p, hydro_get_comoving_internal_energy(p); } +/** + * @brief Returns the comoving internal energy of a particle drifted to the + * current time. + * + * @param p The particle of interest + */ +__attribute__((always_inline)) INLINE static float +hydro_get_drifted_comoving_internal_energy(const struct part* restrict p) { + + return hydro_get_comoving_internal_energy(p); +} + +/** + * @brief Returns the physical internal energy of a particle drifted to the + * current time. + * + * @param p The particle of interest. + * @param cosmo The cosmological model. + */ +__attribute__((always_inline)) INLINE static float +hydro_get_drifted_physical_internal_energy(const struct part* restrict p, + const struct cosmology* cosmo) { + + return hydro_get_comoving_internal_energy(p) * + cosmo->a_factor_internal_energy; +} + /** * @brief Returns the comoving entropy of a particle * @@ -759,6 +788,21 @@ __attribute__((always_inline)) INLINE static float hydro_get_physical_entropy( return hydro_get_comoving_entropy(p); } +/** + * @brief Returns the physical internal energy of a particle + * + * @param p The particle of interest. + * @param cosmo The cosmological model. + */ +__attribute__((always_inline)) INLINE static float +hydro_get_drifted_physical_entropy(const struct part* restrict p, + const struct cosmology* cosmo) { + + /* Note: no cosmological conversion required here with our choice of + * coordinates. */ + return hydro_get_comoving_entropy(p); +} + /** * @brief Returns the sound speed of a particle * diff --git a/src/hydro/GizmoMFM/hydro_iact.h b/src/hydro/GizmoMFM/hydro_iact.h index 5bed20d7f894a76d5fe3642c7438dc03195e43d6..38a97cbea39c1ed5c6926c911941e655e52362aa 100644 --- a/src/hydro/GizmoMFM/hydro_iact.h +++ b/src/hydro/GizmoMFM/hydro_iact.h @@ -267,8 +267,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_fluxes_common( const float dvdotdx = min(dvdr, 0.0f); /* Get the signal velocity */ - /* the magical factor 3 also appears in Gadget2 */ - vmax -= 3.0f * dvdotdx * r_inv; + vmax -= const_viscosity_beta * dvdotdx * r_inv; /* Store the signal velocity */ pi->timestepvars.vmax = max(pi->timestepvars.vmax, vmax); diff --git a/src/hydro/GizmoMFV/hydro.h b/src/hydro/GizmoMFV/hydro.h index 24456b7bdf65acb516630d587e1319e58c96e2fe..98a70aefed098243bbf2dfe08e752ee48a838d3e 100644 --- a/src/hydro/GizmoMFV/hydro.h +++ b/src/hydro/GizmoMFV/hydro.h @@ -476,12 +476,14 @@ __attribute__((always_inline)) INLINE static void hydro_end_gradient( * @param p The particle to act upon * @param xp The extended particle data to act upon * @param cosmo The current cosmological model. + * @param hydro_props Hydrodynamic properties. * @param dt_alpha The time-step used to evolve non-cosmological quantities such * as the artificial viscosity. */ __attribute__((always_inline)) INLINE static void hydro_prepare_force( struct part* restrict p, struct xpart* restrict xp, - const struct cosmology* cosmo, const float dt_alpha) { + const struct cosmology* cosmo, const struct hydro_props* hydro_props, + const float dt_alpha) { /* Initialise values that are used in the force loop */ p->gravity.mflux[0] = 0.0f; @@ -816,6 +818,19 @@ hydro_get_physical_internal_energy(const struct part* restrict p, hydro_get_comoving_internal_energy(p); } +/** + * @brief Returns the physical internal energy of a particle + * + * @param p The particle of interest. + * @param cosmo The cosmological model. + */ +__attribute__((always_inline)) INLINE static float +hydro_get_drifted_physical_internal_energy(const struct part* restrict p, + const struct cosmology* cosmo) { + + return hydro_get_physical_internal_energy(p, cosmo); +} + /** * @brief Returns the comoving entropy of a particle * @@ -845,6 +860,21 @@ __attribute__((always_inline)) INLINE static float hydro_get_physical_entropy( return hydro_get_comoving_entropy(p); } +/** + * @brief Returns the physical internal energy of a particle + * + * @param p The particle of interest. + * @param cosmo The cosmological model. + */ +__attribute__((always_inline)) INLINE static float +hydro_get_drifted_physical_entropy(const struct part* restrict p, + const struct cosmology* cosmo) { + + /* Note: no cosmological conversion required here with our choice of + * coordinates. */ + return hydro_get_comoving_entropy(p); +} + /** * @brief Returns the sound speed of a particle * diff --git a/src/hydro/GizmoMFV/hydro_iact.h b/src/hydro/GizmoMFV/hydro_iact.h index c766ce3cc9048f8da8b3438c3c27e6998dd5df7e..2f73e67ea2fdcecc527de8b1af0d15731f967b9b 100644 --- a/src/hydro/GizmoMFV/hydro_iact.h +++ b/src/hydro/GizmoMFV/hydro_iact.h @@ -271,8 +271,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_fluxes_common( dvdotdx = min(dvdotdx, 0.f); /* Get the signal velocity */ - /* the magical factor 3 also appears in Gadget2 */ - vmax -= 3.f * dvdotdx * r_inv; + vmax -= const_viscosity_beta * dvdotdx * r_inv; /* Store the signal velocity */ pi->timestepvars.vmax = max(pi->timestepvars.vmax, vmax); diff --git a/src/hydro/Minimal/hydro.h b/src/hydro/Minimal/hydro.h index cf629814817064c109f7f016f81b6c621b087436..93a2b3ec8ed4ecb6dcc73314233217d37141ba46 100644 --- a/src/hydro/Minimal/hydro.h +++ b/src/hydro/Minimal/hydro.h @@ -44,35 +44,58 @@ #include "minmax.h" /** - * @brief Returns the comoving internal energy of a particle - * - * For implementations where the main thermodynamic variable - * is not internal energy, this function computes the internal - * energy from the thermodynamic variable. + * @brief Returns the comoving internal energy of a particle at the last + * time the particle was kicked. * * @param p The particle of interest + * @param xp The extended data of the particle of interest. */ __attribute__((always_inline)) INLINE static float -hydro_get_comoving_internal_energy(const struct part *restrict p) { +hydro_get_comoving_internal_energy(const struct part *restrict p, + const struct xpart *restrict xp) { - return p->u; + return xp->u_full; } /** - * @brief Returns the physical internal energy of a particle - * - * For implementations where the main thermodynamic variable - * is not internal energy, this function computes the internal - * energy from the thermodynamic variable and converts it to - * physical coordinates. + * @brief Returns the physical internal energy of a particle at the last + * time the particle was kicked. * * @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 xp->u_full * cosmo->a_factor_internal_energy; +} + +/** + * @brief Returns the comoving internal energy of a particle drifted to the + * current time. + * + * @param p The particle of interest + */ +__attribute__((always_inline)) INLINE static float +hydro_get_drifted_comoving_internal_energy(const struct part *restrict p) { + + return p->u; +} + +/** + * @brief Returns the physical internal energy of a particle drifted to the + * current time. + * + * @param p The particle of interest. + * @param cosmo The cosmological model. + */ +__attribute__((always_inline)) INLINE static float +hydro_get_drifted_physical_internal_energy(const struct part *restrict p, + const struct cosmology *cosmo) { + return p->u * cosmo->a_factor_internal_energy; } @@ -106,33 +129,57 @@ __attribute__((always_inline)) INLINE static float hydro_get_physical_pressure( } /** - * @brief Returns the comoving entropy of a particle + * @brief Returns the comoving entropy of a particle at the last + * time the particle was kicked. * - * For implementations where the main thermodynamic variable - * is not entropy, this function computes the entropy from - * the thermodynamic variable. - * - * @param p The particle of interest + * @param p The particle of interest. + * @param xp The extended data of the particle of interest. */ __attribute__((always_inline)) INLINE static float hydro_get_comoving_entropy( - const struct part *restrict p) { + const struct part *restrict p, const struct xpart *restrict xp) { - return gas_entropy_from_internal_energy(p->rho, p->u); + return gas_entropy_from_internal_energy(p->rho, xp->u_full); } /** - * @brief Returns the physical entropy of a particle + * @brief Returns the physical entropy of a particle at the last + * time the particle was kicked. * - * For implementations where the main thermodynamic variable - * is not entropy, this function computes the entropy from - * the thermodynamic variable and converts it to - * physical coordinates. - * - * @param p The particle of interest + * @param 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. */ + return gas_entropy_from_internal_energy(p->rho, xp->u_full); +} + +/** + * @brief Returns the comoving entropy of a particle drifted to the + * current time. + * + * @param p The particle of interest. + */ +__attribute__((always_inline)) INLINE static float +hydro_get_drifted_comoving_entropy(const struct part *restrict p) { + + return gas_entropy_from_internal_energy(p->rho, p->u); +} + +/** + * @brief Returns the physical entropy of a particle drifted to the + * current time. + * + * @param p The particle of interest. + * @param cosmo The cosmological model. + */ +__attribute__((always_inline)) INLINE static float +hydro_get_drifted_physical_entropy(const struct part *restrict p, + const struct cosmology *cosmo) { /* Note: no cosmological conversion required here with our choice of * coordinates. */ @@ -231,14 +278,14 @@ __attribute__((always_inline)) INLINE static void hydro_get_drifted_velocities( } /** - * @brief Returns the time derivative of internal energy of a particle + * @brief Returns the time derivative of co-moving internal energy of a particle * * We assume a constant density. * * @param p The particle of interest */ -__attribute__((always_inline)) INLINE static float hydro_get_internal_energy_dt( - const struct part *restrict p) { +__attribute__((always_inline)) INLINE static float +hydro_get_comoving_internal_energy_dt(const struct part *restrict p) { return p->u_dt; } @@ -248,14 +295,48 @@ __attribute__((always_inline)) INLINE static float hydro_get_internal_energy_dt( * * We assume a constant density. * + * @param p The particle of interest + * @param cosmo Cosmology data structure + */ +__attribute__((always_inline)) INLINE static float +hydro_get_physical_internal_energy_dt(const struct part *restrict p, + const struct cosmology *cosmo) { + + return p->u_dt * cosmo->a_factor_internal_energy; +} + +/** + * @brief Sets the time derivative of the co-moving internal energy of a + * particle + * + * We assume a constant density for the conversion to entropy. + * * @param p The particle of interest. * @param du_dt The new time derivative of the internal energy. */ -__attribute__((always_inline)) INLINE static void hydro_set_internal_energy_dt( - struct part *restrict p, float du_dt) { +__attribute__((always_inline)) INLINE static void +hydro_set_comoving_internal_energy_dt(struct part *restrict p, float du_dt) { p->u_dt = du_dt; } + +/** + * @brief Returns the time derivative of internal energy of a particle + * + * We assume a constant density. + * + * @param p The particle of interest. + * @param cosmo Cosmology data structure + * @param du_dt The new time derivative of the internal energy. + */ +__attribute__((always_inline)) INLINE static void +hydro_set_physical_internal_energy_dt(struct part *restrict p, + const struct cosmology *cosmo, + float du_dt) { + + p->u_dt = du_dt * cosmo->a_factor_internal_energy; +} + /** * @brief Computes the hydro time-step of a given particle * @@ -308,6 +389,10 @@ __attribute__((always_inline)) INLINE static void hydro_init_part( p->density.wcount_dh = 0.f; p->rho = 0.f; p->density.rho_dh = 0.f; + p->density.div_v = 0.f; + p->density.rot_v[0] = 0.f; + p->density.rot_v[1] = 0.f; + p->density.rot_v[2] = 0.f; } /** @@ -343,6 +428,17 @@ __attribute__((always_inline)) INLINE static void hydro_end_density( p->density.rho_dh *= h_inv_dim_plus_one; p->density.wcount *= h_inv_dim; p->density.wcount_dh *= h_inv_dim_plus_one; + + const float rho_inv = 1.f / p->rho; + const float a_inv2 = cosmo->a2_inv; + + /* Finish calculation of the (physical) velocity curl components */ + p->density.rot_v[0] *= h_inv_dim_plus_one * a_inv2 * rho_inv; + p->density.rot_v[1] *= h_inv_dim_plus_one * a_inv2 * rho_inv; + p->density.rot_v[2] *= h_inv_dim_plus_one * a_inv2 * rho_inv; + + /* Finish calculation of the (physical) velocity divergence */ + p->density.div_v *= h_inv_dim_plus_one * a_inv2 * rho_inv; } /** @@ -370,6 +466,10 @@ __attribute__((always_inline)) INLINE static void hydro_part_has_no_neighbours( p->density.wcount = kernel_root * h_inv_dim; p->density.rho_dh = 0.f; p->density.wcount_dh = 0.f; + p->density.div_v = 0.f; + p->density.rot_v[0] = 0.f; + p->density.rot_v[1] = 0.f; + p->density.rot_v[2] = 0.f; } /** @@ -385,12 +485,28 @@ __attribute__((always_inline)) INLINE static void hydro_part_has_no_neighbours( * @param p The particle to act upon * @param xp The extended particle data to act upon * @param cosmo The current cosmological model. + * @param hydro_props Hydrodynamic properties. * @param dt_alpha The time-step used to evolve non-cosmological quantities such * as the artificial viscosity. */ __attribute__((always_inline)) INLINE static void hydro_prepare_force( struct part *restrict p, struct xpart *restrict xp, - const struct cosmology *cosmo, const float dt_alpha) { + const struct cosmology *cosmo, const struct hydro_props *hydro_props, + const float dt_alpha) { + + const float fac_Balsara_eps = cosmo->a_factor_Balsara_eps; + + /* Inverse of the smoothing length */ + const float h_inv = 1.f / p->h; + + /* Compute the norm of the curl */ + const float curl_v = sqrtf(p->density.rot_v[0] * p->density.rot_v[0] + + p->density.rot_v[1] * p->density.rot_v[1] + + p->density.rot_v[2] * p->density.rot_v[2]); + + /* Compute the norm of div v including the Hubble flow term */ + const float div_physical_v = p->density.div_v + 3.f * cosmo->H; + const float abs_div_physical_v = fabsf(div_physical_v); /* Compute the pressure */ const float pressure = gas_pressure_from_internal_energy(p->rho, p->u); @@ -403,10 +519,18 @@ __attribute__((always_inline)) INLINE static void hydro_prepare_force( const float grad_h_term = 1.f / (1.f + hydro_dimension_inv * p->h * p->density.rho_dh * rho_inv); + /* Compute the Balsara switch */ + /* Pre-multiply in the AV factor; hydro_props are not passed to the iact + * functions */ + const float balsara = hydro_props->viscosity.alpha * abs_div_physical_v / + (abs_div_physical_v + curl_v + + 0.0001f * fac_Balsara_eps * soundspeed * h_inv); + /* Update variables. */ p->force.f = grad_h_term; p->force.pressure = pressure; p->force.soundspeed = soundspeed; + p->force.balsara = balsara; } /** @@ -542,10 +666,10 @@ __attribute__((always_inline)) INLINE static void hydro_kick_extra( xp->u_full += p->u_dt * dt_therm; /* Apply the minimal energy limit */ - const float min_energy = + const float min_comoving_energy = hydro_props->minimal_internal_energy / cosmo->a_factor_internal_energy; - if (xp->u_full < min_energy) { - xp->u_full = min_energy; + if (xp->u_full < min_comoving_energy) { + xp->u_full = min_comoving_energy; p->u_dt = 0.f; } @@ -584,11 +708,11 @@ __attribute__((always_inline)) INLINE static void hydro_convert_quantities( xp->u_full = p->u; /* Apply the minimal energy limit */ - const float min_energy = + const float min_comoving_energy = hydro_props->minimal_internal_energy / cosmo->a_factor_internal_energy; - if (xp->u_full < min_energy) { - xp->u_full = min_energy; - p->u = min_energy; + if (xp->u_full < min_comoving_energy) { + xp->u_full = min_comoving_energy; + p->u = min_comoving_energy; p->u_dt = 0.f; } diff --git a/src/hydro/Minimal/hydro_iact.h b/src/hydro/Minimal/hydro_iact.h index 0193886f57413540d110c513ae3119ba1315f384..e060cb3562f1b319c64d6f6523b18858662312e7 100644 --- a/src/hydro/Minimal/hydro_iact.h +++ b/src/hydro/Minimal/hydro_iact.h @@ -53,6 +53,13 @@ __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) + error("Inhibited pi in interaction function!"); + if (pj->time_bin == time_bin_inhibited) + error("Inhibited pj in interaction function!"); +#endif + /* Get r. */ const float r_inv = 1.0f / sqrtf(r2); const float r = r2 * r_inv; @@ -80,6 +87,33 @@ __attribute__((always_inline)) INLINE static void runner_iact_density( pj->density.rho_dh -= mi * (hydro_dimension * wj + uj * wj_dx); pj->density.wcount += wj; pj->density.wcount_dh -= (hydro_dimension * wj + uj * wj_dx); + + /* Compute dv dot r */ + float dv[3], curlvr[3]; + + const float faci = mj * wi_dx * r_inv; + const float facj = mi * wj_dx * r_inv; + + dv[0] = pi->v[0] - pj->v[0]; + dv[1] = pi->v[1] - pj->v[1]; + dv[2] = pi->v[2] - pj->v[2]; + const float dvdr = dv[0] * dx[0] + dv[1] * dx[1] + dv[2] * dx[2]; + + pi->density.div_v -= faci * dvdr; + pj->density.div_v -= facj * dvdr; + + /* Compute dv cross r */ + curlvr[0] = dv[1] * dx[2] - dv[2] * dx[1]; + curlvr[1] = dv[2] * dx[0] - dv[0] * dx[2]; + curlvr[2] = dv[0] * dx[1] - dv[1] * dx[0]; + + pi->density.rot_v[0] += faci * curlvr[0]; + pi->density.rot_v[1] += faci * curlvr[1]; + pi->density.rot_v[2] += faci * curlvr[2]; + + pj->density.rot_v[0] += facj * curlvr[0]; + pj->density.rot_v[1] += facj * curlvr[1]; + pj->density.rot_v[2] += facj * curlvr[2]; } /** @@ -100,6 +134,13 @@ __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) + error("Inhibited pi in interaction function!"); + if (pj->time_bin == time_bin_inhibited) + error("Inhibited pj in interaction function!"); +#endif + /* Get the masses. */ const float mj = pj->mass; @@ -115,6 +156,27 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_density( pi->density.rho_dh -= mj * (hydro_dimension * wi + ui * wi_dx); pi->density.wcount += wi; pi->density.wcount_dh -= (hydro_dimension * wi + ui * wi_dx); + + /* Compute dv dot r */ + float dv[3], curlvr[3]; + + const float faci = mj * wi_dx * r_inv; + + dv[0] = pi->v[0] - pj->v[0]; + dv[1] = pi->v[1] - pj->v[1]; + dv[2] = pi->v[2] - pj->v[2]; + const float dvdr = dv[0] * dx[0] + dv[1] * dx[1] + dv[2] * dx[2]; + + pi->density.div_v -= faci * dvdr; + + /* Compute dv cross r */ + curlvr[0] = dv[1] * dx[2] - dv[2] * dx[1]; + curlvr[1] = dv[2] * dx[0] - dv[0] * dx[2]; + curlvr[2] = dv[0] * dx[1] - dv[1] * dx[0]; + + pi->density.rot_v[0] += faci * curlvr[0]; + pi->density.rot_v[1] += faci * curlvr[1]; + pi->density.rot_v[2] += faci * curlvr[2]; } /** @@ -133,6 +195,13 @@ __attribute__((always_inline)) INLINE static void runner_iact_force( float r2, const float *dx, float hi, float hj, struct part *restrict pi, struct part *restrict pj, float a, float H) { +#ifdef SWIFT_DEBUG_CHECKS + if (pi->time_bin == time_bin_inhibited) + error("Inhibited pi in interaction function!"); + if (pj->time_bin == time_bin_inhibited) + error("Inhibited pj in interaction function!"); +#endif + /* Cosmological factors entering the EoMs */ const float fac_mu = pow_three_gamma_minus_five_over_two(a); const float a2_Hubble = a * a * H; @@ -184,11 +253,15 @@ __attribute__((always_inline)) INLINE static void runner_iact_force( /* Compute sound speeds and signal velocity */ const float ci = pi->force.soundspeed; const float cj = pj->force.soundspeed; - const float v_sig = ci + cj - 3.f * mu_ij; + const float v_sig = ci + cj - const_viscosity_beta * mu_ij; + + /* Grab balsara switches */ + const float balsara_i = pi->force.balsara; + const float balsara_j = pj->force.balsara; /* Construct the full viscosity term */ const float rho_ij = 0.5f * (rhoi + rhoj); - const float visc = -0.5f * const_viscosity_alpha * v_sig * mu_ij / rho_ij; + const float visc = -0.25f * v_sig * (balsara_i + balsara_j) * mu_ij / rho_ij; /* Convolve with the kernel */ const float visc_acc_term = 0.5f * visc * (wi_dr + wj_dr) * r_inv; @@ -214,7 +287,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_force( const float sph_du_term_j = P_over_rho2_j * dvdr * r_inv * wj_dr; /* Viscosity term */ - const float visc_du_term = 0.5f * visc_acc_term * dvdr; + const float visc_du_term = 0.5f * visc_acc_term * dvdr_Hubble; /* Assemble the energy equation term */ const float du_dt_i = sph_du_term_i + visc_du_term; @@ -249,6 +322,13 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force( float r2, const float *dx, float hi, float hj, struct part *restrict pi, const struct part *restrict pj, float a, float H) { +#ifdef SWIFT_DEBUG_CHECKS + if (pi->time_bin == time_bin_inhibited) + error("Inhibited pi in interaction function!"); + if (pj->time_bin == time_bin_inhibited) + error("Inhibited pj in interaction function!"); +#endif + /* Cosmological factors entering the EoMs */ const float fac_mu = pow_three_gamma_minus_five_over_two(a); const float a2_Hubble = a * a * H; @@ -300,11 +380,15 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force( /* Compute sound speeds and signal velocity */ const float ci = pi->force.soundspeed; const float cj = pj->force.soundspeed; - const float v_sig = ci + cj - 3.f * mu_ij; + const float v_sig = ci + cj - const_viscosity_beta * mu_ij; + + /* Grab balsara switches */ + const float balsara_i = pi->force.balsara; + const float balsara_j = pj->force.balsara; /* Construct the full viscosity term */ const float rho_ij = 0.5f * (rhoi + rhoj); - const float visc = -0.5f * const_viscosity_alpha * v_sig * mu_ij / rho_ij; + const float visc = -0.25f * v_sig * (balsara_i + balsara_j) * mu_ij / rho_ij; /* Convolve with the kernel */ const float visc_acc_term = 0.5f * visc * (wi_dr + wj_dr) * r_inv; @@ -325,7 +409,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force( const float sph_du_term_i = P_over_rho2_i * dvdr * r_inv * wi_dr; /* Viscosity term */ - const float visc_du_term = 0.5f * visc_acc_term * dvdr; + const float visc_du_term = 0.5f * visc_acc_term * dvdr_Hubble; /* Assemble the energy equation term */ const float du_dt_i = sph_du_term_i + visc_du_term; diff --git a/src/hydro/Minimal/hydro_io.h b/src/hydro/Minimal/hydro_io.h index 879255640fc1a1d6a06a666c80d3860c9c31ab64..1146aa9347d443833cd481103da6f6c57d21fcbf 100644 --- a/src/hydro/Minimal/hydro_io.h +++ b/src/hydro/Minimal/hydro_io.h @@ -73,7 +73,7 @@ INLINE static void hydro_read_particles(struct part* parts, INLINE static void convert_S(const struct engine* e, const struct part* p, const struct xpart* xp, float* ret) { - ret[0] = hydro_get_comoving_entropy(p); + ret[0] = hydro_get_comoving_entropy(p, xp); } INLINE static void convert_P(const struct engine* e, const struct part* p, diff --git a/src/hydro/Minimal/hydro_part.h b/src/hydro/Minimal/hydro_part.h index c33f1b9a214cf9839f1acb965b686d4a4962865c..1d14a94f2d91bf259df54c875a32bf3072ad33b6 100644 --- a/src/hydro/Minimal/hydro_part.h +++ b/src/hydro/Minimal/hydro_part.h @@ -124,6 +124,12 @@ struct part { /*! Derivative of density with respect to h */ float rho_dh; + /*! Velocity divergence */ + float div_v; + + /*! Velocity curl */ + float rot_v[3]; + } density; /** @@ -150,6 +156,9 @@ struct part { /*! Time derivative of smoothing length */ float h_dt; + /*! Balsara switch */ + float balsara; + } force; }; diff --git a/src/hydro/Planetary/hydro.h b/src/hydro/Planetary/hydro.h index 57025b17e106ae4b71f150d2c2d319e92752ec9e..dee65a15758043d2cf526ea889b993c694d5dab4 100644 --- a/src/hydro/Planetary/hydro.h +++ b/src/hydro/Planetary/hydro.h @@ -26,8 +26,8 @@ * equations) with multiple materials. * * The thermal variable is the internal energy (u). Simple constant - * viscosity term without switches is implemented. No thermal conduction - * term is implemented. + * viscosity term with the Balsara (1995) switch (optional). + * No thermal conduction term is implemented. * * This corresponds to equations (43), (44), (45), (101), (103) and (104) with * \f$\beta=3\f$ and \f$\alpha_u=0\f$ of Price, D., Journal of Computational @@ -45,28 +45,32 @@ #include "minmax.h" /* - * Note: Define PLANETARY_SPH_BALSARA to use the Balsara (1995) switch for - * the artificial viscosity, instead of the default Monaghan (1992). - * i.e. compile with: make CFLAGS=-DPLANETARY_SPH_BALSARA to use. + * Note: Define PLANETARY_SPH_NO_BALSARA to disable the Balsara (1995) switch + * for the artificial viscosity and use the vanilla Monaghan (1992) instead. + * i.e. compile with: make CFLAGS=-DPLANETARY_SPH_NO_BALSARA */ /** - * @brief Returns the comoving internal energy of a particle + * @brief Returns the comoving internal energy of a particle at the last + * time the particle was kicked. * * For implementations where the main thermodynamic variable * is not internal energy, this function computes the internal * energy from the thermodynamic variable. * * @param p The particle of interest + * @param xp The extended data of the particle of interest. */ __attribute__((always_inline)) INLINE static float -hydro_get_comoving_internal_energy(const struct part *restrict p) { +hydro_get_comoving_internal_energy(const struct part *restrict p, + const struct xpart *restrict xp) { - return p->u; + return xp->u_full; } /** - * @brief Returns the physical internal energy of a particle + * @brief Returns the physical internal energy of a particle at the last + * time the particle was kicked. * * For implementations where the main thermodynamic variable * is not internal energy, this function computes the internal @@ -74,12 +78,40 @@ hydro_get_comoving_internal_energy(const struct part *restrict p) { * physical coordinates. * * @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 xp->u_full * cosmo->a_factor_internal_energy; +} + +/** + * @brief Returns the comoving internal energy of a particle drifted to the + * current time. + * + * @param p The particle of interest + */ +__attribute__((always_inline)) INLINE static float +hydro_get_drifted_comoving_internal_energy(const struct part *restrict p) { + + return p->u; +} + +/** + * @brief Returns the physical internal energy of a particle drifted to the + * current time. + * + * @param p The particle of interest. + * @param cosmo The cosmological model. + */ +__attribute__((always_inline)) INLINE static float +hydro_get_drifted_physical_internal_energy(const struct part *restrict p, + const struct cosmology *cosmo) { + return p->u * cosmo->a_factor_internal_energy; } @@ -120,11 +152,12 @@ __attribute__((always_inline)) INLINE static float hydro_get_physical_pressure( * the thermodynamic variable. * * @param p The particle of interest + * @param xp The extended data of the particle of interest. */ __attribute__((always_inline)) INLINE static float hydro_get_comoving_entropy( - const struct part *restrict p) { + const struct part *restrict p, const struct xpart *restrict xp) { - return gas_entropy_from_internal_energy(p->rho, p->u, p->mat_id); + return gas_entropy_from_internal_energy(p->rho, xp->u_full, p->mat_id); } /** @@ -136,10 +169,40 @@ __attribute__((always_inline)) INLINE static float hydro_get_comoving_entropy( * physical coordinates. * * @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. */ + return gas_entropy_from_internal_energy(p->rho, xp->u_full, p->mat_id); +} + +/** + * @brief Returns the comoving entropy of a particle drifted to the + * current time. + * + * @param p The particle of interest. + */ +__attribute__((always_inline)) INLINE static float +hydro_get_drifted_comoving_entropy(const struct part *restrict p) { + + return gas_entropy_from_internal_energy(p->rho, p->u, p->mat_id); +} + +/** + * @brief Returns the physical entropy of a particle drifted to the + * current time. + * + * @param p The particle of interest. + * @param cosmo The cosmological model. + */ +__attribute__((always_inline)) INLINE static float +hydro_get_drifted_physical_entropy(const struct part *restrict p, + const struct cosmology *cosmo) { /* Note: no cosmological conversion required here with our choice of * coordinates. */ @@ -244,12 +307,27 @@ __attribute__((always_inline)) INLINE static void hydro_get_drifted_velocities( * * @param p The particle of interest */ -__attribute__((always_inline)) INLINE static float hydro_get_internal_energy_dt( - const struct part *restrict p) { +__attribute__((always_inline)) INLINE static float +hydro_get_comoving_internal_energy_dt(const struct part *restrict p) { return p->u_dt; } +/** + * @brief Returns the time derivative of internal energy of a particle + * + * We assume a constant density. + * + * @param p The particle of interest + * @param cosmo Cosmology data structure + */ +__attribute__((always_inline)) INLINE static float +hydro_get_physical_internal_energy_dt(const struct part *restrict p, + const struct cosmology *cosmo) { + + return p->u_dt * cosmo->a_factor_internal_energy; +} + /** * @brief Returns the time derivative of internal energy of a particle * @@ -258,12 +336,29 @@ __attribute__((always_inline)) INLINE static float hydro_get_internal_energy_dt( * @param p The particle of interest. * @param du_dt The new time derivative of the internal energy. */ -__attribute__((always_inline)) INLINE static void hydro_set_internal_energy_dt( - struct part *restrict p, float du_dt) { +__attribute__((always_inline)) INLINE static void +hydro_set_comoving_internal_energy_dt(struct part *restrict p, float du_dt) { p->u_dt = du_dt; } +/** + * @brief Returns the time derivative of internal energy of a particle + * + * We assume a constant density. + * + * @param p The particle of interest. + * @param cosmo Cosmology data structure + * @param du_dt The new time derivative of the internal energy. + */ +__attribute__((always_inline)) INLINE static void +hydro_set_physical_internal_energy_dt(struct part *restrict p, + const struct cosmology *cosmo, + float du_dt) { + + p->u_dt = du_dt * cosmo->a_factor_internal_energy; +} + /** * @brief Computes the hydro time-step of a given particle * @@ -393,14 +488,15 @@ __attribute__((always_inline)) INLINE static void hydro_part_has_no_neighbours( * @param p The particle to act upon * @param xp The extended particle data to act upon * @param cosmo The current cosmological model. + * @param hydro_props Hydrodynamic properties. * @param dt_alpha The time-step used to evolve non-cosmological quantities such * as the artificial viscosity. */ __attribute__((always_inline)) INLINE static void hydro_prepare_force( struct part *restrict p, struct xpart *restrict xp, - const struct cosmology *cosmo, const float dt_alpha) { + const struct cosmology *cosmo, const struct hydro_props *hydro_props, + const float dt_alpha) { -#ifdef PLANETARY_SPH_BALSARA const float fac_mu = cosmo->a_factor_mu; /* Compute the norm of the curl */ @@ -410,7 +506,6 @@ __attribute__((always_inline)) INLINE static void hydro_prepare_force( /* Compute the norm of div v */ const float abs_div_v = fabsf(p->density.div_v); -#endif // PLANETARY_SPH_BALSARA /* Compute the pressure */ const float pressure = @@ -432,20 +527,20 @@ __attribute__((always_inline)) INLINE static void hydro_prepare_force( grad_h_term = 0.f; } -#ifdef PLANETARY_SPH_BALSARA - /* Compute the Balsara switch */ + /* Compute the Balsara switch */ +#ifdef PLANETARY_SPH_NO_BALSARA + const float balsara = hydro_props->viscosity.alpha; +#else const float balsara = - abs_div_v / (abs_div_v + curl_v + 0.0001f * fac_mu * soundspeed / p->h); -#endif // PLANETARY_SPH_BALSARA + hydro_props->viscosity.alpha * abs_div_v / + (abs_div_v + curl_v + 0.0001f * fac_mu * soundspeed / p->h); +#endif /* Update variables. */ p->force.f = grad_h_term; p->force.pressure = pressure; p->force.soundspeed = soundspeed; - -#ifdef PLANETARY_SPH_BALSARA p->force.balsara = balsara; -#endif // PLANETARY_SPH_BALSARA } /** diff --git a/src/hydro/Planetary/hydro_iact.h b/src/hydro/Planetary/hydro_iact.h index bf96034696806e3adff1d8ba7f385af65461b9ea..19ee002b85c1b0bc8ed621a029059cd02c5e670f 100644 --- a/src/hydro/Planetary/hydro_iact.h +++ b/src/hydro/Planetary/hydro_iact.h @@ -25,8 +25,8 @@ * @brief Minimal conservative implementation of SPH (Neighbour loop equations) * * The thermal variable is the internal energy (u). Simple constant - * viscosity term without switches is implemented. No thermal conduction - * term is implemented. + * viscosity term with the Balsara (1995) switch (optional). + * No thermal conduction term is implemented. * * This corresponds to equations (43), (44), (45), (101), (103) and (104) with * \f$\beta=3\f$ and \f$\alpha_u=0\f$ of Price, D., Journal of Computational @@ -176,11 +176,9 @@ __attribute__((always_inline)) INLINE static void runner_iact_force( (pi->v[1] - pj->v[1]) * dx[1] + (pi->v[2] - pj->v[2]) * dx[2] + a2_Hubble * r2; -#ifdef PLANETARY_SPH_BALSARA /* Balsara term */ const float balsara_i = pi->force.balsara; const float balsara_j = pj->force.balsara; -#endif // PLANETARY_SPH_BALSARA /* Are the particles moving towards each other? */ const float omega_ij = min(dvdr, 0.f); @@ -189,16 +187,11 @@ __attribute__((always_inline)) INLINE static void runner_iact_force( /* Compute sound speeds and signal velocity */ const float ci = pi->force.soundspeed; const float cj = pj->force.soundspeed; - const float v_sig = ci + cj - 3.f * mu_ij; + const float v_sig = ci + cj - const_viscosity_beta * mu_ij; /* Now construct the full viscosity term */ const float rho_ij = 0.5f * (rhoi + rhoj); -#ifdef PLANETARY_SPH_BALSARA - const float visc = -0.25f * const_viscosity_alpha * v_sig * mu_ij * - (balsara_i + balsara_j) / rho_ij; -#else - const float visc = -0.5f * const_viscosity_alpha * v_sig * mu_ij / rho_ij; -#endif // PLANETARY_SPH_BALSARA + const float visc = -0.25f * v_sig * mu_ij * (balsara_i + balsara_j) / rho_ij; /* Convolve with the kernel */ const float visc_acc_term = 0.5f * visc * (wi_dr + wj_dr) * r_inv; @@ -300,11 +293,9 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force( (pi->v[1] - pj->v[1]) * dx[1] + (pi->v[2] - pj->v[2]) * dx[2] + a2_Hubble * r2; -#ifdef PLANETARY_SPH_BALSARA /* Balsara term */ const float balsara_i = pi->force.balsara; const float balsara_j = pj->force.balsara; -#endif // PLANETARY_SPH_BALSARA /* Are the particles moving towards each other? */ const float omega_ij = min(dvdr, 0.f); @@ -315,16 +306,11 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force( const float cj = pj->force.soundspeed; /* Signal velocity */ - const float v_sig = ci + cj - 3.f * mu_ij; + const float v_sig = ci + cj - const_viscosity_beta * mu_ij; /* Construct the full viscosity term */ const float rho_ij = 0.5f * (rhoi + rhoj); -#ifdef PLANETARY_SPH_BALSARA - const float visc = -0.25f * const_viscosity_alpha * v_sig * mu_ij * - (balsara_i + balsara_j) / rho_ij; -#else - const float visc = -0.5f * const_viscosity_alpha * v_sig * mu_ij / rho_ij; -#endif // PLANETARY_SPH_BALSARA + const float visc = -0.25f * v_sig * mu_ij * (balsara_i + balsara_j) / rho_ij; /* Convolve with the kernel */ const float visc_acc_term = 0.5f * visc * (wi_dr + wj_dr) * r_inv; diff --git a/src/hydro/Planetary/hydro_io.h b/src/hydro/Planetary/hydro_io.h index afb37d884494fd02e30c143194804a2b49a77be0..1b84f8d6db295694846ffd26a422ce158aad0c60 100644 --- a/src/hydro/Planetary/hydro_io.h +++ b/src/hydro/Planetary/hydro_io.h @@ -25,8 +25,8 @@ * @brief Minimal conservative implementation of SPH (i/o routines) * * The thermal variable is the internal energy (u). Simple constant - * viscosity term without switches is implemented. No thermal conduction - * term is implemented. + * viscosity term with the Balsara (1995) switch (optional). + * No thermal conduction term is implemented. * * This corresponds to equations (43), (44), (45), (101), (103) and (104) with * \f$\beta=3\f$ and \f$\alpha_u=0\f$ of @@ -76,7 +76,7 @@ INLINE static void hydro_read_particles(struct part* parts, INLINE static void convert_S(const struct engine* e, const struct part* p, const struct xpart* xp, float* ret) { - ret[0] = hydro_get_comoving_entropy(p); + ret[0] = hydro_get_comoving_entropy(p, xp); } INLINE static void convert_P(const struct engine* e, const struct part* p, @@ -197,14 +197,14 @@ INLINE static void hydro_write_flavour(hid_t h_grpsph) { /* Viscosity and thermal conduction */ /* Nothing in this minimal model... */ io_write_attribute_s(h_grpsph, "Thermal Conductivity Model", "No treatment"); -#ifdef PLANETARY_SPH_BALSARA +#ifdef PLANETARY_SPH_NO_BALSARA + io_write_attribute_s(h_grpsph, "Viscosity Model", + "Minimal treatment as in Monaghan (1992)"); +#else io_write_attribute_s( h_grpsph, "Viscosity Model", "as in Springel (2005), i.e. Monaghan (1992) with Balsara (1995) switch"); -#else - io_write_attribute_s(h_grpsph, "Viscosity Model", - "Minimal treatment as in Monaghan (1992)"); -#endif // PLANETARY_SPH_BALSARA +#endif /* Time integration properties */ io_write_attribute_f(h_grpsph, "Maximal Delta u change over dt", diff --git a/src/hydro/Planetary/hydro_part.h b/src/hydro/Planetary/hydro_part.h index 7d1fc8f6729992bfdf2eeaba6e33cc9a7b071655..4087cef62e873231a556f82869a7f6d848c8d72c 100644 --- a/src/hydro/Planetary/hydro_part.h +++ b/src/hydro/Planetary/hydro_part.h @@ -25,8 +25,8 @@ * @brief Minimal conservative implementation of SPH (Particle definition) * * The thermal variable is the internal energy (u). Simple constant - * viscosity term without switches is implemented. No thermal conduction - * term is implemented. + * viscosity term with the Balsara (1995) switch (optional). + * No thermal conduction term is implemented. * * This corresponds to equations (43), (44), (45), (101), (103) and (104) with * \f$\beta=3\f$ and \f$\alpha_u=0\f$ of Price, D., Journal of Computational @@ -126,13 +126,11 @@ struct part { /*! Derivative of density with respect to h */ float rho_dh; -#ifdef PLANETARY_SPH_BALSARA /*! Velocity divergence. */ float div_v; /*! Velocity curl. */ float rot_v[3]; -#endif // PLANETARY_SPH_BALSARA } density; @@ -160,10 +158,8 @@ struct part { /*! Time derivative of smoothing length */ float h_dt; -#ifdef PLANETARY_SPH_BALSARA /*! Balsara switch */ float balsara; -#endif // PLANETARY_SPH_BALSARA } force; }; diff --git a/src/hydro/PressureEnergy/hydro.h b/src/hydro/PressureEnergy/hydro.h index 57be32072ad0cb8ba5187db9ff78115ce9fb5217..3274c1b1b58adf0fa6a4c94132fa5a87186e59ce 100644 --- a/src/hydro/PressureEnergy/hydro.h +++ b/src/hydro/PressureEnergy/hydro.h @@ -49,22 +49,26 @@ #include <float.h> /** - * @brief Returns the comoving internal energy of a particle + * @brief Returns the comoving internal energy of a particle at the last + * time the particle was kicked. * * For implementations where the main thermodynamic variable * is not internal energy, this function computes the internal * energy from the thermodynamic variable. * * @param p The particle of interest + * @param xp The extended data of the particle of interest. */ __attribute__((always_inline)) INLINE static float -hydro_get_comoving_internal_energy(const struct part *restrict p) { +hydro_get_comoving_internal_energy(const struct part *restrict p, + const struct xpart *restrict xp) { - return p->u; + return xp->u_full; } /** - * @brief Returns the physical internal energy of a particle + * @brief Returns the physical internal energy of a particle at the last + * time the particle was kicked. * * For implementations where the main thermodynamic variable * is not internal energy, this function computes the internal @@ -72,12 +76,40 @@ hydro_get_comoving_internal_energy(const struct part *restrict p) { * physical coordinates. * * @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 xp->u_full * cosmo->a_factor_internal_energy; +} + +/** + * @brief Returns the comoving internal energy of a particle drifted to the + * current time. + * + * @param p The particle of interest + */ +__attribute__((always_inline)) INLINE static float +hydro_get_drifted_comoving_internal_energy(const struct part *restrict p) { + + return p->u; +} + +/** + * @brief Returns the physical internal energy of a particle drifted to the + * current time. + * + * @param p The particle of interest. + * @param cosmo The cosmological model. + */ +__attribute__((always_inline)) INLINE static float +hydro_get_drifted_physical_internal_energy(const struct part *restrict p, + const struct cosmology *cosmo) { + return p->u * cosmo->a_factor_internal_energy; } @@ -110,33 +142,66 @@ __attribute__((always_inline)) INLINE static float hydro_get_physical_pressure( } /** - * @brief Returns the comoving entropy of a particle + * @brief Returns the comoving entropy of a particle at the last + * time the particle was kicked. * * For implementations where the main thermodynamic variable * is not entropy, this function computes the entropy from * the thermodynamic variable. * * @param p The particle of interest + * @param xp The extended data of the particle of interest. */ __attribute__((always_inline)) INLINE static float hydro_get_comoving_entropy( - const struct part *restrict p) { + const struct part *restrict p, const struct xpart *restrict xp) { - return gas_entropy_from_internal_energy(p->rho, p->u); + return gas_entropy_from_internal_energy(p->rho, xp->u_full); } /** - * @brief Returns the physical entropy of a particle + * @brief Returns the physical entropy of a particle at the last + * time the particle was kicked. * * For implementations where the main thermodynamic variable * is not entropy, this function computes the entropy from * the thermodynamic variable and converts it to * physical coordinates. * - * @param p The particle of interest + * @param 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. */ + return gas_entropy_from_internal_energy(p->rho, xp->u_full); +} + +/** + * @brief Returns the comoving entropy of a particle drifted to the + * current time. + * + * @param p The particle of interest. + */ +__attribute__((always_inline)) INLINE static float +hydro_get_drifted_comoving_entropy(const struct part *restrict p) { + + return gas_entropy_from_internal_energy(p->rho, p->u); +} + +/** + * @brief Returns the physical entropy of a particle drifted to the + * current time. + * + * @param p The particle of interest. + * @param cosmo The cosmological model. + */ +__attribute__((always_inline)) INLINE static float +hydro_get_drifted_physical_entropy(const struct part *restrict p, + const struct cosmology *cosmo) { /* Note: no cosmological conversion required here with our choice of * coordinates. */ @@ -245,12 +310,27 @@ __attribute__((always_inline)) INLINE static void hydro_get_drifted_velocities( * * @param p The particle of interest */ -__attribute__((always_inline)) INLINE static float hydro_get_internal_energy_dt( - const struct part *restrict p) { +__attribute__((always_inline)) INLINE static float +hydro_get_comoving_internal_energy_dt(const struct part *restrict p) { return p->u_dt; } +/** + * @brief Returns the time derivative of internal energy of a particle + * + * We assume a constant density. + * + * @param p The particle of interest + * @param cosmo Cosmology data structure + */ +__attribute__((always_inline)) INLINE static float +hydro_get_physical_internal_energy_dt(const struct part *restrict p, + const struct cosmology *cosmo) { + + return p->u_dt * cosmo->a_factor_internal_energy; +} + /** * @brief Sets the time derivative of internal energy of a particle * @@ -259,12 +339,29 @@ __attribute__((always_inline)) INLINE static float hydro_get_internal_energy_dt( * @param p The particle of interest. * @param du_dt The new time derivative of the internal energy. */ -__attribute__((always_inline)) INLINE static void hydro_set_internal_energy_dt( - struct part *restrict p, float du_dt) { +__attribute__((always_inline)) INLINE static void +hydro_set_comoving_internal_energy_dt(struct part *restrict p, float du_dt) { p->u_dt = du_dt; } +/** + * @brief Returns the time derivative of internal energy of a particle + * + * We assume a constant density. + * + * @param p The particle of interest. + * @param cosmo Cosmology data structure + * @param du_dt The new time derivative of the internal energy. + */ +__attribute__((always_inline)) INLINE static void +hydro_set_physical_internal_energy_dt(struct part *restrict p, + const struct cosmology *cosmo, + float du_dt) { + + p->u_dt = du_dt * cosmo->a_factor_internal_energy; +} + /** * @brief Computes the hydro time-step of a given particle * @@ -427,12 +524,14 @@ __attribute__((always_inline)) INLINE static void hydro_part_has_no_neighbours( * @param p The particle to act upon * @param xp The extended particle data to act upon * @param cosmo The current cosmological model. + * @param hydro_props Hydrodynamic properties. * @param dt_alpha The time-step used to evolve non-cosmological quantities such * as the artificial viscosity. */ __attribute__((always_inline)) INLINE static void hydro_prepare_force( struct part *restrict p, struct xpart *restrict xp, - const struct cosmology *cosmo, const float dt_alpha) { + const struct cosmology *cosmo, const struct hydro_props *hydro_props, + const float dt_alpha) { const float fac_mu = cosmo->a_factor_mu; @@ -449,7 +548,8 @@ __attribute__((always_inline)) INLINE static void hydro_prepare_force( /* Compute the Balsara switch */ const float balsara = - abs_div_v / (abs_div_v + curl_v + 0.0001f * soundspeed * fac_mu / p->h); + hydro_props->viscosity.alpha * abs_div_v / + (abs_div_v + curl_v + 0.0001f * soundspeed * fac_mu / p->h); /* Compute the "grad h" term */ const float common_factor = p->h / (hydro_dimension * p->density.wcount); diff --git a/src/hydro/PressureEnergy/hydro_iact.h b/src/hydro/PressureEnergy/hydro_iact.h index e23b06247e255bee088bd920dee46919443abd96..2ed7fe8cb8112c42de933a2ca315966e67108f0a 100644 --- a/src/hydro/PressureEnergy/hydro_iact.h +++ b/src/hydro/PressureEnergy/hydro_iact.h @@ -244,7 +244,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_force( /* Compute sound speeds and signal velocity */ const float ci = pi->force.soundspeed; const float cj = pj->force.soundspeed; - const float v_sig = ci + cj - 3.f * mu_ij; + const float v_sig = ci + cj - const_viscosity_beta * mu_ij; /* Balsara term */ const float balsara_i = pi->force.balsara; @@ -252,8 +252,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_force( /* Construct the full viscosity term */ const float rho_ij = 0.5f * (rhoi + rhoj); - const float visc = -0.25f * const_viscosity_alpha * v_sig * mu_ij * - (balsara_i + balsara_j) / rho_ij; + const float visc = -0.25f * v_sig * mu_ij * (balsara_i + balsara_j) / rho_ij; /* Convolve with the kernel */ const float visc_acc_term = 0.5f * visc * (wi_dr + wj_dr) * r_inv; @@ -372,7 +371,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force( /* Compute sound speeds and signal velocity */ const float ci = pi->force.soundspeed; const float cj = pj->force.soundspeed; - const float v_sig = ci + cj - 3.f * mu_ij; + const float v_sig = ci + cj - const_viscosity_beta * mu_ij; /* Balsara term */ const float balsara_i = pi->force.balsara; @@ -380,8 +379,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force( /* Construct the full viscosity term */ const float rho_ij = 0.5f * (rhoi + rhoj); - const float visc = -0.25f * const_viscosity_alpha * v_sig * mu_ij * - (balsara_i + balsara_j) / rho_ij; + const float visc = -0.25f * v_sig * mu_ij * (balsara_i + balsara_j) / rho_ij; /* Convolve with the kernel */ const float visc_acc_term = 0.5f * visc * (wi_dr + wj_dr) * r_inv; diff --git a/src/hydro/PressureEnergy/hydro_io.h b/src/hydro/PressureEnergy/hydro_io.h index a69bfdac425ba671dbadc237fe6647bbee0072b9..06762c6124c2c726c4e687980455ab956a5fa79e 100644 --- a/src/hydro/PressureEnergy/hydro_io.h +++ b/src/hydro/PressureEnergy/hydro_io.h @@ -68,16 +68,10 @@ INLINE static void hydro_read_particles(struct part* parts, UNIT_CONV_DENSITY, parts, rho); } -INLINE static void convert_u(const struct engine* e, const struct part* p, - const struct xpart* xp, float* ret) { - - ret[0] = hydro_get_comoving_internal_energy(p); -} - INLINE static void convert_S(const struct engine* e, const struct part* p, const struct xpart* xp, float* ret) { - ret[0] = hydro_get_comoving_entropy(p); + ret[0] = hydro_get_comoving_entropy(p, xp); } INLINE static void convert_P(const struct engine* e, const struct part* p, @@ -169,9 +163,8 @@ INLINE static void hydro_write_particles(const struct part* parts, io_make_output_field("Masses", FLOAT, 1, UNIT_CONV_MASS, parts, mass); list[3] = io_make_output_field("SmoothingLength", FLOAT, 1, UNIT_CONV_LENGTH, parts, h); - list[4] = io_make_output_field_convert_part("InternalEnergy", FLOAT, 1, - UNIT_CONV_ENERGY_PER_UNIT_MASS, - parts, xparts, convert_u); + list[4] = io_make_output_field("InternalEnergy", FLOAT, 1, + UNIT_CONV_ENERGY_PER_UNIT_MASS, parts, u); list[5] = io_make_output_field("ParticleIDs", ULONGLONG, 1, UNIT_CONV_NO_UNITS, parts, id); list[6] = diff --git a/src/hydro/PressureEntropy/hydro.h b/src/hydro/PressureEntropy/hydro.h index a5c0c62c385a2304adb27ccbad4b7f6769d8b5d0..b16d24cfcee9407c8213b1e17465005884da6617 100644 --- a/src/hydro/PressureEntropy/hydro.h +++ b/src/hydro/PressureEntropy/hydro.h @@ -42,26 +42,58 @@ #include "minmax.h" /** - * @brief Returns the comoving internal energy of a particle + * @brief Returns the comoving internal energy of a particle at the last + * time the particle was kicked. * * @param p The particle of interest + * @param xp The extended data of the particle of interest. */ __attribute__((always_inline)) INLINE static float -hydro_get_comoving_internal_energy(const struct part *restrict p) { +hydro_get_comoving_internal_energy(const struct part *restrict p, + const struct xpart *restrict xp) { - return gas_internal_energy_from_entropy(p->rho_bar, p->entropy); + return gas_internal_energy_from_entropy(p->rho_bar, xp->entropy_full); } /** - * @brief Returns the physical internal energy of a particle + * @brief Returns the physical internal energy of a particle at the last + * time the particle was kicked. * - * @param p The particle of interest + * @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 gas_internal_energy_from_entropy(p->rho_bar * cosmo->a3_inv, + xp->entropy_full); +} +/** + * @brief Returns the comoving internal energy of a particle drifted to the + * current time. + * + * @param p The particle of interest + */ +__attribute__((always_inline)) INLINE static float +hydro_get_drifted_comoving_internal_energy(const struct part *restrict p) { + + return gas_internal_energy_from_entropy(p->rho_bar, p->entropy); +} + +/** + * @brief Returns the physical internal energy of a particle drifted to the + * current time. + * + * @param p The particle of interest. + * @param cosmo The cosmological model. + */ +__attribute__((always_inline)) INLINE static float +hydro_get_drifted_physical_internal_energy(const struct part *restrict p, + const struct cosmology *cosmo) { + return gas_internal_energy_from_entropy(p->rho_bar * cosmo->a3_inv, p->entropy); } @@ -89,24 +121,57 @@ __attribute__((always_inline)) INLINE static float hydro_get_physical_pressure( } /** - * @brief Returns the comoving entropy of a particle + * @brief Returns the comoving entropy of a particle at the last + * time the particle was kicked. * - * @param p The particle of interest + * @param p The particle of interest. + * @param xp The extended data of the particle of interest. */ __attribute__((always_inline)) INLINE static float hydro_get_comoving_entropy( - const struct part *restrict p) { + const struct part *restrict p, const struct xpart *restrict xp) { - return p->entropy; + return xp->entropy_full; } /** - * @brief Returns the physical entropy of a particle + * @brief Returns the physical entropy of a particl at the last + * time the particle was kicked. * * @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. */ + return xp->entropy_full; +} + +/** + * @brief Returns the comoving entropy of a particle drifted to the + * current time. + * + * @param p The particle of interest. + */ +__attribute__((always_inline)) INLINE static float +hydro_get_drifted_comoving_entropy(const struct part *restrict p) { + + return p->entropy; +} + +/** + * @brief Returns the physical entropy of a particle drifted to the + * current time. + * + * @param p The particle of interest. + * @param cosmo The cosmological model. + */ +__attribute__((always_inline)) INLINE static float +hydro_get_drifted_physical_entropy(const struct part *restrict p, + const struct cosmology *cosmo) { /* Note: no cosmological conversion required here with our choice of * coordinates. */ @@ -210,12 +275,28 @@ __attribute__((always_inline)) INLINE static void hydro_get_drifted_velocities( * * @param p The particle of interest */ -__attribute__((always_inline)) INLINE static float hydro_get_internal_energy_dt( - const struct part *restrict p) { +__attribute__((always_inline)) INLINE static float +hydro_get_comoving_internal_energy_dt(const struct part *restrict p) { return gas_internal_energy_from_entropy(p->rho_bar, p->entropy_dt); } +/** + * @brief Returns the time derivative of physical internal energy of a particle + * + * We assume a constant density. + * + * @param p The particle of interest. + * @param cosmo The cosmological model. + */ +__attribute__((always_inline)) INLINE static float +hydro_get_physical_internal_energy_dt(const struct part *restrict p, + const struct cosmology *cosmo) { + + return gas_internal_energy_from_entropy(p->rho_bar * cosmo->a3_inv, + p->entropy_dt); +} + /** * @brief Returns the time derivative of internal energy of a particle * @@ -224,12 +305,29 @@ __attribute__((always_inline)) INLINE static float hydro_get_internal_energy_dt( * @param p The particle of interest. * @param du_dt The new time derivative of the internal energy. */ -__attribute__((always_inline)) INLINE static void hydro_set_internal_energy_dt( - struct part *restrict p, float du_dt) { +__attribute__((always_inline)) INLINE static void +hydro_set_comoving_internal_energy_dt(struct part *restrict p, float du_dt) { p->entropy_dt = gas_entropy_from_internal_energy(p->rho_bar, du_dt); } +/** + * @brief Sets the time derivative of the physical internal energy of a particle + * + * We assume a constant density for the conversion to entropy. + * + * @param p The particle of interest. + * @param cosmo Cosmology data structure + * @param du_dt The time derivative of the internal energy. + */ +__attribute__((always_inline)) INLINE static void +hydro_set_physical_internal_energy_dt(struct part *restrict p, + const struct cosmology *restrict cosmo, + float du_dt) { + p->entropy_dt = + gas_entropy_from_internal_energy(p->rho_bar * cosmo->a3_inv, du_dt); +} + /** * @brief Computes the hydro time-step of a given particle * @@ -380,12 +478,14 @@ __attribute__((always_inline)) INLINE static void hydro_part_has_no_neighbours( * @param p The particle to act upon * @param xp The extended particle data to act upon * @param cosmo The current cosmological model. + * @param hydro_props Hydrodynamic properties. * @param dt_alpha The time-step used to evolve non-cosmological quantities such * as the artificial viscosity. */ __attribute__((always_inline)) INLINE static void hydro_prepare_force( struct part *restrict p, struct xpart *restrict xp, - const struct cosmology *cosmo, const float dt_alpha) { + const struct cosmology *cosmo, const struct hydro_props *hydro_props, + const float dt_alpha) { const float fac_mu = cosmo->a_factor_mu; @@ -405,7 +505,8 @@ __attribute__((always_inline)) INLINE static void hydro_prepare_force( /* Compute the Balsara switch */ const float balsara = - abs_div_v / (abs_div_v + curl_v + 0.0001f * soundspeed * fac_mu / p->h); + hydro_props->viscosity.alpha * abs_div_v / + (abs_div_v + curl_v + 0.0001f * soundspeed * fac_mu / p->h); /* Divide the pressure by the density squared to get the SPH term */ const float rho_bar_inv = 1.f / p->rho_bar; diff --git a/src/hydro/PressureEntropy/hydro_iact.h b/src/hydro/PressureEntropy/hydro_iact.h index b8f8c1983a3b1fb67781f7228194deb770273988..a018b39a99be5ed691485d93bd8dfd1735378bda 100644 --- a/src/hydro/PressureEntropy/hydro_iact.h +++ b/src/hydro/PressureEntropy/hydro_iact.h @@ -259,12 +259,11 @@ __attribute__((always_inline)) INLINE static void runner_iact_force( const float mu_ij = fac_mu * r_inv * omega_ij; /* This is 0 or negative */ /* Signal velocity */ - const float v_sig = ci + cj - 3.f * mu_ij; + const float v_sig = ci + cj - const_viscosity_beta * mu_ij; /* Now construct the full viscosity term */ const float rho_ij = 0.5f * (rhoi + rhoj); - const float visc = -0.25f * const_viscosity_alpha * v_sig * mu_ij * - (balsara_i + balsara_j) / rho_ij; + const float visc = -0.25f * v_sig * mu_ij * (balsara_i + balsara_j) / rho_ij; /* Now, convolve with the kernel */ const float visc_term = 0.5f * visc * (wi_dr + wj_dr); @@ -373,12 +372,11 @@ __attribute__((always_inline)) INLINE static void runner_iact_nonsym_force( const float mu_ij = fac_mu * r_inv * omega_ij; /* This is 0 or negative */ /* Signal velocity */ - const float v_sig = ci + cj - 3.f * mu_ij; + const float v_sig = ci + cj - const_viscosity_beta * mu_ij; /* Now construct the full viscosity term */ const float rho_ij = 0.5f * (rhoi + rhoj); - const float visc = -0.25f * const_viscosity_alpha * v_sig * mu_ij * - (balsara_i + balsara_j) / rho_ij; + const float visc = -0.25f * v_sig * mu_ij * (balsara_i + balsara_j) / rho_ij; /* Now, convolve with the kernel */ const float visc_term = 0.5f * visc * (wi_dr + wj_dr); diff --git a/src/hydro/PressureEntropy/hydro_io.h b/src/hydro/PressureEntropy/hydro_io.h index 8c11bf6e334e18b10217e90f6573a42e40880955..e9397bf6108b8bc16658157e424055274f05f23c 100644 --- a/src/hydro/PressureEntropy/hydro_io.h +++ b/src/hydro/PressureEntropy/hydro_io.h @@ -71,7 +71,7 @@ INLINE static void hydro_read_particles(struct part* parts, INLINE static void convert_u(const struct engine* e, const struct part* p, const struct xpart* xp, float* ret) { - ret[0] = hydro_get_comoving_internal_energy(p); + ret[0] = hydro_get_comoving_internal_energy(p, xp); } INLINE static void convert_P(const struct engine* e, const struct part* p, @@ -194,8 +194,6 @@ INLINE static void hydro_write_flavour(hid_t h_grpsph) { io_write_attribute_s( h_grpsph, "Viscosity Model", "as in Springel (2005), i.e. Monaghan (1992) with Balsara (1995) switch"); - io_write_attribute_f(h_grpsph, "Viscosity alpha", const_viscosity_alpha); - io_write_attribute_f(h_grpsph, "Viscosity beta", 3.f); /* Time integration properties */ io_write_attribute_f(h_grpsph, "Maximal Delta u change over dt", diff --git a/src/hydro/Shadowswift/hydro.h b/src/hydro/Shadowswift/hydro.h index 0715223850023be90294e5ccaa43c197c8eab2d4..7e38aa6b57f383564e96d9fea24730926c0ac70b 100644 --- a/src/hydro/Shadowswift/hydro.h +++ b/src/hydro/Shadowswift/hydro.h @@ -295,12 +295,14 @@ __attribute__((always_inline)) INLINE static void hydro_part_has_no_neighbours( * @param p The particle to act upon * @param xp The extended particle data to act upon * @param cosmo The current cosmological model. + * @param hydro_props Hydrodynamic properties. * @param dt_alpha The time-step used to evolve non-cosmological quantities such * as the artificial viscosity. */ __attribute__((always_inline)) INLINE static void hydro_prepare_force( struct part* restrict p, struct xpart* restrict xp, - const struct cosmology* cosmo, const float dt_alpha) { + const struct cosmology* cosmo, const struct hydro_props* hydro_props, + const float dt_alpha) { /* Initialize time step criterion variables */ p->timestepvars.vmax = 0.0f; diff --git a/src/hydro_properties.c b/src/hydro_properties.c index 260bbdd79c8a9ca380d93142a073674e2f9a489a..2b1cd42055c66768e943241c75298e53e0bf75a8 100644 --- a/src/hydro_properties.c +++ b/src/hydro_properties.c @@ -40,6 +40,13 @@ #define hydro_props_default_init_temp 0.f #define hydro_props_default_min_temp 0.f #define hydro_props_default_H_ionization_temperature 1e4 +#define hydro_props_default_viscosity_alpha 0.8f +#define hydro_props_default_viscosity_alpha_min \ + 0.1f /* Values taken from (Price,2004), not used in legacy gadget mode */ +#define hydro_props_default_viscosity_alpha_max \ + 2.0f /* Values taken from (Price,2004), not used in legacy gadget mode */ +#define hydro_props_default_viscosity_length \ + 0.1f /* Values taken from (Price,2004), not used in legacy gadget mode */ /** * @brief Initialize the global properties of the hydro scheme. @@ -112,6 +119,21 @@ 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); + /* 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); + + p->viscosity.alpha_max = + parser_get_opt_param_float(params, "SPH:viscosity_alpha_max", + hydro_props_default_viscosity_alpha_max); + + p->viscosity.alpha_min = + parser_get_opt_param_float(params, "SPH:viscosity_alpha_min", + hydro_props_default_viscosity_alpha_min); + + p->viscosity.length = parser_get_opt_param_float( + params, "SPH:viscosity_length", hydro_props_default_viscosity_length); + /* Compute the initial energy (Note the temp. read is in internal units) */ /* u_init = k_B T_init / (mu m_p (gamma - 1)) */ double u_init = phys_const->const_boltzmann_k / phys_const->const_proton_mass; @@ -164,6 +186,12 @@ void hydro_props_print(const struct hydro_props *p) { message("Hydrodynamic integration: CFL parameter: %.4f.", p->CFL_condition); + message( + "Artificial viscosity parameters set to alpha: %.3f, max: %.3f, " + "min: %.3f, length: %.3f.", + p->viscosity.alpha, p->viscosity.alpha_max, p->viscosity.alpha_min, + p->viscosity.length); + message( "Hydrodynamic integration: Max change of volume: %.2f " "(max|dlog(h)/dt|=%f).", @@ -183,13 +211,14 @@ void hydro_props_print(const struct hydro_props *p) { message("Minimal gas temperature set to %f", p->minimal_temperature); // Matthieu: Temporary location for this i/o business. + #ifdef PLANETARY_SPH -#ifdef PLANETARY_SPH_BALSARA - message("Planetary SPH: Balsara switch enabled"); +#ifdef PLANETARY_SPH_NO_BALSARA + message("Planetary SPH: Balsara switch DISABLED"); #else - message("Planetary SPH: Balsara switch disabled"); -#endif // PLANETARY_SPH_BALSARA -#endif // PLANETARY_SPH + message("Planetary SPH: Balsara switch ENABLED"); +#endif +#endif } #if defined(HAVE_HDF5) @@ -220,10 +249,54 @@ void hydro_props_print_snapshot(hid_t h_grpsph, const struct hydro_props *p) { p->hydrogen_mass_fraction); io_write_attribute_f(h_grpsph, "Hydrogen ionization transition temperature", p->hydrogen_ionization_temperature); - io_write_attribute_f(h_grpsph, "Alpha viscosity", const_viscosity_alpha); + io_write_attribute_f(h_grpsph, "Alpha viscosity", p->viscosity.alpha); + io_write_attribute_f(h_grpsph, "Alpha viscosity (max)", + p->viscosity.alpha_max); + io_write_attribute_f(h_grpsph, "Alpha viscosity (min)", + p->viscosity.alpha_min); + io_write_attribute_f(h_grpsph, "Viscosity decay length", p->viscosity.length); + io_write_attribute_f(h_grpsph, "Beta viscosity", const_viscosity_beta); } #endif +/** + * @brief Initialises a hydro_props struct with somewhat useful values for + * the automated test suite. This is not intended for production use, + * but rather to fill for the purposes of mocking. + * + * @param p the struct + */ +void hydro_props_init_no_hydro(struct hydro_props *p) { + p->eta_neighbours = 1.2348; + p->h_tolerance = hydro_props_default_h_tolerance; + p->target_neighbours = pow_dimension(p->eta_neighbours) * kernel_norm; + const float delta_eta = p->eta_neighbours * (1.f + p->h_tolerance); + p->delta_neighbours = + (pow_dimension(delta_eta) - pow_dimension(p->eta_neighbours)) * + kernel_norm; + p->h_max = hydro_props_default_h_max; + p->max_smoothing_iterations = hydro_props_default_max_iterations; + p->CFL_condition = 0.1; + p->log_max_h_change = logf(powf(1.4, hydro_dimension_inv)); + + /* These values are inconsistent and in a production run would probably lead + to a crash. Again, this function is intended for mocking use in unit tests + and is _not_ to be used otherwise! */ + p->minimal_temperature = hydro_props_default_min_temp; + p->minimal_internal_energy = 0.f; + p->initial_temperature = hydro_props_default_init_temp; + p->initial_internal_energy = 0.f; + + p->hydrogen_mass_fraction = 0.755; + p->hydrogen_ionization_temperature = + hydro_props_default_H_ionization_temperature; + + p->viscosity.alpha = hydro_props_default_viscosity_alpha; + p->viscosity.alpha_max = hydro_props_default_viscosity_alpha_max; + p->viscosity.alpha_min = hydro_props_default_viscosity_alpha_min; + p->viscosity.length = hydro_props_default_viscosity_length; +} + /** * @brief Write a hydro_props struct to the given FILE as a stream of bytes. * diff --git a/src/hydro_properties.h b/src/hydro_properties.h index cb3fba9724b6c2e01a616505345a99c2259a67a2..b45b93192e7db7b1bdca49557f8563322f09aae9 100644 --- a/src/hydro_properties.h +++ b/src/hydro_properties.h @@ -69,20 +69,36 @@ struct hydro_props { /*! Minimal temperature allowed */ float minimal_temperature; - /*! Minimal internal energy per unit mass */ + /*! Minimal physical internal energy per unit mass */ float minimal_internal_energy; /*! Initial temperature */ float initial_temperature; - /*! Initial internal energy per unit mass */ + /*! Initial physical internal energy per unit mass */ float initial_internal_energy; - /*! Primoridal hydrogen mass fraction for initial energy conversion */ + /*! Primordial hydrogen mass fraction for initial energy conversion */ float hydrogen_mass_fraction; /*! Temperature of the neutral to ionized transition of Hydrogen */ float hydrogen_ionization_temperature; + + /*! Artificial viscosity parameters */ + struct { + /*! For the fixed, simple case. Also used to set the initial AV + coefficient for variable schemes. */ + float alpha; + + /*! Artificial viscosity (max) for the variable case (e.g. M&M) */ + float alpha_max; + + /*! Artificial viscosity (min) for the variable case (e.g. M&M) */ + float alpha_min; + + /*! The decay length of the artificial viscosity (used in M&M, etc.) */ + float length; + } viscosity; }; void hydro_props_print(const struct hydro_props *p); @@ -99,4 +115,7 @@ void hydro_props_print_snapshot(hid_t h_grpsph, const struct hydro_props *p); void hydro_props_struct_dump(const struct hydro_props *p, FILE *stream); void hydro_props_struct_restore(const struct hydro_props *p, FILE *stream); +/* Setup for tests */ +void hydro_props_init_no_hydro(struct hydro_props *p); + #endif /* SWIFT_HYDRO_PROPERTIES */ diff --git a/src/kick.h b/src/kick.h index 8c1c55519c311888ea1271f2285841731d7407ba..e85c9de40d2084304bde108e6f5fa9c776fd3e8f 100644 --- a/src/kick.h +++ b/src/kick.h @@ -45,8 +45,8 @@ __attribute__((always_inline)) INLINE static void kick_gpart( if (gp->ti_kick != ti_start) error( "g-particle has not been kicked to the current time gp->ti_kick=%lld, " - "ti_start=%lld, ti_end=%lld", - gp->ti_kick, ti_start, ti_end); + "ti_start=%lld, ti_end=%lld id=%lld", + gp->ti_kick, ti_start, ti_end, gp->id_or_neg_offset); gp->ti_kick = ti_end; #endif @@ -85,8 +85,8 @@ __attribute__((always_inline)) INLINE static void kick_part( if (p->ti_kick != ti_start) error( "particle has not been kicked to the current time p->ti_kick=%lld, " - "ti_start=%lld, ti_end=%lld", - p->ti_kick, ti_start, ti_end); + "ti_start=%lld, ti_end=%lld id=%lld", + p->ti_kick, ti_start, ti_end, p->id); p->ti_kick = ti_end; #endif @@ -133,8 +133,8 @@ __attribute__((always_inline)) INLINE static void kick_spart( if (sp->ti_kick != ti_start) error( "s-particle has not been kicked to the current time sp->ti_kick=%lld, " - "ti_start=%lld, ti_end=%lld", - sp->ti_kick, ti_start, ti_end); + "ti_start=%lld, ti_end=%lld id=%lld", + sp->ti_kick, ti_start, ti_end, sp->id); sp->ti_kick = ti_end; #endif diff --git a/src/logger.c b/src/logger.c index 5fd4145aa1b042ed806dd3fe5487d094600b66c4..2f4b0593dac039db96375afcee258a25dd871549 100644 --- a/src/logger.c +++ b/src/logger.c @@ -21,8 +21,10 @@ #include "../config.h" #ifdef HAVE_POSIX_FALLOCATE /* Are we on a sensible platform? */ +#ifdef WITH_LOGGER /* Some standard headers. */ +#include <hdf5.h> #include <stdint.h> #include <stdlib.h> #include <string.h> @@ -33,8 +35,110 @@ /* Local headers. */ #include "atomic.h" #include "dump.h" +#include "engine.h" #include "error.h" #include "part.h" +#include "units.h" + +/* header constants + * Thoses are definitions from the format and therefore should not be changed! + * Size in bytes + */ +/* size of a mask */ +#define logger_mask_size 1 + +/* size of an offset */ +#define logger_offset_size 7 + +/* size of the version information */ +#define logger_version_size 20 + +/* size of the size information */ +#define logger_header_number_size 2 + +char logger_version[logger_version_size] = "0.1"; + +const unsigned int logger_datatype_size[logger_data_count] = { + sizeof(int), sizeof(float), sizeof(double), + sizeof(char), sizeof(long long), 1, +}; + +/** + * @brief Write the header of a chunk (offset + mask). + * + * This is maybe broken for big(?) endian. + * + * @param buff The writing buffer + * @param mask The mask to write + * @param offset The old offset + * @param offset_new The new offset + * + * @return updated buff + */ +char *logger_write_chunk_header(char *buff, const unsigned int *mask, + const size_t *offset, const size_t offset_new) { + /* write mask */ + memcpy(buff, mask, logger_mask_size); + buff += logger_mask_size; + + /* write offset */ + size_t diff_offset = offset_new - *offset; + memcpy(buff, &diff_offset, logger_offset_size); + buff += logger_offset_size; + + return buff; +} + +/** + * @brief Write to the dump + * + * @param d #dump file + * @param offset (return) offset of the data + * @param size number of bytes to write + * @param p pointer to the data + */ +void logger_write_data(struct dump *d, size_t *offset, size_t size, + const void *p) { + /* get buffer */ + char *buff = dump_get(d, size, offset); + + /* write data to the buffer */ + memcpy(buff, p, size); +} + +/** + * @brief Write a parameter to the file + * + * TODO Make it thread safe or remove it. + * + * write data in the following order: name, data type, data. + * It should be used only for the file header. + * + * @param d #dump file + * @param params #logger_parameters file format informations + * @param offset (return) offset of the next chunk + * @param p pointer to the data + * @param name Label of the parameter (should be smaller than log->name) + * @param data_type #logger_datatype to write + */ +void logger_write_general_data(struct dump *d, + const struct logger_parameters *params, + size_t *offset, const void *p, char *name, + size_t data_type) { + /* write name */ + logger_write_data(d, offset, params->label_size, name); + + /* write data type */ + logger_write_data(d, offset, params->data_type_size, &data_type); + + /* write value */ + if (data_type >= logger_data_count) error("Not implemented"); + size_t size = logger_datatype_size[data_type]; + + logger_write_data(d, offset, size, p); + + *offset += size; +} /** * @brief Compute the size of a message given its mask. @@ -43,10 +147,10 @@ * * @return The size of the logger message in bytes. */ -int logger_size(unsigned int mask) { +int logger_compute_chunk_size(unsigned int mask) { /* Start with 8 bytes for the header. */ - int size = 8; + int size = logger_mask_size + logger_offset_size; /* Is this a particle or a timestep? */ if (mask & logger_mask_timestamp) { @@ -57,6 +161,7 @@ int logger_size(unsigned int mask) { /* A timestamp consists of an unsigned long long int. */ size += sizeof(unsigned long long int); + size += sizeof(double); } else { @@ -88,33 +193,65 @@ int logger_size(unsigned int mask) { return size; } +/** + * @brief log all particles in the engine. + * + * @param log The #logger + * @param e The #engine + */ +void logger_log_all(struct logger *log, const struct engine *e) { + + /* Ensure that enough space is available */ + logger_ensure_size(log, e->total_nr_parts, e->total_nr_gparts, 0); +#ifdef SWIFT_DEBUG_CHECKS + message("Need to implement stars"); +#endif + + /* some constants */ + const struct space *s = e->s; + const unsigned int mask = logger_mask_x | logger_mask_v | logger_mask_a | + logger_mask_u | logger_mask_h | logger_mask_rho | + logger_mask_consts; + + /* loop over all parts */ + for (long long i = 0; i < e->total_nr_parts; i++) { + logger_log_part(log, &s->parts[i], mask, + &s->xparts[i].logger_data.last_offset); + s->xparts[i].logger_data.steps_since_last_output = 0; + } + + /* loop over all gparts */ + if (e->total_nr_gparts > 0) error("Not implemented"); + + /* loop over all sparts */ + // TODO +} + /** * @brief Dump a #part to the log. * + * @param log The #logger * @param p The #part to dump. * @param mask The mask of the data to dump. - * @param offset Pointer to the offset of the previous log of this particle. - * @param dump The #dump in which to log the particle data. + * @param offset Pointer to the offset of the previous log of this particle; + * (return) offset of this log. */ -void logger_log_part(struct part *p, unsigned int mask, size_t *offset, - struct dump *dump) { +void logger_log_part(struct logger *log, const struct part *p, + unsigned int mask, size_t *offset) { /* Make sure we're not writing a timestamp. */ if (mask & logger_mask_timestamp) error("You should not log particles as timestamps."); /* Start by computing the size of the message. */ - const int size = logger_size(mask); + const int size = logger_compute_chunk_size(mask); /* Allocate a chunk of memory in the dump of the right size. */ size_t offset_new; - char *buff = (char *)dump_get(dump, size, &offset_new); + char *buff = (char *)dump_get(log->dump, size, &offset_new); /* Write the header. */ - uint64_t temp = (((uint64_t)(offset_new - *offset)) & 0xffffffffffffffULL) | - ((uint64_t)mask << 56); - memcpy(buff, &temp, 8); - buff += 8; + buff = logger_write_chunk_header(buff, &mask, offset, offset_new); /* Particle position as three doubles. */ if (mask & logger_mask_x) { @@ -155,7 +292,7 @@ void logger_log_part(struct part *p, unsigned int mask, size_t *offset, } /* Particle constants, which is a bit more complicated. */ - if (mask & logger_mask_rho) { + if (mask & logger_mask_consts) { memcpy(buff, &p->mass, sizeof(float)); buff += sizeof(float); memcpy(buff, &p->id, sizeof(long long)); @@ -171,13 +308,14 @@ void logger_log_part(struct part *p, unsigned int mask, size_t *offset, /** * @brief Dump a #gpart to the log. * + * @param log The #logger * @param p The #gpart to dump. * @param mask The mask of the data to dump. - * @param offset Pointer to the offset of the previous log of this particle. - * @param dump The #dump in which to log the particle data. + * @param offset Pointer to the offset of the previous log of this particle; + * (return) offset of this log. */ -void logger_log_gpart(struct gpart *p, unsigned int mask, size_t *offset, - struct dump *dump) { +void logger_log_gpart(struct logger *log, const struct gpart *p, + unsigned int mask, size_t *offset) { /* Make sure we're not writing a timestamp. */ if (mask & logger_mask_timestamp) @@ -188,17 +326,14 @@ void logger_log_gpart(struct gpart *p, unsigned int mask, size_t *offset, error("Can't log SPH quantities for gparts."); /* Start by computing the size of the message. */ - const int size = logger_size(mask); + const int size = logger_compute_chunk_size(mask); /* Allocate a chunk of memory in the dump of the right size. */ size_t offset_new; - char *buff = (char *)dump_get(dump, size, &offset_new); + char *buff = (char *)dump_get(log->dump, size, &offset_new); /* Write the header. */ - uint64_t temp = (((uint64_t)(offset_new - *offset)) & 0xffffffffffffffULL) | - ((uint64_t)mask << 56); - memcpy(buff, &temp, 8); - buff += 8; + buff = logger_write_chunk_header(buff, &mask, offset, offset_new); /* Particle position as three doubles. */ if (mask & logger_mask_x) { @@ -219,7 +354,7 @@ void logger_log_gpart(struct gpart *p, unsigned int mask, size_t *offset, } /* Particle constants, which is a bit more complicated. */ - if (mask & logger_mask_rho) { + if (mask & logger_mask_consts) { memcpy(buff, &p->mass, sizeof(float)); buff += sizeof(float); memcpy(buff, &p->id_or_neg_offset, sizeof(long long)); @@ -230,29 +365,327 @@ void logger_log_gpart(struct gpart *p, unsigned int mask, size_t *offset, *offset = offset_new; } -void logger_log_timestamp(unsigned long long int timestamp, size_t *offset, - struct dump *dump) { +/** + * @brief write a timestamp + * + * @param log The #logger + * @param timestamp time to write + * @param time time or scale factor + * @param offset Pointer to the offset of the previous log of this particle; + * (return) offset of this log. + */ +void logger_log_timestamp(struct logger *log, integertime_t timestamp, + double time, size_t *offset) { + struct dump *dump = log->dump; /* Start by computing the size of the message. */ - const int size = logger_size(logger_mask_timestamp); + const int size = logger_compute_chunk_size(logger_mask_timestamp); /* Allocate a chunk of memory in the dump of the right size. */ size_t offset_new; char *buff = (char *)dump_get(dump, size, &offset_new); /* Write the header. */ - uint64_t temp = (((uint64_t)(offset_new - *offset)) & 0xffffffffffffffULL) | - ((uint64_t)logger_mask_timestamp << 56); - memcpy(buff, &temp, 8); - buff += 8; + unsigned int mask = logger_mask_timestamp; + buff = logger_write_chunk_header(buff, &mask, offset, offset_new); /* Store the timestamp. */ - memcpy(buff, ×tamp, sizeof(unsigned long long int)); + memcpy(buff, ×tamp, sizeof(integertime_t)); + buff += sizeof(integertime_t); + + /* Store the time */ + memcpy(buff, &time, sizeof(double)); /* Update the log message offset. */ *offset = offset_new; } +/** + * @brief Ensure that the buffer is large enough for a step. + * + * Check if logger parameters are large enough to write all particles + * and ensure that enough space is available in the buffer. + * + * @param log The #logger + * @param total_nr_parts total number of part + * @param total_nr_gparts total number of gpart + * @param total_nr_sparts total number of spart + */ +void logger_ensure_size(struct logger *log, size_t total_nr_parts, + size_t total_nr_gparts, size_t total_nr_sparts) { + + struct logger_parameters *log_params = log->params; + + /* count part memory */ + size_t limit = log_params->total_size; + + limit *= total_nr_parts; + + /* count gpart memory */ + if (total_nr_gparts > 0) error("Not implemented"); + + /* count spart memory */ + if (total_nr_sparts > 0) error("Not implemented"); + + /* ensure enough space in dump */ + dump_ensure(log->dump, limit, log->buffer_scale * limit); +} + +/** + * @brief intialize the logger structure + * + * @param log The #logger + * @param params The #swift_params + */ +void logger_init(struct logger *log, struct swift_params *params) { + /* read parameters */ + log->delta_step = parser_get_param_int(params, "Logger:delta_step"); + size_t buffer_size = + parser_get_opt_param_float(params, "Logger:initial_buffer_size", 0.5) * + 1e9; + log->buffer_scale = + parser_get_opt_param_float(params, "Logger:buffer_scale", 10); + parser_get_param_string(params, "Logger:basename", log->base_name); + + /* set initial value of parameters */ + log->timestamp_offset = 0; + + /* generate dump filename */ + char logger_name_file[PARSER_MAX_LINE_SIZE]; + strcpy(logger_name_file, log->base_name); + strcat(logger_name_file, ".dump"); + + /* init parameters */ + log->params = + (struct logger_parameters *)malloc(sizeof(struct logger_parameters)); + logger_parameters_init(log->params); + + /* init dump */ + log->dump = malloc(sizeof(struct dump)); + struct dump *dump_file = log->dump; + + dump_init(dump_file, logger_name_file, buffer_size); +} + +/** + * @brief Close dump file and desallocate memory + * + * @param log The #logger + */ +void logger_clean(struct logger *log) { + dump_close(log->dump); + logger_parameters_clean(log->params); + free(log->params); +} + +/** + * @brief Write a file header to a logger file + * + * @param log The #logger + * @param dump The #dump in which to log the particle data. + * + */ +void logger_write_file_header(struct logger *log, const struct engine *e) { + + /* get required variables */ + const struct logger_parameters log_params = *log->params; + struct dump *dump = log->dump; + + size_t file_offset = dump->file_offset; + + if (file_offset != 0) + error( + "The logger is not empty." + "This function should be called before writing anything in the logger"); + + /* Write version information */ + logger_write_data(dump, &file_offset, logger_version_size, &logger_version); + + /* write number of bytes used for the offsets */ + logger_write_data(dump, &file_offset, logger_header_number_size, + &log_params.offset_size); + + /* write offset direction */ + int reversed = 0; + logger_write_data(dump, &file_offset, logger_datatype_size[logger_data_bool], + &reversed); + + /* placeholder to write the offset of the first log here */ + char *skip_header = dump_get(dump, log_params.offset_size, &file_offset); + + /* write number of bytes used for names */ + logger_write_data(dump, &file_offset, logger_header_number_size, + &log_params.label_size); + + /* write number of bytes used for numbers */ + logger_write_data(dump, &file_offset, logger_header_number_size, + &log_params.number_size); + + /* write number of bytes used for masks */ + logger_write_data(dump, &file_offset, logger_header_number_size, + &log_params.mask_size); + + /* write number of masks */ + logger_write_data(dump, &file_offset, log_params.number_size, + &log_params.number_mask); + + /* write masks */ + // loop over all mask type + for (size_t i = 0; i < log_params.number_mask; i++) { + // mask name + size_t j = i * log_params.label_size; + logger_write_data(dump, &file_offset, log_params.label_size, + &log_params.masks_name[j]); + + // mask + logger_write_data(dump, &file_offset, log_params.mask_size, + &log_params.masks[i]); + + // mask size + logger_write_data(dump, &file_offset, log_params.number_size, + &log_params.masks_data_size[i]); + } + + /* write mask data */ + // TODO + /* loop over each mask and each data in this mask */ + /* write number of bytes for each field */ + /* write data type (float, double, ...) */ + /* write data name (mass, id, ...) */ + + /* Write data */ + char *name = malloc(sizeof(char) * log_params.label_size); + strcpy(name, "time_base"); + logger_write_general_data(dump, &log_params, &file_offset, &e->time_base, + name, logger_data_double); + + /* last step: write first offset */ + memcpy(skip_header, &file_offset, log_params.offset_size); + + /* free memory */ + free(name); +} + +/** + * @brief initialize the #logger_parameters with the format informations + * + * @param log_params #logger_parameters to initialize + */ +void logger_parameters_init(struct logger_parameters *log_params) { + /* set parameters */ + log_params->label_size = 20; + log_params->offset_size = 7; + log_params->mask_size = 1; + log_params->number_size = 1; + log_params->data_type_size = 1; + + log_params->number_mask = 8; + + /* set masks array */ + log_params->masks = malloc(sizeof(size_t) * log_params->number_mask); + log_params->masks[0] = logger_mask_x; + log_params->masks[1] = logger_mask_v; + log_params->masks[2] = logger_mask_a; + log_params->masks[3] = logger_mask_u; + log_params->masks[4] = logger_mask_h; + log_params->masks[5] = logger_mask_rho; + log_params->masks[6] = logger_mask_consts; + log_params->masks[7] = logger_mask_timestamp; + + /* set the mask names */ + size_t block_size = log_params->label_size * log_params->number_mask; + log_params->masks_name = malloc(block_size); + char *cur_name = log_params->masks_name; + + char tmp[log_params->label_size]; + strcpy(tmp, "position"); + memcpy(cur_name, &tmp, log_params->label_size); + cur_name += log_params->label_size; + + strcpy(tmp, "velocity"); + memcpy(cur_name, &tmp, log_params->label_size); + cur_name += log_params->label_size; + + strcpy(tmp, "acceleration"); + memcpy(cur_name, &tmp, log_params->label_size); + cur_name += log_params->label_size; + + strcpy(tmp, "entropy"); + memcpy(cur_name, &tmp, log_params->label_size); + cur_name += log_params->label_size; + + strcpy(tmp, "cutoff radius"); + memcpy(cur_name, &tmp, log_params->label_size); + cur_name += log_params->label_size; + + strcpy(tmp, "density"); + memcpy(cur_name, &tmp, log_params->label_size); + cur_name += log_params->label_size; + + strcpy(tmp, "consts"); + memcpy(cur_name, &tmp, log_params->label_size); + cur_name += log_params->label_size; + + strcpy(tmp, "timestamp"); + memcpy(cur_name, &tmp, log_params->label_size); + cur_name += log_params->label_size; + + /* set the data size */ + log_params->masks_data_size = + malloc(sizeof(size_t) * log_params->number_mask); + log_params->masks_data_size[0] = 3 * sizeof(double); + log_params->masks_data_size[1] = 3 * sizeof(float); + log_params->masks_data_size[2] = 3 * sizeof(float); + log_params->masks_data_size[3] = sizeof(float); + log_params->masks_data_size[4] = sizeof(float); + log_params->masks_data_size[5] = sizeof(float); + log_params->masks_data_size[6] = sizeof(float) + sizeof(long long); + log_params->masks_data_size[7] = sizeof(integertime_t) + sizeof(double); + + /* Compute the size of a chunk if all the mask are activated */ + log_params->total_size = logger_offset_size + logger_mask_size; + + for (size_t i = 0; i < log_params->number_mask; i++) { + if (log_params->masks[i] != logger_mask_timestamp) + log_params->total_size += log_params->masks_data_size[i]; + } + + // todo masks_type +} + +/** + * @brief Clean the #logger_parameters + * + * @param log_params The #logger_parameters + */ +void logger_parameters_clean(struct logger_parameters *log_params) { + free(log_params->masks); + free(log_params->masks_name); + free(log_params->masks_data_size); +} + +/** + * @brief read chunk header + * + * @param buff The reading buffer + * @param mask The mask to read + * @param offset (return) the offset pointed by this chunk (absolute) + * @param offset_cur The current chunk offset + * + * @return Number of bytes read + */ +__attribute__((always_inline)) INLINE static int logger_read_chunk_header( + const char *buff, unsigned int *mask, size_t *offset, size_t cur_offset) { + memcpy(mask, buff, logger_mask_size); + buff += logger_mask_size; + + *offset = 0; + memcpy(offset, buff, logger_offset_size); + *offset = cur_offset - *offset; + + return logger_mask_size + logger_offset_size; +} + /** * @brief Read a logger message and store the data in a #part. * @@ -269,11 +702,9 @@ int logger_read_part(struct part *p, size_t *offset, const char *buff) { buff = &buff[*offset]; /* Start by reading the logger mask for this entry. */ - uint64_t temp; - memcpy(&temp, buff, 8); - const int mask = temp >> 56; - *offset -= temp & 0xffffffffffffffULL; - buff += 8; + const size_t cur_offset = *offset; + unsigned int mask = 0; + buff += logger_read_chunk_header(buff, &mask, offset, cur_offset); /* We are only interested in particle data. */ if (mask & logger_mask_timestamp) @@ -347,11 +778,9 @@ int logger_read_gpart(struct gpart *p, size_t *offset, const char *buff) { buff = &buff[*offset]; /* Start by reading the logger mask for this entry. */ - uint64_t temp; - memcpy(&temp, buff, 8); - const int mask = temp >> 56; - *offset -= temp & 0xffffffffffffffULL; - buff += 8; + const size_t cur_offset = *offset; + unsigned int mask = 0; + buff += logger_read_chunk_header(buff, &mask, offset, cur_offset); /* We are only interested in particle data. */ if (mask & logger_mask_timestamp) @@ -401,18 +830,16 @@ int logger_read_gpart(struct gpart *p, size_t *offset, const char *buff) { * * @return The mask containing the values read. */ -int logger_read_timestamp(unsigned long long int *t, size_t *offset, - const char *buff) { +int logger_read_timestamp(unsigned long long int *t, double *time, + size_t *offset, const char *buff) { /* Jump to the offset. */ buff = &buff[*offset]; /* Start by reading the logger mask for this entry. */ - uint64_t temp; - memcpy(&temp, buff, 8); - const int mask = temp >> 56; - *offset -= temp & 0xffffffffffffffULL; - buff += 8; + const size_t cur_offset = *offset; + unsigned int mask = 0; + buff += logger_read_chunk_header(buff, &mask, offset, cur_offset); /* We are only interested in timestamps. */ if (!(mask & logger_mask_timestamp)) @@ -424,9 +851,15 @@ int logger_read_timestamp(unsigned long long int *t, size_t *offset, /* Copy the timestamp value from the buffer. */ memcpy(t, buff, sizeof(unsigned long long int)); + buff += sizeof(unsigned long long int); + + /* Copy the timestamp value from the buffer. */ + memcpy(time, buff, sizeof(double)); /* Finally, return the mask of the values we just read. */ return mask; } +#endif /* WITH_LOGGER */ + #endif /* HAVE_POSIX_FALLOCATE */ diff --git a/src/logger.h b/src/logger.h index 596c0903750404d0934e0d3843a5461523700e9e..3ac5291eaab1f0e4fc05640cc23e1705a7178c9a 100644 --- a/src/logger.h +++ b/src/logger.h @@ -19,11 +19,20 @@ #ifndef SWIFT_LOGGER_H #define SWIFT_LOGGER_H +#ifdef WITH_LOGGER + /* Includes. */ -#include "part.h" +#include "common_io.h" +#include "inline.h" +#include "timeline.h" +#include "units.h" /* Forward declaration */ struct dump; +struct gpart; +struct part; +/* TODO remove dependency */ +struct engine; /** * Logger entries contain messages representing the particle data at a given @@ -59,31 +68,147 @@ struct dump; * The offset refers to the relative location of the previous message for the * same particle or for the previous timestamp (if mask bit 7 is set). I.e. * the previous log entry will be at the address of the current mask byte minus - * the unsigned value stored in the offset. An offset of zero indicates that - * this is the first message for the given particle/timestamp. + * the unsigned value stored in the offset. An offset equal to the chunk offset + * indicated that this is the first message for the given particle/timestamp. */ /* Some constants. */ -#define logger_mask_x 1 -#define logger_mask_v 2 -#define logger_mask_a 4 -#define logger_mask_u 8 -#define logger_mask_h 16 -#define logger_mask_rho 32 -#define logger_mask_consts 64 -#define logger_mask_timestamp 128 +enum logger_masks { + logger_mask_x = (1 << 0), + logger_mask_v = (1 << 1), + logger_mask_a = (1 << 2), + logger_mask_u = (1 << 3), + logger_mask_h = (1 << 4), + logger_mask_rho = (1 << 5), + logger_mask_consts = (1 << 6), + logger_mask_timestamp = (1 << 7), +}; + +/* Size of the strings. */ +#define logger_string_length 200 + +/* parameters of the logger */ +struct logger_parameters { + /* size of a label in bytes */ + size_t label_size; + + /* size of an offset in bytes */ + size_t offset_size; + + /* size of a mask in bytes */ + size_t mask_size; + + /* size of a number in bytes */ + size_t number_size; + + /* size of a data type in bytes */ + size_t data_type_size; + + /* number of different mask */ + size_t number_mask; + + /* value of each masks */ + size_t *masks; + + /* data size of each mask */ + size_t *masks_data_size; + + /* label of each mask */ + char *masks_name; + + /* Size of a chunk if every mask are activated */ + size_t total_size; +}; + +/* structure containing global data */ +struct logger { + /* Number of particle steps between dumping a chunk of data */ + short int delta_step; + + /* Logger basename */ + char base_name[logger_string_length]; + + /* File name of the dump file */ + struct dump *dump; + + /* timestamp offset for logger*/ + size_t timestamp_offset; + + /* scaling factor when buffer is too small */ + float buffer_scale; + + /* logger parameters */ + struct logger_parameters *params; + +} SWIFT_STRUCT_ALIGN; + +/* required structure for each particle type */ +struct logger_part_data { + /* Number of particle updates since last output */ + int steps_since_last_output; + + /* offset of last particle log entry */ + size_t last_offset; +}; + +enum logger_datatype { + logger_data_int, + logger_data_float, + logger_data_double, + logger_data_char, + logger_data_longlong, + logger_data_bool, + logger_data_count /* should be last */ +}; + +extern const unsigned int logger_datatype_size[]; /* Function prototypes. */ -int logger_size(unsigned int mask); -void logger_log_part(struct part *p, unsigned int mask, size_t *offset, - struct dump *dump); -void logger_log_gpart(struct gpart *p, unsigned int mask, size_t *offset, - struct dump *dump); -void logger_log_timestamp(unsigned long long int t, size_t *offset, - struct dump *dump); +int logger_compute_chunk_size(unsigned int mask); +void logger_log_all(struct logger *log, const struct engine *e); +void logger_log_part(struct logger *log, const struct part *p, + unsigned int mask, size_t *offset); +void logger_log_gpart(struct logger *log, const struct gpart *p, + unsigned int mask, size_t *offset); +void logger_init(struct logger *log, struct swift_params *params); +void logger_clean(struct logger *log); +void logger_log_timestamp(struct logger *log, integertime_t t, double time, + size_t *offset); +void logger_ensure_size(struct logger *log, size_t total_nr_parts, + size_t total_nr_gparts, size_t total_nr_sparts); +void logger_write_file_header(struct logger *log, const struct engine *e); + int logger_read_part(struct part *p, size_t *offset, const char *buff); int logger_read_gpart(struct gpart *p, size_t *offset, const char *buff); -int logger_read_timestamp(unsigned long long int *t, size_t *offset, - const char *buff); +int logger_read_timestamp(unsigned long long int *t, double *time, + size_t *offset, const char *buff); + +void logger_parameters_init(struct logger_parameters *log_params); +void logger_parameters_clean(struct logger_parameters *log_params); + +/** + * @brief Initialize the logger data for a particle. + * + * @param logger The #logger_part_data. + */ +INLINE static void logger_part_data_init(struct logger_part_data *logger) { + logger->last_offset = 0; + logger->steps_since_last_output = SHRT_MAX; +} + +/** + * @brief Should this particle write its data now ? + * + * @param xp The #xpart. + * @param e The #engine containing information about the current time. + * @return 1 if the #part should write, 0 otherwise. + */ +__attribute__((always_inline)) INLINE static int logger_should_write( + const struct logger_part_data *logger_data, const struct logger *log) { + + return (logger_data->steps_since_last_output > log->delta_step); +} + +#endif /* WITH_LOGGER */ #endif /* SWIFT_LOGGER_H */ diff --git a/src/logger_io.c b/src/logger_io.c new file mode 100644 index 0000000000000000000000000000000000000000..a0a5ba1db85aa4eb96ee140966a47393ba5a3b68 --- /dev/null +++ b/src/logger_io.c @@ -0,0 +1,299 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2012 Pedro Gonnet (pedro.gonnet@durham.ac.uk), + * Matthieu Schaller (matthieu.schaller@durham.ac.uk). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ + +/* Config parameters. */ +#include "../config.h" + +#ifdef WITH_LOGGER + +/* Some standard headers. */ +#include <hdf5.h> +#include <math.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +/* This object's header. */ +#include "logger_io.h" + +/* Local includes. */ +#include "chemistry_io.h" +#include "common_io.h" +#include "cooling.h" +#include "dimension.h" +#include "engine.h" +#include "error.h" +#include "gravity_io.h" +#include "gravity_properties.h" +#include "hydro_io.h" +#include "hydro_properties.h" +#include "io_properties.h" +#include "kernel_hydro.h" +#include "parallel_io.h" +#include "part.h" +#include "serial_io.h" +#include "single_io.h" +#include "stars_io.h" +#include "units.h" +#include "xmf.h" + +/** + * @brief Writes an HDF5 index file + * + * @param e The engine containing all the system. + * @param baseName The common part of the snapshot file name. + * @param internal_units The #unit_system used internally + * @param snapshot_units The #unit_system used in the snapshots + * + * Creates an HDF5 output file and writes the offset and id of particles + * contained in the engine. If such a file already exists, it is erased and + * replaced by the new one. + * + * Calls #error() if an error occurs. + * + */ +void write_index_single(struct engine* e, const char* baseName, + const struct unit_system* internal_units, + const struct unit_system* snapshot_units) { + + hid_t h_file = 0, h_grp = 0; + const size_t Ngas = e->s->nr_parts; + const size_t Nstars = e->s->nr_sparts; + const size_t Ntot = e->s->nr_gparts; + int periodic = e->s->periodic; + int numFiles = 1; + struct part* parts = e->s->parts; + struct xpart* xparts = e->s->xparts; + // struct gpart* gparts = e->s->gparts; + struct gpart* dmparts = NULL; + // struct spart* sparts = e->s->sparts; + static int outputCount = 0; + + struct logger* log = e->logger; + + /* Number of unassociated gparts */ + const size_t Ndm = Ntot > 0 ? Ntot - (Ngas + Nstars) : 0; + + long long N_total[swift_type_count] = {Ngas, Ndm, 0, 0, Nstars, 0}; + + /* File name */ + char fileName[FILENAME_BUFFER_SIZE]; + snprintf(fileName, FILENAME_BUFFER_SIZE, "%s_%04i.hdf5", baseName, + outputCount); + + /* Open file */ + /* message("Opening file '%s'.", fileName); */ + h_file = H5Fcreate(fileName, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + if (h_file < 0) { + error("Error while opening file '%s'.", fileName); + } + + /* Open header to write simulation properties */ + /* message("Writing runtime parameters..."); */ + h_grp = + H5Gcreate(h_file, "/RuntimePars", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + if (h_grp < 0) error("Error while creating runtime parameters group\n"); + + /* Write the relevant information */ + io_write_attribute(h_grp, "PeriodicBoundariesOn", INT, &periodic, 1); + + /* Close runtime parameters */ + H5Gclose(h_grp); + + /* Open header to write simulation properties */ + /* message("Writing file header..."); */ + h_grp = H5Gcreate(h_file, "/Header", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + if (h_grp < 0) error("Error while creating file header\n"); + + /* Print the relevant information and print status */ + io_write_attribute(h_grp, "BoxSize", DOUBLE, e->s->dim, 3); + double dblTime = e->time; + io_write_attribute(h_grp, "Time", DOUBLE, &dblTime, 1); + io_write_attribute(h_grp, "Time Offset", UINT, &log->timestamp_offset, 1); + int dimension = (int)hydro_dimension; + io_write_attribute(h_grp, "Dimension", INT, &dimension, 1); + + /* GADGET-2 legacy values */ + /* Number of particles of each type */ + unsigned int numParticles[swift_type_count] = {0}; + unsigned int numParticlesHighWord[swift_type_count] = {0}; + for (int ptype = 0; ptype < swift_type_count; ++ptype) { + numParticles[ptype] = (unsigned int)N_total[ptype]; + numParticlesHighWord[ptype] = (unsigned int)(N_total[ptype] >> 32); + } + io_write_attribute(h_grp, "NumPart_ThisFile", LONGLONG, N_total, + swift_type_count); + io_write_attribute(h_grp, "NumPart_Total", UINT, numParticles, + swift_type_count); + io_write_attribute(h_grp, "NumPart_Total_HighWord", UINT, + numParticlesHighWord, swift_type_count); + double MassTable[swift_type_count] = {0}; + io_write_attribute(h_grp, "MassTable", DOUBLE, MassTable, swift_type_count); + unsigned int flagEntropy[swift_type_count] = {0}; + flagEntropy[0] = writeEntropyFlag(); + io_write_attribute(h_grp, "Flag_Entropy_ICs", UINT, flagEntropy, + swift_type_count); + io_write_attribute(h_grp, "NumFilesPerSnapshot", INT, &numFiles, 1); + + /* Close header */ + H5Gclose(h_grp); + + /* Print the code version */ + io_write_code_description(h_file); + + /* Print the SPH parameters */ + if (e->policy & engine_policy_hydro) { + h_grp = H5Gcreate(h_file, "/HydroScheme", H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT); + if (h_grp < 0) error("Error while creating SPH group"); + hydro_props_print_snapshot(h_grp, e->hydro_properties); + hydro_write_flavour(h_grp); + H5Gclose(h_grp); + } + + /* Print the gravity parameters */ + if (e->policy & engine_policy_self_gravity) { + h_grp = H5Gcreate(h_file, "/GravityScheme", H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT); + if (h_grp < 0) error("Error while creating gravity group"); + gravity_props_print_snapshot(h_grp, e->gravity_properties); + H5Gclose(h_grp); + } + + /* Print the runtime parameters */ + h_grp = + H5Gcreate(h_file, "/Parameters", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + if (h_grp < 0) error("Error while creating parameters group"); + parser_write_params_to_hdf5(e->parameter_file, h_grp, 1); + H5Gclose(h_grp); + + /* Print the runtime unused parameters */ + h_grp = H5Gcreate(h_file, "/UnusedParameters", H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT); + if (h_grp < 0) error("Error while creating parameters group"); + parser_write_params_to_hdf5(e->parameter_file, h_grp, 0); + H5Gclose(h_grp); + + /* Print the system of Units used in the spashot */ + io_write_unit_system(h_file, snapshot_units, "Units"); + + /* Print the system of Units used internally */ + io_write_unit_system(h_file, internal_units, "InternalCodeUnits"); + + /* Tell the user if a conversion will be needed */ + if (e->verbose) { + if (units_are_equal(snapshot_units, internal_units)) { + + message("Snapshot and internal units match. No conversion needed."); + + } else { + + message("Conversion needed from:"); + message("(Snapshot) Unit system: U_M = %e g.", + snapshot_units->UnitMass_in_cgs); + message("(Snapshot) Unit system: U_L = %e cm.", + snapshot_units->UnitLength_in_cgs); + message("(Snapshot) Unit system: U_t = %e s.", + snapshot_units->UnitTime_in_cgs); + message("(Snapshot) Unit system: U_I = %e A.", + snapshot_units->UnitCurrent_in_cgs); + message("(Snapshot) Unit system: U_T = %e K.", + snapshot_units->UnitTemperature_in_cgs); + message("to:"); + message("(internal) Unit system: U_M = %e g.", + internal_units->UnitMass_in_cgs); + message("(internal) Unit system: U_L = %e cm.", + internal_units->UnitLength_in_cgs); + message("(internal) Unit system: U_t = %e s.", + internal_units->UnitTime_in_cgs); + message("(internal) Unit system: U_I = %e A.", + internal_units->UnitCurrent_in_cgs); + message("(internal) Unit system: U_T = %e K.", + internal_units->UnitTemperature_in_cgs); + } + } + + /* Loop over all particle types */ + for (int ptype = 0; ptype < swift_type_count; ptype++) { + + /* Don't do anything if no particle of this kind */ + if (numParticles[ptype] == 0) continue; + + /* Open the particle group in the file */ + char partTypeGroupName[PARTICLE_GROUP_BUFFER_SIZE]; + snprintf(partTypeGroupName, PARTICLE_GROUP_BUFFER_SIZE, "/PartType%d", + ptype); + h_grp = H5Gcreate(h_file, partTypeGroupName, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT); + if (h_grp < 0) { + error("Error while creating particle group.\n"); + } + + int num_fields = 0; + struct io_props list[100]; + size_t N = 0; + + /* Write particle fields from the particle structure */ + switch (ptype) { + + case swift_type_gas: + N = Ngas; + hydro_write_index(parts, xparts, list, &num_fields); + break; + + case swift_type_dark_matter: + error("TODO"); + break; + + case swift_type_stars: + N = Nstars; + error("TODO"); + // star_write_index(sparts, list, &num_fields); + break; + + default: + error("Particle Type %d not yet supported. Aborting", ptype); + } + + /* Write everything */ + for (int i = 0; i < num_fields; ++i) + writeArray(e, h_grp, fileName, NULL, partTypeGroupName, list[i], N, + internal_units, snapshot_units); + + /* Free temporary array */ + if (dmparts) { + free(dmparts); + dmparts = NULL; + } + + /* Close particle group */ + H5Gclose(h_grp); + } + + /* message("Done writing particles..."); */ + + /* Close file */ + H5Fclose(h_file); + + ++outputCount; +} + +#endif /* HAVE_HDF5 */ diff --git a/src/logger_io.h b/src/logger_io.h new file mode 100644 index 0000000000000000000000000000000000000000..f5b1274fb7b957d5b48bc8425bf784c586ac6a08 --- /dev/null +++ b/src/logger_io.h @@ -0,0 +1,61 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2012 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_LOGGER_IO_H +#define SWIFT_LOGGER_IO_H + +/* Config parameters. */ +#include "../config.h" + +#ifdef WITH_LOGGER + +/* Includes. */ +#include "engine.h" +#include "io_properties.h" +#include "part.h" +#include "units.h" + +void write_index_single(struct engine* e, const char* baseName, + const struct unit_system* internal_units, + const struct unit_system* snapshot_units); + +/** + * @brief Specifies which particle fields to write to a dataset + * + * @param parts The particle array. + * @param list The list of i/o properties to write. + * @param num_fields The number of i/o fields to write. + * + * In this version, we only want the ids and the offset. + */ +__attribute__((always_inline)) INLINE static void hydro_write_index( + const struct part* parts, const struct xpart* xparts, struct io_props* list, + int* num_fields) { + + *num_fields = 2; + + /* List what we want to write */ + list[0] = io_make_output_field("ParticleIDs", ULONGLONG, 1, + UNIT_CONV_NO_UNITS, parts, id); + + list[1] = io_make_output_field("Offset", ULONGLONG, 1, UNIT_CONV_NO_UNITS, + xparts, logger_data.last_offset); +} +#endif + +#endif /* SWIFT_LOGGER_IO_H */ diff --git a/src/map.c b/src/map.c index b0a3117388cb77f4311cf7ee3c5d62a0937da655..68c3618fcdb10a618a97e5d1a2565d58db677cdb 100644 --- a/src/map.c +++ b/src/map.c @@ -73,9 +73,9 @@ void map_cells_plot(struct cell *c, void *data) { printf("%.16e %.16e %.16e\n\n\n", l[0] + h[0], l[1] + h[1], l[2]); if (!c->split) { - for (int k = 0; k < c->count; k++) - printf("0 0 0 %.16e %.16e %.16e\n", c->parts[k].x[0], c->parts[k].x[1], - c->parts[k].x[2]); + for (int k = 0; k < c->hydro.count; k++) + printf("0 0 0 %.16e %.16e %.16e\n", c->hydro.parts[k].x[0], + c->hydro.parts[k].x[1], c->hydro.parts[k].x[2]); printf("\n\n"); } /* else @@ -102,11 +102,11 @@ void map_check(struct part *p, struct cell *c, void *data) { void map_cellcheck(struct cell *c, void *data) { int *count = (int *)data; - atomic_add(count, c->count); + atomic_add(count, c->hydro.count); /* Loop over all parts and check if they are in the cell. */ - for (int k = 0; k < c->count; k++) { - struct part *p = &c->parts[k]; + for (int k = 0; k < c->hydro.count; k++) { + struct part *p = &c->hydro.parts[k]; if (p->x[0] < c->loc[0] || p->x[1] < c->loc[1] || p->x[2] < c->loc[2] || p->x[0] > c->loc[0] + c->width[0] || p->x[1] > c->loc[1] + c->width[1] || @@ -122,8 +122,8 @@ void map_cellcheck(struct cell *c, void *data) { } /* Loop over all gparts and check if they are in the cell. */ - for (int k = 0; k < c->gcount; k++) { - struct gpart *p = &c->gparts[k]; + for (int k = 0; k < c->grav.count; k++) { + struct gpart *p = &c->grav.parts[k]; if (p->x[0] < c->loc[0] || p->x[1] < c->loc[1] || p->x[2] < c->loc[2] || p->x[0] > c->loc[0] + c->width[0] || p->x[1] > c->loc[1] + c->width[1] || @@ -191,6 +191,13 @@ void map_h_max(struct part *p, struct cell *c, void *data) { if (p->h > (*p2)->h) *p2 = p; } +void map_stars_h_max(struct spart *p, struct cell *c, void *data) { + + struct spart **p2 = (struct spart **)data; + + if (p->h > (*p2)->h) *p2 = p; +} + /** * @brief Mapping function for neighbour count. */ diff --git a/src/map.h b/src/map.h index 950a5fd96ebdc7177b41912b1565163f33de8701..6ad05e30df0644e1ee37b1b912bc11681ccf837c 100644 --- a/src/map.h +++ b/src/map.h @@ -34,6 +34,7 @@ void map_wcount_min(struct part *p, struct cell *c, void *data); void map_wcount_max(struct part *p, struct cell *c, void *data); void map_h_min(struct part *p, struct cell *c, void *data); void map_h_max(struct part *p, struct cell *c, void *data); +void map_stars_h_max(struct spart *p, struct cell *c, void *data); void map_icount(struct part *p, struct cell *c, void *data); void map_dump(struct part *p, struct cell *c, void *data); diff --git a/src/mesh_gravity.c b/src/mesh_gravity.c index 2f2f1628e7077ba301322c7af6b858e979b313ad..e7005b083c94e20f5218923e443f71464ab383e1 100644 --- a/src/mesh_gravity.c +++ b/src/mesh_gravity.c @@ -185,8 +185,8 @@ INLINE static void gpart_to_mesh_CIC(const struct gpart* gp, double* rho, int N, */ void cell_gpart_to_mesh_CIC(const struct cell* c, double* rho, int N, double fac, const double dim[3]) { - const int gcount = c->gcount; - const struct gpart* gparts = c->gparts; + const int gcount = c->grav.count; + const struct gpart* gparts = c->grav.parts; /* Assign all the gpart of that cell to the mesh */ for (int i = 0; i < gcount; ++i) diff --git a/src/multipole.c b/src/multipole.c index bd5c6d6546fa0546108dcd53d7fe4060293c37a7..a77e6fce297802fb4118b7ac3d4c6a9bf4ecfd22 100644 --- a/src/multipole.c +++ b/src/multipole.c @@ -20,3 +20,70 @@ /* Config parameters. */ #include "../config.h" + +/* This object's header. */ +#include "multipole.h" + +/* MPI headers. */ +#ifdef WITH_MPI +#include <mpi.h> +#endif + +#ifdef WITH_MPI + +/* MPI data type for the multipole transfer and reduction */ +MPI_Datatype multipole_mpi_type; +MPI_Op multipole_mpi_reduce_op; + +/** + * @brief Apply a bit-by-bit XOR operattion on #gravity_tensors (i.e. does + * a^=b). + * + * @param a The #gravity_tensors to add to. + * @param b The #gravity_tensors to add. + */ +void gravity_binary_xor(struct gravity_tensors *a, + const struct gravity_tensors *b) { + + char *aa = (char *)a; + const char *bb = (const char *)b; + + for (size_t i = 0; i < sizeof(struct gravity_tensors); ++i) { + aa[i] ^= bb[i]; + } +} + +/** + * @brief MPI reduction function for the #gravity_tensors. + * + * @param invec Array of #gravity_tensors to read. + * @param inoutvec Array of #gravity_tensors to read and do the reduction into. + * @param len The length of the array. + * @param datatype The MPI type this function acts upon (unused). + */ +void gravity_tensors_mpi_reduce(void *invec, void *inoutvec, int *len, + MPI_Datatype *datatype) { + + for (int i = 0; i < *len; ++i) { + gravity_binary_xor(&((struct gravity_tensors *)inoutvec)[i], + &((const struct gravity_tensors *)invec)[i]); + } +} + +void multipole_create_mpi_types(void) { + + /* Create the datatype for multipoles */ + /* We just consider each structure to be a byte field disregarding their */ + /* detailed content */ + if (MPI_Type_contiguous( + sizeof(struct gravity_tensors) / sizeof(unsigned char), MPI_BYTE, + &multipole_mpi_type) != MPI_SUCCESS || + MPI_Type_commit(&multipole_mpi_type) != MPI_SUCCESS) { + error("Failed to create MPI type for multipole."); + } + + /* And the reduction operator */ + MPI_Op_create(gravity_tensors_mpi_reduce, 1, &multipole_mpi_reduce_op); +} + +#endif diff --git a/src/multipole.h b/src/multipole.h index 41839b932716c5631bfe5354190c40eb6ab96a3f..8139dc0548bb94b108d6e32da4b19808998f48d3 100644 --- a/src/multipole.h +++ b/src/multipole.h @@ -207,6 +207,13 @@ struct gravity_tensors { }; } SWIFT_STRUCT_ALIGN; +#ifdef WITH_MPI +/* MPI datatypes for transfers */ +extern MPI_Datatype multipole_mpi_type; +extern MPI_Op multipole_mpi_reduce_op; +void multipole_create_mpi_types(void); +#endif + /** * @brief Reset the data of a #multipole. * @@ -1028,6 +1035,11 @@ INLINE static void gravity_P2M(struct gravity_tensors *multi, for (int k = 0; k < gcount; k++) { const double m = gparts[k].mass; +#ifdef SWIFT_DEBUG_CHECKS + if (gparts[k].time_bin == time_bin_inhibited) + error("Inhibited particle in P2M. Should have been removed earlier."); +#endif + mass += m; com[0] += gparts[k].x[0] * m; com[1] += gparts[k].x[1] * m; diff --git a/src/outputlist.c b/src/outputlist.c index fd33370ca45f25c17ecd2cc8df622138842507f3..2ab904d4fd0b7008b324f3c37a5cab6c6b337520 100644 --- a/src/outputlist.c +++ b/src/outputlist.c @@ -112,6 +112,9 @@ void output_list_read_file(struct output_list *outputlist, const char *filename, ind += 1; } + /* Cleanup */ + free(line); + if (ind != outputlist->size) error("Did not read the correct number of output times."); @@ -266,8 +269,12 @@ void output_list_print(const struct output_list *outputlist) { /** * @brief Clean an #output_list */ -void output_list_clean(struct output_list *outputlist) { - free(outputlist->times); +void output_list_clean(struct output_list **outputlist) { + if (*outputlist) { + free((*outputlist)->times); + free(*outputlist); + *outputlist = NULL; + } } /** diff --git a/src/outputlist.h b/src/outputlist.h index 6045d75ea29f0aab44252835147502f3df0de20c..b7b12ca32f469c70f716553b30a15f48198f8e5e 100644 --- a/src/outputlist.h +++ b/src/outputlist.h @@ -58,7 +58,7 @@ void output_list_read_next_time(struct output_list *t, const struct engine *e, void output_list_init(struct output_list **list, const struct engine *e, const char *name, double *delta_time, double *time_first); void output_list_print(const struct output_list *outputlist); -void output_list_clean(struct output_list *outputlist); +void output_list_clean(struct output_list **outputlist); void output_list_struct_dump(struct output_list *list, FILE *stream); void output_list_struct_restore(struct output_list *list, FILE *stream); diff --git a/src/parallel_io.c b/src/parallel_io.c index fa1b58d4dc5f2dd8d330c42df95e3e67de8ea2b1..510b637c67ffa2a6e9cb8edd6c4871fc1960dc95 100644 --- a/src/parallel_io.c +++ b/src/parallel_io.c @@ -138,7 +138,37 @@ void readArray_chunk(hid_t h_data, hid_t h_plist_id, for (size_t i = 0; i < num_elements; ++i) temp_d[i] *= factor; } else { float* temp_f = (float*)temp; - for (size_t i = 0; i < num_elements; ++i) temp_f[i] *= factor; + +#ifdef SWIFT_DEBUG_CHECKS + float maximum = 0.; + float minimum = FLT_MAX; +#endif + + /* Loop that converts the Units */ + for (size_t i = 0; i < num_elements; ++i) { + +#ifdef SWIFT_DEBUG_CHECKS + /* Find the absolute minimum and maximum values */ + const float abstemp_f = fabsf(temp_f[i]); + if (abstemp_f != 0.f) { + maximum = max(maximum, abstemp_f); + minimum = min(minimum, abstemp_f); + } +#endif + + /* Convert the float units */ + temp_f[i] *= factor; + } + +#ifdef SWIFT_DEBUG_CHECKS + /* The two possible errors: larger than float or smaller + * than float precission. */ + if (factor * maximum > FLT_MAX) { + error("Unit conversion results in numbers larger than floats"); + } else if (factor * minimum < FLT_MIN) { + error("Numbers smaller than float precision"); + } +#endif } } @@ -401,8 +431,9 @@ void prepareArray(struct engine* e, hid_t grp, char* fileName, FILE* xmfFile, io_write_attribute_s(h_data, "Conversion factor", buffer); /* Add a line to the XMF */ - xmf_write_line(xmfFile, fileName, partTypeGroupName, props.name, N_total, - props.dimension, props.type); + if (xmfFile != NULL) + xmf_write_line(xmfFile, fileName, partTypeGroupName, props.name, N_total, + props.dimension, props.type); /* Close everything */ H5Pclose(h_plist_id); @@ -618,7 +649,6 @@ void writeArray(struct engine* e, hid_t grp, char* fileName, * @param Ngas (output) The number of particles read from the file. * @param Ngparts (output) The number of particles read from the file. * @param Nstars (output) The number of particles read from the file. - * @param periodic (output) 1 if the volume is periodic, 0 if not. * @param flag_entropy (output) 1 if the ICs contained Entropy in the * InternalEnergy field * @param with_hydro Are we running with hydro ? @@ -640,11 +670,11 @@ void writeArray(struct engine* e, hid_t grp, char* fileName, void read_ic_parallel(char* fileName, const struct unit_system* internal_units, double dim[3], struct part** parts, struct gpart** gparts, struct spart** sparts, size_t* Ngas, size_t* Ngparts, - size_t* Nstars, int* periodic, int* flag_entropy, - int with_hydro, int with_gravity, int with_stars, - int cleanup_h, int cleanup_sqrt_a, double h, double a, - int mpi_rank, int mpi_size, MPI_Comm comm, MPI_Info info, - int n_threads, int dry_run) { + size_t* Nstars, int* flag_entropy, int with_hydro, + int with_gravity, int with_stars, int cleanup_h, + int cleanup_sqrt_a, double h, double a, int mpi_rank, + int mpi_size, MPI_Comm comm, MPI_Info info, int n_threads, + int dry_run) { hid_t h_file = 0, h_grp = 0; /* GADGET has only cubic boxes (in cosmological mode) */ @@ -664,17 +694,6 @@ void read_ic_parallel(char* fileName, const struct unit_system* internal_units, h_file = H5Fopen(fileName, H5F_ACC_RDONLY, h_plist_id); if (h_file < 0) error("Error while opening file '%s'.", fileName); - /* Open header to read simulation properties */ - /* message("Reading runtime parameters..."); */ - h_grp = H5Gopen(h_file, "/RuntimePars", H5P_DEFAULT); - if (h_grp < 0) error("Error while opening runtime parameters\n"); - - /* Read the relevant information */ - io_read_attribute(h_grp, "PeriodicBoundariesOn", INT, periodic); - - /* Close runtime parameters */ - H5Gclose(h_grp); - /* Open header to read simulation properties */ /* message("Reading file header..."); */ h_grp = H5Gopen(h_file, "/Header", H5P_DEFAULT); @@ -1020,7 +1039,7 @@ void prepare_file(struct engine* e, const char* baseName, long long N_total[6], h_grp = H5Gcreate(h_file, "/SubgridScheme", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); if (h_grp < 0) error("Error while creating subgrid group"); - cooling_write_flavour(h_grp); + cooling_write_flavour(h_grp, e->cooling_func); chemistry_write_flavour(h_grp); H5Gclose(h_grp); @@ -1171,22 +1190,30 @@ void write_output_parallel(struct engine* e, const char* baseName, int mpi_rank, int mpi_size, MPI_Comm comm, MPI_Info info) { - const size_t Ngas = e->s->nr_parts; - const size_t Nstars = e->s->nr_sparts; - const size_t Ntot = e->s->nr_gparts; const struct part* parts = e->s->parts; const struct xpart* xparts = e->s->xparts; const struct gpart* gparts = e->s->gparts; - struct gpart* dmparts = NULL; const struct spart* sparts = e->s->sparts; - const struct cooling_function_data* cooling = e->cooling_func; struct swift_params* params = e->parameter_file; - /* Number of unassociated gparts */ - const size_t Ndm = Ntot > 0 ? Ntot - (Ngas + Nstars) : 0; + /* Number of particles currently in the arrays */ + const size_t Ntot = e->s->nr_gparts; + const size_t Ngas = e->s->nr_parts; + const size_t Nstars = e->s->nr_sparts; + // const size_t Nbaryons = Ngas + Nstars; + // 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 Nbaryons_written = Ngas_written + Nstars_written; + const size_t Ndm_written = + Ntot_written > 0 ? Ntot_written - Nbaryons_written : 0; /* Compute offset in the file and total number of particles */ - size_t N[swift_type_count] = {Ngas, Ndm, 0, 0, Nstars, 0}; + size_t N[swift_type_count] = { + Ngas_written, Ndm_written, 0, 0, Nstars_written, 0}; long long N_total[swift_type_count] = {0}; long long offset[swift_type_count] = {0}; MPI_Exscan(&N, &offset, swift_type_count, MPI_LONG_LONG_INT, MPI_SUM, comm); @@ -1260,8 +1287,8 @@ void write_output_parallel(struct engine* e, const char* baseName, #if H5_VERSION_GE(1, 10, 0) h_err = H5Pset_all_coll_metadata_ops(plist_id, 1); if (h_err < 0) error("Error setting collective meta-data on all ops"); - h_err = H5Pset_coll_metadata_write(plist_id, 1); - if (h_err < 0) error("Error setting collective meta-data writes"); + // h_err = H5Pset_coll_metadata_write(plist_id, 1); + // if (h_err < 0) error("Error setting collective meta-data writes"); #endif #ifdef IO_SPEED_MEASUREMENT @@ -1337,38 +1364,98 @@ void write_output_parallel(struct engine* e, const char* baseName, struct io_props list[100]; size_t Nparticles = 0; + struct part* parts_written = NULL; + struct xpart* xparts_written = NULL; + struct gpart* gparts_written = NULL; + struct spart* sparts_written = NULL; + /* Write particle fields from the particle structure */ switch (ptype) { - case swift_type_gas: - 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, cooling); - break; + case swift_type_gas: { + if (Ngas == Ngas_written) { + + /* No inhibted particles: easy case */ + 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); + } else { + + /* Ok, we need to fish out the particles we want */ + Nparticles = Ngas_written; + + /* Allocate temporary arrays */ + if (posix_memalign((void**)&parts_written, part_align, + Ngas_written * sizeof(struct part)) != 0) + error("Error while allocating temporart memory for parts"); + if (posix_memalign((void**)&xparts_written, xpart_align, + Ngas_written * sizeof(struct xpart)) != 0) + error("Error while allocating temporart memory for xparts"); + + /* Collect the particles we want to write */ + io_collect_parts_to_write(parts, xparts, parts_written, + xparts_written, Ngas, Ngas_written); + + /* Select the fields to write */ + hydro_write_particles(parts_written, xparts_written, list, + &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); + } + } break; - case swift_type_dark_matter: - /* Allocate temporary array */ - if (posix_memalign((void**)&dmparts, gpart_align, - Ndm * sizeof(struct gpart)) != 0) - error( - "Error while allocating temporart memory for " - "DM particles"); - bzero(dmparts, Ndm * sizeof(struct gpart)); - - /* Collect the DM particles from gpart */ - io_collect_dm_gparts(gparts, Ntot, dmparts, Ndm); - - /* Write DM particles */ - Nparticles = Ndm; - darkmatter_write_particles(dmparts, list, &num_fields); - break; + case swift_type_dark_matter: { + if (Ntot == Ndm_written) { - case swift_type_stars: - Nparticles = Nstars; - stars_write_particles(sparts, list, &num_fields); - break; + /* This is a DM-only run without inhibited particles */ + Nparticles = Ntot; + darkmatter_write_particles(gparts, list, &num_fields); + } else { + + /* Ok, we need to fish out the particles we want */ + Nparticles = Ndm_written; + + /* Allocate temporary array */ + if (posix_memalign((void**)&gparts_written, gpart_align, + Ndm_written * sizeof(struct gpart)) != 0) + error("Error while allocating temporart memory for gparts"); + + /* Collect the non-inhibited DM particles from gpart */ + io_collect_gparts_to_write(gparts, gparts_written, Ntot, Ndm_written); + + /* Write DM particles */ + darkmatter_write_particles(gparts_written, list, &num_fields); + } + } break; + + case swift_type_stars: { + if (Nstars == Nstars_written) { + + /* No inhibted particles: easy case */ + Nparticles = Nstars; + stars_write_particles(sparts, list, &num_fields); + } else { + + /* Ok, we need to fish out the particles we want */ + Nparticles = Nstars_written; + + /* Allocate temporary arrays */ + if (posix_memalign((void**)&sparts_written, spart_align, + Nstars_written * sizeof(struct spart)) != 0) + error("Error while allocating temporart memory for sparts"); + + /* Collect the particles we want to write */ + io_collect_sparts_to_write(sparts, sparts_written, Nstars, + Nstars_written); + + /* Select the fields to write */ + stars_write_particles(sparts, list, &num_fields); + } + } break; default: error("Particle Type %d not yet supported. Aborting", ptype); @@ -1390,10 +1477,10 @@ void write_output_parallel(struct engine* e, const char* baseName, } /* Free temporary array */ - if (dmparts) { - free(dmparts); - dmparts = 0; - } + if (parts_written) free(parts_written); + if (xparts_written) free(xparts_written); + if (gparts_written) free(gparts_written); + if (sparts_written) free(sparts_written); #ifdef IO_SPEED_MEASUREMENT MPI_Barrier(MPI_COMM_WORLD); diff --git a/src/parallel_io.h b/src/parallel_io.h index 668b6f83443fe4c39ddf3269c8d2236e72588e32..9cd775347f0d5fbb3bc1b17664e0d5dba734d795 100644 --- a/src/parallel_io.h +++ b/src/parallel_io.h @@ -25,22 +25,21 @@ #if defined(HAVE_HDF5) && defined(WITH_MPI) && defined(HAVE_PARALLEL_HDF5) /* MPI headers. */ -#ifdef WITH_MPI #include <mpi.h> -#endif /* Includes. */ #include "engine.h" +#include "io_properties.h" #include "part.h" #include "units.h" void read_ic_parallel(char* fileName, const struct unit_system* internal_units, double dim[3], struct part** parts, struct gpart** gparts, struct spart** sparts, size_t* Ngas, size_t* Ngparts, - size_t* Nsparts, int* periodic, int* flag_entropy, - int with_hydro, int with_gravity, int with_stars, - int cleanup_h, int cleanup_sqrt_a, double h, double a, - int mpi_rank, int mpi_size, MPI_Comm comm, MPI_Info info, + size_t* Nsparts, int* flag_entropy, int with_hydro, + int with_gravity, int with_stars, int cleanup_h, + int cleanup_sqrt_a, double h, double a, int mpi_rank, + int mpi_size, MPI_Comm comm, MPI_Info info, int nr_threads, int dry_run); void write_output_parallel(struct engine* e, const char* baseName, @@ -48,6 +47,13 @@ void write_output_parallel(struct engine* e, const char* baseName, const struct unit_system* snapshot_units, int mpi_rank, int mpi_size, MPI_Comm comm, MPI_Info info); + +void writeArray(struct engine* e, hid_t grp, char* fileName, + char* partTypeGroupName, struct io_props props, size_t N, + long long N_total, int mpi_rank, long long offset, + const struct unit_system* internal_units, + const struct unit_system* snapshot_units); + #endif #endif /* SWIFT_PARALLEL_IO_H */ diff --git a/src/parser.c b/src/parser.c index f3e5ef00f96f0f7b55daff0ff32077e9373c4a2f..57592d57abb78100d113b91710af68f7b1c3e32d 100644 --- a/src/parser.c +++ b/src/parser.c @@ -35,6 +35,7 @@ #include "error.h" #include "restart.h" #include "tools.h" +#include "version.h" #define PARSER_COMMENT_STRING "#" #define PARSER_COMMENT_CHAR '#' @@ -1158,7 +1159,13 @@ void parser_write_params_to_file(const struct swift_params *params, char *token; /* Start of file identifier in YAML. */ - fprintf(file, "%s\n", PARSER_START_OF_FILE); + fprintf(file, "%s\n\n", PARSER_START_OF_FILE); + + fprintf(file, "# SWIFT used parameter file\n"); + fprintf(file, "# Code version: %s\n", package_version()); + fprintf(file, "# git revision: %s\n", git_revision()); + fprintf(file, "# git branch: %s\n", git_branch()); + fprintf(file, "# git date: %s\n", git_date()); /* Flags to track which parameters are written. */ int *written = (int *)calloc(params->paramCount, sizeof(int)); diff --git a/src/part.c b/src/part.c index db221dbd4bf9ff2b829b02fbae673aa1c65f339e..3a626e652cf28f0376cadc1d9a40ab85b752e6c1 100644 --- a/src/part.c +++ b/src/part.c @@ -26,8 +26,10 @@ #endif /* This object's header. */ -#include "error.h" #include "multipole.h" + +/* Local headers */ +#include "error.h" #include "part.h" /** @@ -133,6 +135,8 @@ void part_verify_links(struct part *parts, struct gpart *gparts, struct spart *sparts, size_t nr_parts, size_t nr_gparts, size_t nr_sparts, int verbose) { + ticks tic = getticks(); + for (size_t k = 0; k < nr_gparts; ++k) { /* We have a DM particle */ @@ -246,6 +250,9 @@ void part_verify_links(struct part *parts, struct gpart *gparts, } if (verbose) message("All links OK"); + if (verbose) + message("took %.3f %s.", clocks_from_ticks(getticks() - tic), + clocks_getunit()); } #ifdef WITH_MPI @@ -254,7 +261,6 @@ MPI_Datatype part_mpi_type; MPI_Datatype xpart_mpi_type; MPI_Datatype gpart_mpi_type; MPI_Datatype spart_mpi_type; -MPI_Datatype multipole_mpi_type; /** * @brief Registers MPI particle types. @@ -287,11 +293,5 @@ void part_create_mpi_types(void) { MPI_Type_commit(&spart_mpi_type) != MPI_SUCCESS) { error("Failed to create MPI type for sparts."); } - if (MPI_Type_contiguous( - sizeof(struct gravity_tensors) / sizeof(unsigned char), MPI_BYTE, - &multipole_mpi_type) != MPI_SUCCESS || - MPI_Type_commit(&multipole_mpi_type) != MPI_SUCCESS) { - error("Failed to create MPI type for multipole."); - } } #endif diff --git a/src/part.h b/src/part.h index 1608467bf73693e88cb7d300bea6125d7e542e52..41c0a8867ec513a507adcf5ae97268175c4b4b69 100644 --- a/src/part.h +++ b/src/part.h @@ -109,7 +109,6 @@ extern MPI_Datatype part_mpi_type; extern MPI_Datatype xpart_mpi_type; extern MPI_Datatype gpart_mpi_type; extern MPI_Datatype spart_mpi_type; -extern MPI_Datatype multipole_mpi_type; void part_create_mpi_types(void); #endif diff --git a/src/partition.c b/src/partition.c index 6a88731d518ddd702d4f3b116b5108ffd8d61c3c..d3b7f7d285904c38c6424656ee27f3fbd0e1f1a2 100644 --- a/src/partition.c +++ b/src/partition.c @@ -1197,8 +1197,8 @@ static void repart_edge_metis(int vweights, int eweights, int timebins, * we cut for that. Note that weight is added to the local and * remote cells, as we want to keep both away from any cuts, this * can overflow int, so take care. */ - int dti = num_time_bins - get_time_bin(ci->ti_hydro_end_min); - int dtj = num_time_bins - get_time_bin(cj->ti_hydro_end_min); + int dti = num_time_bins - get_time_bin(ci->hydro.ti_end_min); + int dtj = num_time_bins - get_time_bin(cj->hydro.ti_end_min); double dt = (double)(1 << dti) + (double)(1 << dtj); weights_e[ik] += dt; weights_e[jk] += dt; diff --git a/src/physical_constants_cgs.h b/src/physical_constants_cgs.h index 59e36e288e70dabecbdccd86891853b1daa0c5bd..fecd1f894af5df5db54b37883ba07e470b956bdf 100644 --- a/src/physical_constants_cgs.h +++ b/src/physical_constants_cgs.h @@ -95,7 +95,7 @@ const double const_earth_mass_cgs = 5.9724e27; /*! Temperature of the CMB at present day [K] */ const double const_T_CMB_0_cgs = 2.7255; -/*! Primordial Helium fraction */ +/*! Primordial Helium fraction [-] */ const double const_primordial_He_fraction_cgs = 0.245; #endif /* SWIFT_PHYSICAL_CONSTANTS_CGS_H */ diff --git a/src/potential.h b/src/potential.h index 814b83c69180631db21e392704c0279808a6f03e..59567fe92296068f838c39a3eb5ff55c14005d48 100644 --- a/src/potential.h +++ b/src/potential.h @@ -34,6 +34,10 @@ #include "./potential/point_mass/potential.h" #elif defined(EXTERNAL_POTENTIAL_ISOTHERMAL) #include "./potential/isothermal/potential.h" +#elif defined(EXTERNAL_POTENTIAL_HERNQUIST) +#include "./potential/hernquist/potential.h" +#elif defined(EXTERNAL_POTENTIAL_NFW) +#include "./potential/nfw/potential.h" #elif defined(EXTERNAL_POTENTIAL_DISC_PATCH) #include "./potential/disc_patch/potential.h" #elif defined(EXTERNAL_POTENTIAL_SINE_WAVE) diff --git a/src/potential/hernquist/potential.h b/src/potential/hernquist/potential.h new file mode 100644 index 0000000000000000000000000000000000000000..d0ec339d91376d25e0e5a2106826d07deca7115b --- /dev/null +++ b/src/potential/hernquist/potential.h @@ -0,0 +1,223 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2018 Folkert Nobels (nobels@strw.leidenuniv.nl) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ +#ifndef SWIFT_POTENTIAL_HERNQUIST_H +#define SWIFT_POTENTIAL_HERNQUIST_H + +/* Config parameters. */ +#include "../config.h" + +/* Some standard headers. */ +#include <math.h> + +/* Local includes. */ +#include "error.h" +#include "parser.h" +#include "part.h" +#include "physical_constants.h" +#include "space.h" +#include "units.h" + +/** + * @brief External Potential Properties - Hernquist potential + */ +struct external_potential { + + /*! Position of the centre of potential */ + double x[3]; + + /*! Mass of the halo */ + double mass; + + /*! Scale length (often as a, to prevent confusion with the cosmological + * scale-factor we use al) */ + double al; + + /*! Square of the softening length. Acceleration tends to zero within this + * distance from the origin */ + double epsilon2; + + /* Minimum timestep of the potential given by the timestep multiple + * times the orbital time at the softening length */ + double mintime; + + /*! Time-step condition pre-factor, is multiplied times the circular orbital + * time to get the time steps */ + double timestep_mult; +}; + +/** + * @brief Computes the time-step in a Hernquist potential based on a + * fraction of the circular orbital time + * + * @param time The current time. + * @param potential The #external_potential used in the run. + * @param phys_const The physical constants in internal units. + * @param g Pointer to the g-particle data. + */ +__attribute__((always_inline)) INLINE static float external_gravity_timestep( + double time, const struct external_potential* restrict potential, + const struct phys_const* restrict phys_const, + const struct gpart* restrict g) { + + const float G_newton = phys_const->const_newton_G; + + /* Calculate the relative potential with respect to the centre of the + * potential */ + const float dx = g->x[0] - potential->x[0]; + const float dy = g->x[1] - potential->x[1]; + const float dz = g->x[2] - potential->x[2]; + + /* calculate the radius */ + const float r = sqrtf(dx * dx + dy * dy + dz * dz + potential->epsilon2); + const float sqrtgm_inv = 1.f / sqrtf(G_newton * potential->mass); + + /* Calculate the circular orbital period */ + const float period = 2.f * M_PI * sqrtf(r) * potential->al * + (1 + r / potential->al) * sqrtgm_inv; + + /* Time-step as a fraction of the cirecular orbital time */ + const float time_step = potential->timestep_mult * period; + + return max(time_step, potential->mintime); +} + +/** + * @brief Computes the gravitational acceleration from an Hernquist potential. + * + * Note that the accelerations are multiplied by Newton's G constant + * later on. + * + * a_x = - GM / (a+r)^2 * x/r + * a_y = - GM / (a+r)^2 * y/r + * a_z = - GM / (a+r)^2 * z/r + * + * @param time The current time. + * @param potential The #external_potential used in the run. + * @param phys_const The physical constants in internal units. + * @param g Pointer to the g-particle data. + */ +__attribute__((always_inline)) INLINE static void external_gravity_acceleration( + double time, const struct external_potential* potential, + const struct phys_const* const phys_const, struct gpart* g) { + + /* Determine the position relative to the centre of the potential */ + const float dx = g->x[0] - potential->x[0]; + const float dy = g->x[1] - potential->x[1]; + const float dz = g->x[2] - potential->x[2]; + + /* Calculate the acceleration */ + const float r = sqrtf(dx * dx + dy * dy + dz * dz + potential->epsilon2); + const float r_plus_a_inv = 1.f / (r + potential->al); + const float r_plus_a_inv2 = r_plus_a_inv * r_plus_a_inv; + const float term = -potential->mass * r_plus_a_inv2 / r; + + g->a_grav[0] += term * dx; + g->a_grav[1] += term * dy; + g->a_grav[2] += term * dz; +} + +/** + * @brief Computes the gravitational potential energy of a particle in an + * Hernquist potential. + * + * phi = - GM/(r+a) + * + * @param time The current time (unused here). + * @param potential The #external_potential used in the run. + * @param phys_const Physical constants in internal units. + * @param g Pointer to the particle data. + */ +__attribute__((always_inline)) INLINE static float +external_gravity_get_potential_energy( + double time, const struct external_potential* potential, + const struct phys_const* const phys_const, const struct gpart* g) { + + const float dx = g->x[0] - potential->x[0]; + const float dy = g->x[1] - potential->x[1]; + const float dz = g->x[2] - potential->x[2]; + const float r = sqrtf(dx * dx + dy * dy + dz * dz); + const float r_plus_alinv = 1.f / (r + potential->al); + return -phys_const->const_newton_G * potential->mass * r_plus_alinv; +} + +/** + * @brief Initialises the external potential properties in the internal system + * of units. + * + * @param parameter_file The parsed parameter file + * @param phys_const Physical constants in internal units + * @param us The current internal system of units + * @param potential The external potential properties to initialize + */ +static INLINE void potential_init_backend( + struct swift_params* parameter_file, const struct phys_const* phys_const, + const struct unit_system* us, const struct space* s, + struct external_potential* potential) { + + /* Read in the position of the centre of potential */ + parser_get_param_double_array(parameter_file, "HernquistPotential:position", + 3, potential->x); + + /* Is the position absolute or relative to the centre of the box? */ + const int useabspos = + parser_get_param_int(parameter_file, "HernquistPotential:useabspos"); + + if (!useabspos) { + potential->x[0] += s->dim[0] / 2.; + potential->x[1] += s->dim[1] / 2.; + potential->x[2] += s->dim[2] / 2.; + } + + /* Read the other parameters of the model */ + potential->mass = + parser_get_param_double(parameter_file, "HernquistPotential:mass"); + potential->al = + parser_get_param_double(parameter_file, "HernquistPotential:scalelength"); + potential->timestep_mult = parser_get_param_float( + parameter_file, "HernquistPotential:timestep_mult"); + const float epsilon = + parser_get_param_double(parameter_file, "HernquistPotential:epsilon"); + potential->epsilon2 = epsilon * epsilon; + + /* Compute the minimal time-step. */ + /* This is the circular orbital time at the softened radius */ + const float sqrtgm = sqrtf(phys_const->const_newton_G * potential->mass); + potential->mintime = 2.f * sqrtf(epsilon) * potential->al * M_PI * + (1 + epsilon / potential->al) / sqrtgm * + potential->timestep_mult; +} + +/** + * @brief prints the properties of the external potential to stdout. + * + * @param potential the external potential properties. + */ +static inline void potential_print_backend( + const struct external_potential* potential) { + + message( + "external potential is 'hernquist' with properties are (x,y,z) = (%e, " + "%e, %e), mass = %e " + "scale length = %e , minimum time = %e " + "timestep multiplier = %e", + potential->x[0], potential->x[1], potential->x[2], potential->mass, + potential->al, potential->mintime, potential->timestep_mult); +} + +#endif /* SWIFT_POTENTIAL_HERNQUIST_H */ diff --git a/src/potential/isothermal/potential.h b/src/potential/isothermal/potential.h index b5f8d7c39738bfe1895c73e6e59ae1279c0f74fa..160372210e41036f2737c10a4aa3d2ddac1077f2 100644 --- a/src/potential/isothermal/potential.h +++ b/src/potential/isothermal/potential.h @@ -148,7 +148,7 @@ external_gravity_get_potential_energy( const float dy = g->x[1] - potential->x[1]; const float dz = g->x[2] - potential->x[2]; - return -0.5f * potential->vrot * potential->vrot * + return 0.5f * potential->vrot * potential->vrot * logf(dx * dx + dy * dy + dz * dz + potential->epsilon2); } @@ -166,11 +166,19 @@ static INLINE void potential_init_backend( const struct unit_system* us, const struct space* s, struct external_potential* potential) { + /* Read in the position of the centre of potential */ parser_get_param_double_array(parameter_file, "IsothermalPotential:position", 3, potential->x); - potential->x[0] += s->dim[0] / 2.; - potential->x[1] += s->dim[1] / 2.; - potential->x[2] += s->dim[2] / 2.; + + /* Is the position absolute or relative to the centre of the box? */ + const int useabspos = + parser_get_param_int(parameter_file, "IsothermalPotential:useabspos"); + + if (!useabspos) { + potential->x[0] += s->dim[0] / 2.; + potential->x[1] += s->dim[1] / 2.; + potential->x[2] += s->dim[2] / 2.; + } potential->vrot = parser_get_param_double(parameter_file, "IsothermalPotential:vrot"); diff --git a/src/potential/nfw/potential.h b/src/potential/nfw/potential.h new file mode 100644 index 0000000000000000000000000000000000000000..28bafd439a36a41f2feecdc7169f8628fbed47f4 --- /dev/null +++ b/src/potential/nfw/potential.h @@ -0,0 +1,260 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2018 Ashley Kelly () + * Folkert Nobels (nobels@strw.leidenuniv.nl) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ +#ifndef SWIFT_POTENTIAL_NFW_H +#define SWIFT_POTENTIAL_NFW_H + +/* Config parameters. */ +#include "../config.h" + +/* Some standard headers. */ +#include <float.h> +#include <math.h> + +/* Local includes. */ +#include "error.h" +#include "parser.h" +#include "part.h" +#include "physical_constants.h" +#include "space.h" +#include "units.h" + +/** + * @brief External Potential Properties - NFW Potential + rho(r) = rho_0 / ( (r/R_s)*(1+r/R_s)^2 ) + + We however parameterise this in terms of c and virial_mass + */ +struct external_potential { + + /*! Position of the centre of potential */ + double x[3]; + + /*! The scale radius of the NFW potential */ + double r_s; + + /*! The pre-factor \f$ 4 \pi G \rho_0 \r_s^3 \f$ */ + double pre_factor; + + /*! The critical density of the universe */ + double rho_c; + + /*! The concentration parameter */ + double c_200; + + /*! The virial mass */ + double M_200; + + /*! Time-step condition pre_factor, this factor is used to multiply times the + * orbital time, so in the case of 0.01 we take 1% of the orbital time as + * the time integration steps */ + double timestep_mult; + + /*! Minimum time step based on the orbital time at the softening times + * the timestep_mult */ + double mintime; + + /*! Common log term \f$ \ln(1+c_{200}) - \frac{c_{200}}{1 + c_{200}} \f$ */ + double log_c200_term; + + /*! Softening length */ + double eps; +}; + +/** + * @brief Computes the time-step due to the acceleration from the NFW potential + * as a fraction (timestep_mult) of the circular orbital time of that + * particle. + * + * @param time The current time. + * @param potential The #external_potential used in the run. + * @param phys_const The physical constants in internal units. + * @param g Pointer to the g-particle data. + */ +__attribute__((always_inline)) INLINE static float external_gravity_timestep( + double time, const struct external_potential* restrict potential, + const struct phys_const* restrict phys_const, + const struct gpart* restrict g) { + + const float dx = g->x[0] - potential->x[0]; + const float dy = g->x[1] - potential->x[1]; + const float dz = g->x[2] - potential->x[2]; + + const float r = + sqrtf(dx * dx + dy * dy + dz * dz + potential->eps * potential->eps); + + const float mr = potential->M_200 * + (logf(1.f + r / potential->r_s) - r / (r + potential->r_s)) / + potential->log_c200_term; + + const float period = + 2 * M_PI * r * sqrtf(r / (phys_const->const_newton_G * mr)); + + /* Time-step as a fraction of the circular period */ + const float time_step = potential->timestep_mult * period; + + return max(time_step, potential->mintime); +} + +/** + * @brief Computes the gravitational acceleration from an NFW Halo potential. + * + * Note that the accelerations are multiplied by Newton's G constant + * later on. + * + * a_x = 4 pi \rho_0 r_s^3 ( 1/((r+rs)*r^2) - log(1+r/rs)/r^3) * x + * a_y = 4 pi \rho_0 r_s^3 ( 1/((r+rs)*r^2) - log(1+r/rs)/r^3) * y + * a_z = 4 pi \rho_0 r_s^3 ( 1/((r+rs)*r^2) - log(1+r/rs)/r^3) * z + * + * @param time The current time. + * @param potential The #external_potential used in the run. + * @param phys_const The physical constants in internal units. + * @param g Pointer to the g-particle data. + */ +__attribute__((always_inline)) INLINE static void external_gravity_acceleration( + double time, const struct external_potential* restrict potential, + const struct phys_const* restrict phys_const, struct gpart* restrict g) { + + const float dx = g->x[0] - potential->x[0]; + const float dy = g->x[1] - potential->x[1]; + const float dz = g->x[2] - potential->x[2]; + + const float r = + sqrtf(dx * dx + dy * dy + dz * dz + potential->eps * potential->eps); + const float term1 = potential->pre_factor; + const float term2 = (1.0f / ((r + potential->r_s) * r * r) - + logf(1.0f + r / potential->r_s) / (r * r * r)); + + g->a_grav[0] += term1 * term2 * dx; + g->a_grav[1] += term1 * term2 * dy; + g->a_grav[2] += term1 * term2 * dz; +} + +/** + * @brief Computes the gravitational potential energy of a particle in an + * NFW potential. + * + * phi = -4 * pi * G * rho_0 * r_s^3 * ln(1+r/r_s) + * + * @param time The current time (unused here). + * @param potential The #external_potential used in the run. + * @param phys_const Physical constants in internal units. + * @param g Pointer to the particle data. + */ +__attribute__((always_inline)) INLINE static float +external_gravity_get_potential_energy( + double time, const struct external_potential* potential, + const struct phys_const* const phys_const, const struct gpart* g) { + + const float dx = g->x[0] - potential->x[0]; + const float dy = g->x[1] - potential->x[1]; + const float dz = g->x[2] - potential->x[2]; + + const float r = + sqrtf(dx * dx + dy * dy + dz * dz + potential->eps * potential->eps); + const float term1 = -potential->pre_factor / r; + const float term2 = logf(1.0f + r / potential->r_s); + + return term1 * term2; +} + +/** + * @brief Initialises the external potential properties in the internal system + * of units. + * + * @param parameter_file The parsed parameter file + * @param phys_const Physical constants in internal units + * @param us The current internal system of units + * @param potential The external potential properties to initialize + */ +static INLINE void potential_init_backend( + struct swift_params* parameter_file, const struct phys_const* phys_const, + const struct unit_system* us, const struct space* s, + struct external_potential* potential) { + + /* Read in the position of the centre of potential */ + parser_get_param_double_array(parameter_file, "NFWPotential:position", 3, + potential->x); + + /* Is the position absolute or relative to the centre of the box? */ + const int useabspos = + parser_get_param_int(parameter_file, "NFWPotential:useabspos"); + + if (!useabspos) { + potential->x[0] += s->dim[0] / 2.; + potential->x[1] += s->dim[1] / 2.; + potential->x[2] += s->dim[2] / 2.; + } + + /* Read the other parameters of the model */ + potential->timestep_mult = + parser_get_param_double(parameter_file, "NFWPotential:timestep_mult"); + potential->c_200 = + parser_get_param_double(parameter_file, "NFWPotential:concentration"); + potential->M_200 = + parser_get_param_double(parameter_file, "NFWPotential:M_200"); + potential->rho_c = + parser_get_param_double(parameter_file, "NFWPotential:critical_density"); + potential->eps = 0.05; + + /* Compute R_200 */ + const double R_200 = + cbrtf(3.0 * potential->M_200 / (4. * M_PI * 200.0 * potential->rho_c)); + + /* NFW scale-radius */ + potential->r_s = R_200 / potential->c_200; + const double r_s3 = potential->r_s * potential->r_s * potential->r_s; + + /* Log(c_200) term appearing in many expressions */ + potential->log_c200_term = + log(1. + potential->c_200) - potential->c_200 / (1. + potential->c_200); + + const double rho_0 = + potential->M_200 / (4.f * M_PI * r_s3 * potential->log_c200_term); + + /* Pre-factor for the accelerations (note G is multiplied in later on) */ + potential->pre_factor = 4.0f * M_PI * rho_0 * r_s3; + + /* Compute the orbital time at the softening radius */ + const double sqrtgm = sqrt(phys_const->const_newton_G * potential->M_200); + const double epslnthing = log(1.f + potential->eps / potential->r_s) - + potential->eps / (potential->eps + potential->r_s); + + potential->mintime = 2. * M_PI * potential->eps * sqrtf(potential->eps) * + sqrtf(potential->log_c200_term / epslnthing) / sqrtgm * + potential->timestep_mult; +} + +/** + * @brief Prints the properties of the external potential to stdout. + * + * @param potential The external potential properties. + */ +static INLINE void potential_print_backend( + const struct external_potential* potential) { + + message( + "External potential is 'NFW' with properties are (x,y,z) = (%e, " + "%e, %e), scale radius = %e " + "timestep multiplier = %e, mintime = %e", + potential->x[0], potential->x[1], potential->x[2], potential->r_s, + potential->timestep_mult, potential->mintime); +} + +#endif /* SWIFT_POTENTIAL_NFW_H */ diff --git a/src/potential/point_mass/potential.h b/src/potential/point_mass/potential.h index f9d56a1ff165f2331c91ea828b5ffe0e0db76c2f..5ae03f8637708d75800a6a7fb283b98bdb42cec2 100644 --- a/src/potential/point_mass/potential.h +++ b/src/potential/point_mass/potential.h @@ -137,7 +137,7 @@ external_gravity_get_potential_energy( const float dx = g->x[0] - potential->x[0]; const float dy = g->x[1] - potential->x[1]; const float dz = g->x[2] - potential->x[2]; - const float rinv = 1. / sqrtf(dx * dx + dy * dy + dz * dz); + const float rinv = 1.f / sqrtf(dx * dx + dy * dy + dz * dz); return -phys_const->const_newton_G * potential->mass * rinv; } @@ -156,8 +156,21 @@ static INLINE void potential_init_backend( const struct unit_system* us, const struct space* s, struct external_potential* potential) { + /* Read in the position of the centre of potential */ parser_get_param_double_array(parameter_file, "PointMassPotential:position", 3, potential->x); + + /* Is the position absolute or relative to the centre of the box? */ + const int useabspos = + parser_get_param_int(parameter_file, "PointMassPotential:useabspos"); + + if (!useabspos) { + potential->x[0] += s->dim[0] / 2.; + potential->x[1] += s->dim[1] / 2.; + potential->x[2] += s->dim[2] / 2.; + } + + /* Read the other parameters of the model */ potential->mass = parser_get_param_double(parameter_file, "PointMassPotential:mass"); potential->timestep_mult = parser_get_param_float( diff --git a/src/potential/point_mass_softened/potential.h b/src/potential/point_mass_softened/potential.h index 0e35e7bb9870c7954b47316a3cc30bb68cde5fc4..050bc1a00c98da4c350e59cf1ef8ef855094e552 100644 --- a/src/potential/point_mass_softened/potential.h +++ b/src/potential/point_mass_softened/potential.h @@ -183,8 +183,21 @@ static INLINE void potential_init_backend( const struct unit_system* us, const struct space* s, struct external_potential* potential) { + /* Read in the position of the centre of potential */ parser_get_param_double_array(parameter_file, "PointMassPotential:position", 3, potential->x); + + /* Is the position absolute or relative to the centre of the box? */ + const int useabspos = + parser_get_param_int(parameter_file, "PointMassPotential:useabspos"); + + if (!useabspos) { + potential->x[0] += s->dim[0] / 2.; + potential->x[1] += s->dim[1] / 2.; + potential->x[2] += s->dim[2] / 2.; + } + + /* Read the other parameters of the model */ potential->mass = parser_get_param_double(parameter_file, "PointMassPotential:mass"); potential->timestep_mult = parser_get_param_float( diff --git a/src/proxy.c b/src/proxy.c index 80b33a776c1b2833e711f3bbd3be32474cf5cf73..325ed78644b07a497374e40bfc8518edcb018593 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -71,8 +71,8 @@ void proxy_tags_exchange(struct proxy *proxies, int num_proxies, int offset_out[s->nr_cells]; for (int k = 0; k < s->nr_cells; k++) { offset_out[k] = count_out; - if (s->cells_top[k].sendto) { - count_out += s->cells_top[k].pcell_size; + if (s->cells_top[k].mpi.sendto) { + count_out += s->cells_top[k].mpi.pcell_size; } } @@ -82,7 +82,7 @@ void proxy_tags_exchange(struct proxy *proxies, int num_proxies, for (int k = 0; k < num_proxies; k++) { for (int j = 0; j < proxies[k].nr_cells_in; j++) { offset_in[proxies[k].cells_in[j] - s->cells_top] = count_in; - count_in += proxies[k].cells_in[j]->pcell_size; + count_in += proxies[k].cells_in[j]->mpi.pcell_size; } } @@ -97,7 +97,7 @@ void proxy_tags_exchange(struct proxy *proxies, int num_proxies, /* Pack the local tags. */ for (int k = 0; k < s->nr_cells; k++) { - if (s->cells_top[k].sendto) { + if (s->cells_top[k].mpi.sendto) { cell_pack_tags(&s->cells_top[k], &tags_out[offset_out[k]]); } } @@ -129,8 +129,8 @@ void proxy_tags_exchange(struct proxy *proxies, int num_proxies, const int cid = proxies[k].cells_in[j] - s->cells_top; cids_in[recv_rid] = cid; int err = MPI_Irecv( - &tags_in[offset_in[cid]], proxies[k].cells_in[j]->pcell_size, MPI_INT, - proxies[k].nodeID, cid, MPI_COMM_WORLD, &reqs_in[recv_rid]); + &tags_in[offset_in[cid]], proxies[k].cells_in[j]->mpi.pcell_size, + MPI_INT, proxies[k].nodeID, cid, MPI_COMM_WORLD, &reqs_in[recv_rid]); if (err != MPI_SUCCESS) mpi_error(err, "Failed to irecv tags."); recv_rid += 1; } @@ -138,7 +138,7 @@ void proxy_tags_exchange(struct proxy *proxies, int num_proxies, const int cid = proxies[k].cells_out[j] - s->cells_top; cids_out[send_rid] = cid; int err = MPI_Isend( - &tags_out[offset_out[cid]], proxies[k].cells_out[j]->pcell_size, + &tags_out[offset_out[cid]], proxies[k].cells_out[j]->mpi.pcell_size, MPI_INT, proxies[k].nodeID, cid, MPI_COMM_WORLD, &reqs_out[send_rid]); if (err != MPI_SUCCESS) mpi_error(err, "Failed to isend tags."); send_rid += 1; @@ -193,7 +193,7 @@ void proxy_cells_exchange_first(struct proxy *p) { /* Get the number of pcells we will need to send. */ p->size_pcells_out = 0; for (int k = 0; k < p->nr_cells_out; k++) - p->size_pcells_out += p->cells_out[k]->pcell_size; + p->size_pcells_out += p->cells_out[k]->mpi.pcell_size; /* Send the number of pcells. */ int err = MPI_Isend(&p->size_pcells_out, 1, MPI_INT, p->nodeID, @@ -209,9 +209,9 @@ void proxy_cells_exchange_first(struct proxy *p) { sizeof(struct pcell) * p->size_pcells_out) != 0) error("Failed to allocate pcell_out buffer."); for (int ind = 0, k = 0; k < p->nr_cells_out; k++) { - memcpy(&p->pcells_out[ind], p->cells_out[k]->pcell, - sizeof(struct pcell) * p->cells_out[k]->pcell_size); - ind += p->cells_out[k]->pcell_size; + memcpy(&p->pcells_out[ind], p->cells_out[k]->mpi.pcell, + sizeof(struct pcell) * p->cells_out[k]->mpi.pcell_size); + ind += p->cells_out[k]->mpi.pcell_size; } /* Send the pcell buffer. */ @@ -298,9 +298,9 @@ void proxy_cells_exchange(struct proxy *proxies, int num_proxies, int offset[s->nr_cells]; for (int k = 0; k < s->nr_cells; k++) { offset[k] = count_out; - if (s->cells_top[k].sendto) + if (s->cells_top[k].mpi.sendto) count_out += - (s->cells_top[k].pcell_size = cell_getsize(&s->cells_top[k])); + (s->cells_top[k].mpi.pcell_size = cell_getsize(&s->cells_top[k])); } if (s->e->verbose) @@ -317,9 +317,9 @@ void proxy_cells_exchange(struct proxy *proxies, int num_proxies, /* Pack the cells. */ for (int k = 0; k < s->nr_cells; k++) - if (s->cells_top[k].sendto) { + if (s->cells_top[k].mpi.sendto) { cell_pack(&s->cells_top[k], &pcells[offset[k]], with_gravity); - s->cells_top[k].pcell = &pcells[offset[k]]; + s->cells_top[k].mpi.pcell = &pcells[offset[k]]; } if (s->e->verbose) diff --git a/src/restart.c b/src/restart.c index c412c8477d9f93e7c085e13c9e3fe72cd0cab9df..54a098413d7a393ac88a7ef5d7300d912c99f845 100644 --- a/src/restart.c +++ b/src/restart.c @@ -334,3 +334,17 @@ void restart_remove_previous(const char *filename) { } } } + +/** + * @brief Run a given command, usually to resubmit a job. + * + * No check is done on the command being run. + * + * @param command The command to run in the system's shell. + */ +void restart_resubmit(const char *command) { + + /* Let's trust the user's command... */ + const int result = system(command); + if (result != 0) message("Command returned error code %d", result); +} diff --git a/src/restart.h b/src/restart.h index 49d127492255364cbf0f48653c560494e83a2920..b9380201659dacf05fcedad8c9fcb29e7bd89be2 100644 --- a/src/restart.h +++ b/src/restart.h @@ -41,4 +41,6 @@ int restart_stop_now(const char *dir, int cleanup); void restart_save_previous(const char *filename); void restart_remove_previous(const char *filename); +void restart_resubmit(const char *command); + #endif /* SWIFT_RESTART_H */ diff --git a/src/runner.c b/src/runner.c index f88a91e790fac997bcc09d7323a50bc13a63e4bf..cf5492dad4702d3090393809e02c526b45c293eb 100644 --- a/src/runner.c +++ b/src/runner.c @@ -53,6 +53,7 @@ #include "hydro.h" #include "hydro_properties.h" #include "kick.h" +#include "logger.h" #include "minmax.h" #include "runner_doiact_vec.h" #include "scheduler.h" @@ -107,7 +108,7 @@ * @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->count; + 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; @@ -145,7 +146,7 @@ void runner_do_sourceterms(struct runner *r, struct cell *c, int timer) { */ void runner_do_stars_ghost(struct runner *r, struct cell *c, int timer) { - struct spart *restrict sparts = c->sparts; + struct spart *restrict sparts = c->stars.parts; const struct engine *e = r->e; const struct cosmology *cosmo = e->cosmology; const struct stars_props *stars_properties = e->stars_properties; @@ -168,9 +169,9 @@ void runner_do_stars_ghost(struct runner *r, struct cell *c, int timer) { /* Init the list of active particles that have to be updated. */ int *sid = NULL; - if ((sid = (int *)malloc(sizeof(int) * c->scount)) == NULL) + if ((sid = (int *)malloc(sizeof(int) * c->stars.count)) == NULL) error("Can't allocate memory for sid."); - for (int k = 0; k < c->scount; k++) + for (int k = 0; k < c->stars.count; k++) if (spart_is_active(&sparts[k], e)) { sid[scount] = k; ++scount; @@ -283,7 +284,7 @@ void runner_do_stars_ghost(struct runner *r, struct cell *c, int timer) { for (struct cell *finger = c; finger != NULL; finger = finger->parent) { /* Run through this cell's density interactions. */ - for (struct link *l = finger->density; l != NULL; l = l->next) { + for (struct link *l = finger->stars.density; l != NULL; l = l->next) { #ifdef SWIFT_DEBUG_CHECKS if (l->t->ti_run < r->e->ti_current) @@ -348,8 +349,8 @@ void runner_do_stars_ghost(struct runner *r, struct cell *c, int timer) { */ void runner_do_grav_external(struct runner *r, struct cell *c, int timer) { - struct gpart *restrict gparts = c->gparts; - const int gcount = c->gcount; + struct gpart *restrict gparts = c->grav.parts; + const int gcount = c->grav.count; const struct engine *e = r->e; const struct external_potential *potential = e->external_potential; const struct phys_const *constants = e->physical_constants; @@ -391,8 +392,8 @@ void runner_do_grav_external(struct runner *r, struct cell *c, int timer) { */ void runner_do_grav_mesh(struct runner *r, struct cell *c, int timer) { - struct gpart *restrict gparts = c->gparts; - const int gcount = c->gcount; + struct gpart *restrict gparts = c->grav.parts; + const int gcount = c->grav.count; const struct engine *e = r->e; #ifdef SWIFT_DEBUG_CHECKS @@ -433,11 +434,12 @@ void runner_do_cooling(struct runner *r, struct cell *c, int timer) { const struct cooling_function_data *cooling_func = e->cooling_func; const struct phys_const *constants = e->physical_constants; const struct unit_system *us = e->internal_units; + const struct hydro_props *hydro_props = e->hydro_properties; const double time_base = e->time_base; const integertime_t ti_current = e->ti_current; - struct part *restrict parts = c->parts; - struct xpart *restrict xparts = c->xparts; - const int count = c->count; + struct part *restrict parts = c->hydro.parts; + struct xpart *restrict xparts = c->hydro.xparts; + const int count = c->hydro.count; TIMER_TIC; @@ -459,19 +461,25 @@ void runner_do_cooling(struct runner *r, struct cell *c, int timer) { if (part_is_active(p, e)) { - double dt_cool; + double dt_cool, dt_therm; if (with_cosmology) { const integertime_t ti_step = get_integer_timestep(p->time_bin); const integertime_t ti_begin = - get_integer_time_begin(ti_current + 1, p->time_bin); + get_integer_time_begin(ti_current - 1, p->time_bin); + dt_cool = cosmology_get_delta_time(cosmo, ti_begin, ti_begin + ti_step); + dt_therm = cosmology_get_therm_kick_factor(e->cosmology, ti_begin, + ti_begin + ti_step); + } else { dt_cool = get_timestep(p->time_bin, time_base); + dt_therm = get_timestep(p->time_bin, time_base); } /* Let's cool ! */ - cooling_cool_part(constants, us, cosmo, cooling_func, p, xp, dt_cool); + cooling_cool_part(constants, us, cosmo, hydro_props, cooling_func, p, + xp, dt_cool, dt_therm); } } } @@ -479,6 +487,52 @@ void runner_do_cooling(struct runner *r, struct cell *c, int timer) { if (timer) TIMER_TOC(timer_do_cooling); } +/** + * + */ +void runner_do_star_formation(struct runner *r, struct cell *c, int timer) { + + const struct engine *e = r->e; + const struct cosmology *cosmo = e->cosmology; + const int count = c->hydro.count; + struct part *restrict parts = c->hydro.parts; + struct xpart *restrict xparts = c->hydro.xparts; + + TIMER_TIC; + + /* Anything to do here? */ + if (!cell_is_active_hydro(c, e)) return; + + /* Recurse? */ + if (c->split) { + for (int k = 0; k < 8; k++) + if (c->progeny[k] != NULL) runner_do_star_formation(r, c->progeny[k], 0); + } else { + + /* Loop over the gas particles in this cell. */ + for (int k = 0; k < count; k++) { + + /* Get a handle on the part. */ + struct part *restrict p = &parts[k]; + struct xpart *restrict xp = &xparts[k]; + + if (part_is_active(p, e)) { + + const float rho = hydro_get_physical_density(p, cosmo); + + // MATTHIEU: Temporary star-formation law + // Do not use this at home. + if (rho > 1.5e7 && e->step > 2) { + message("Removing particle id=%lld rho=%e", p->id, rho); + cell_convert_part_to_gpart(e, c, p, xp); + } + } + } + } + + if (timer) TIMER_TOC(timer_do_star_formation); +} + /** * @brief Sort the entries in ascending order using QuickSort. * @@ -568,11 +622,11 @@ void runner_do_sort_ascending(struct entry *sort, int N) { void runner_check_sorts(struct cell *c, int flags) { #ifdef SWIFT_DEBUG_CHECKS - if (flags & ~c->sorted) error("Inconsistent sort flags (downward)!"); + if (flags & ~c->hydro.sorted) error("Inconsistent sort flags (downward)!"); if (c->split) for (int k = 0; k < 8; k++) - if (c->progeny[k] != NULL && c->progeny[k]->count > 0) - runner_check_sorts(c->progeny[k], c->sorted); + if (c->progeny[k] != NULL && c->progeny[k]->hydro.count > 0) + runner_check_sorts(c->progeny[k], c->hydro.sorted); #else error("Calling debugging code without debugging flag activated."); #endif @@ -593,21 +647,21 @@ void runner_do_sort(struct runner *r, struct cell *c, int flags, int cleanup, int clock) { struct entry *fingers[8]; - const int count = c->count; - const struct part *parts = c->parts; - struct xpart *xparts = c->xparts; + const int count = c->hydro.count; + const struct part *parts = c->hydro.parts; + struct xpart *xparts = c->hydro.xparts; float buff[8]; TIMER_TIC; /* We need to do the local sorts plus whatever was requested further up. */ - flags |= c->do_sort; + flags |= c->hydro.do_sort; if (cleanup) { - c->sorted = 0; + c->hydro.sorted = 0; } else { - flags &= ~c->sorted; + flags &= ~c->hydro.sorted; } - if (flags == 0 && !c->do_sub_sort) return; + if (flags == 0 && !c->hydro.do_sub_sort) return; /* Check that the particles have been moved to the current time */ if (flags && !cell_are_part_drifted(c, r->e)) @@ -615,24 +669,25 @@ void runner_do_sort(struct runner *r, struct cell *c, int flags, int cleanup, #ifdef SWIFT_DEBUG_CHECKS /* Make sure the sort flags are consistent (downward). */ - runner_check_sorts(c, c->sorted); + runner_check_sorts(c, c->hydro.sorted); /* Make sure the sort flags are consistent (upard). */ for (struct cell *finger = c->parent; finger != NULL; finger = finger->parent) { - if (finger->sorted & ~c->sorted) error("Inconsistent sort flags (upward)."); + if (finger->hydro.sorted & ~c->hydro.sorted) + error("Inconsistent sort flags (upward)."); } /* Update the sort timer which represents the last time the sorts were re-set. */ - if (c->sorted == 0) c->ti_sort = r->e->ti_current; + if (c->hydro.sorted == 0) c->hydro.ti_sort = r->e->ti_current; #endif /* start by allocating the entry arrays in the requested dimensions. */ for (int j = 0; j < 13; j++) { - if ((flags & (1 << j)) && c->sort[j] == NULL) { - if ((c->sort[j] = (struct entry *)malloc(sizeof(struct entry) * - (count + 1))) == NULL) + if ((flags & (1 << j)) && c->hydro.sort[j] == NULL) { + if ((c->hydro.sort[j] = (struct entry *)malloc(sizeof(struct entry) * + (count + 1))) == NULL) error("Failed to allocate sort memory."); } } @@ -644,18 +699,19 @@ void runner_do_sort(struct runner *r, struct cell *c, int flags, int cleanup, float dx_max_sort = 0.0f; float dx_max_sort_old = 0.0f; for (int k = 0; k < 8; k++) { - if (c->progeny[k] != NULL && c->progeny[k]->count > 0) { + if (c->progeny[k] != NULL && c->progeny[k]->hydro.count > 0) { /* Only propagate cleanup if the progeny is stale. */ runner_do_sort(r, c->progeny[k], flags, - cleanup && (c->progeny[k]->dx_max_sort > + cleanup && (c->progeny[k]->hydro.dx_max_sort > space_maxreldx * c->progeny[k]->dmin), 0); - dx_max_sort = max(dx_max_sort, c->progeny[k]->dx_max_sort); - dx_max_sort_old = max(dx_max_sort_old, c->progeny[k]->dx_max_sort_old); + dx_max_sort = max(dx_max_sort, c->progeny[k]->hydro.dx_max_sort); + dx_max_sort_old = + max(dx_max_sort_old, c->progeny[k]->hydro.dx_max_sort_old); } } - c->dx_max_sort = dx_max_sort; - c->dx_max_sort_old = dx_max_sort_old; + c->hydro.dx_max_sort = dx_max_sort; + c->hydro.dx_max_sort_old = dx_max_sort_old; /* Loop over the 13 different sort arrays. */ for (int j = 0; j < 13; j++) { @@ -668,7 +724,7 @@ void runner_do_sort(struct runner *r, struct cell *c, int flags, int cleanup, off[0] = 0; for (int k = 1; k < 8; k++) if (c->progeny[k - 1] != NULL) - off[k] = off[k - 1] + c->progeny[k - 1]->count; + off[k] = off[k - 1] + c->progeny[k - 1]->hydro.count; else off[k] = off[k - 1]; @@ -676,8 +732,8 @@ void runner_do_sort(struct runner *r, struct cell *c, int flags, int cleanup, int inds[8]; for (int k = 0; k < 8; k++) { inds[k] = k; - if (c->progeny[k] != NULL && c->progeny[k]->count > 0) { - fingers[k] = c->progeny[k]->sort[j]; + if (c->progeny[k] != NULL && c->progeny[k]->hydro.count > 0) { + fingers[k] = c->progeny[k]->hydro.sort[j]; buff[k] = fingers[k]->d; off[k] = off[k]; } else @@ -694,7 +750,7 @@ void runner_do_sort(struct runner *r, struct cell *c, int flags, int cleanup, } /* For each entry in the new sort list. */ - struct entry *finger = c->sort[j]; + struct entry *finger = c->hydro.sort[j]; for (int ind = 0; ind < count; ind++) { /* Copy the minimum into the new sort array. */ @@ -715,11 +771,11 @@ void runner_do_sort(struct runner *r, struct cell *c, int flags, int cleanup, } /* Merge. */ /* Add a sentinel. */ - c->sort[j][count].d = FLT_MAX; - c->sort[j][count].i = 0; + c->hydro.sort[j][count].d = FLT_MAX; + c->hydro.sort[j][count].i = 0; /* Mark as sorted. */ - atomic_or(&c->sorted, 1 << j); + atomic_or(&c->hydro.sorted, 1 << j); } /* loop over sort arrays. */ @@ -729,7 +785,7 @@ void runner_do_sort(struct runner *r, struct cell *c, int flags, int cleanup, else { /* Reset the sort distance */ - if (c->sorted == 0) { + if (c->hydro.sorted == 0) { #ifdef SWIFT_DEBUG_CHECKS if (xparts != NULL && c->nodeID != engine_rank) error("Have non-NULL xparts in foreign cell"); @@ -743,8 +799,8 @@ void runner_do_sort(struct runner *r, struct cell *c, int flags, int cleanup, xparts[k].x_diff_sort[2] = 0.0f; } } - c->dx_max_sort_old = 0.f; - c->dx_max_sort = 0.f; + c->hydro.dx_max_sort_old = 0.f; + c->hydro.dx_max_sort = 0.f; } /* Fill the sort array. */ @@ -752,20 +808,20 @@ void runner_do_sort(struct runner *r, struct cell *c, int flags, int cleanup, const double px[3] = {parts[k].x[0], parts[k].x[1], parts[k].x[2]}; for (int j = 0; j < 13; j++) if (flags & (1 << j)) { - c->sort[j][k].i = k; - c->sort[j][k].d = px[0] * runner_shift[j][0] + - px[1] * runner_shift[j][1] + - px[2] * runner_shift[j][2]; + c->hydro.sort[j][k].i = k; + c->hydro.sort[j][k].d = px[0] * runner_shift[j][0] + + px[1] * runner_shift[j][1] + + px[2] * runner_shift[j][2]; } } /* Add the sentinel and sort. */ for (int j = 0; j < 13; j++) if (flags & (1 << j)) { - c->sort[j][count].d = FLT_MAX; - c->sort[j][count].i = 0; - runner_do_sort_ascending(c->sort[j], count); - atomic_or(&c->sorted, 1 << j); + c->hydro.sort[j][count].d = FLT_MAX; + c->hydro.sort[j][count].i = 0; + runner_do_sort_ascending(c->hydro.sort[j], count); + atomic_or(&c->hydro.sorted, 1 << j); } } @@ -773,7 +829,7 @@ void runner_do_sort(struct runner *r, struct cell *c, int flags, int cleanup, /* Verify the sorting. */ for (int j = 0; j < 13; j++) { if (!(flags & (1 << j))) continue; - struct entry *finger = c->sort[j]; + struct entry *finger = c->hydro.sort[j]; for (int k = 1; k < count; k++) { if (finger[k].d < finger[k - 1].d) error("Sorting failed, ascending array."); @@ -787,14 +843,15 @@ void runner_do_sort(struct runner *r, struct cell *c, int flags, int cleanup, /* Make sure the sort flags are consistent (upward). */ for (struct cell *finger = c->parent; finger != NULL; finger = finger->parent) { - if (finger->sorted & ~c->sorted) error("Inconsistent sort flags."); + if (finger->hydro.sorted & ~c->hydro.sorted) + error("Inconsistent sort flags."); } #endif /* Clear the cell's sort flags. */ - c->do_sort = 0; - c->do_sub_sort = 0; - c->requires_sorts = 0; + c->hydro.do_sort = 0; + c->hydro.do_sub_sort = 0; + c->hydro.requires_sorts = 0; if (clock) TIMER_TOC(timer_dosort); } @@ -821,7 +878,7 @@ void runner_do_init_grav(struct runner *r, struct cell *c, int timer) { if (!cell_is_active_gravity(c, e)) return; /* Reset the gravity acceleration tensors */ - gravity_field_tensors_init(&c->multipole->pot, e->ti_current); + gravity_field_tensors_init(&c->grav.multipole->pot, e->ti_current); /* Recurse? */ if (c->split) { @@ -845,14 +902,15 @@ void runner_do_extra_ghost(struct runner *r, struct cell *c, int timer) { #ifdef EXTRA_HYDRO_LOOP - struct part *restrict parts = c->parts; - struct xpart *restrict xparts = c->xparts; - const int count = c->count; + struct part *restrict parts = c->hydro.parts; + struct xpart *restrict xparts = c->hydro.xparts; + const int count = c->hydro.count; const struct engine *e = r->e; const integertime_t ti_end = e->ti_current; const int with_cosmology = (e->policy & engine_policy_cosmology); const double time_base = e->time_base; const struct cosmology *cosmo = e->cosmology; + const struct hydro_props *hydro_props = e->hydro_properties; TIMER_TIC; @@ -891,7 +949,7 @@ void runner_do_extra_ghost(struct runner *r, struct cell *c, int timer) { } /* Compute variables required for the force loop */ - hydro_prepare_force(p, xp, cosmo, dt_alpha); + hydro_prepare_force(p, xp, cosmo, hydro_props, dt_alpha); /* The particle force values are now set. Do _NOT_ try to read any particle density variables! */ @@ -919,8 +977,8 @@ void runner_do_extra_ghost(struct runner *r, struct cell *c, int timer) { */ void runner_do_ghost(struct runner *r, struct cell *c, int timer) { - struct part *restrict parts = c->parts; - struct xpart *restrict xparts = c->xparts; + struct part *restrict parts = c->hydro.parts; + struct xpart *restrict xparts = c->hydro.xparts; const struct engine *e = r->e; const struct space *s = e->s; const struct hydro_space *hs = &s->hs; @@ -946,9 +1004,9 @@ void runner_do_ghost(struct runner *r, struct cell *c, int timer) { /* Init the list of active particles that have to be updated. */ int *pid = NULL; - if ((pid = (int *)malloc(sizeof(int) * c->count)) == NULL) + if ((pid = (int *)malloc(sizeof(int) * c->hydro.count)) == NULL) error("Can't allocate memory for pid."); - for (int k = 0; k < c->count; k++) + for (int k = 0; k < c->hydro.count; k++) if (part_is_active(&parts[k], e)) { pid[count] = k; ++count; @@ -1024,6 +1082,8 @@ void runner_do_ghost(struct runner *r, struct cell *c, int timer) { hydro_reset_gradient(p); #else + const struct hydro_props *hydro_props = e->hydro_properties; + /* Calculate the time-step for passing to hydro_prepare_force, used * for the evolution of alpha factors (i.e. those involved in the * artificial viscosity and thermal conduction terms) */ @@ -1043,7 +1103,7 @@ void runner_do_ghost(struct runner *r, struct cell *c, int timer) { /* As of here, particle force variables will be set. */ /* Compute variables required for the force loop */ - hydro_prepare_force(p, xp, cosmo, dt_alpha); + hydro_prepare_force(p, xp, cosmo, hydro_props, dt_alpha); /* The particle force values are now set. Do _NOT_ try to read any particle density variables! */ @@ -1053,6 +1113,7 @@ void runner_do_ghost(struct runner *r, struct cell *c, int timer) { #endif /* EXTRA_HYDRO_LOOP */ + /* Ok, we are done with this particle */ continue; } @@ -1122,6 +1183,8 @@ void runner_do_ghost(struct runner *r, struct cell *c, int timer) { hydro_reset_gradient(p); #else + const struct hydro_props *hydro_props = e->hydro_properties; + /* Calculate the time-step for passing to hydro_prepare_force, used for * the evolution of alpha factors (i.e. those involved in the artificial * viscosity and thermal conduction terms) */ @@ -1140,7 +1203,7 @@ void runner_do_ghost(struct runner *r, struct cell *c, int timer) { /* As of here, particle force variables will be set. */ /* Compute variables required for the force loop */ - hydro_prepare_force(p, xp, cosmo, dt_alpha); + hydro_prepare_force(p, xp, cosmo, hydro_props, dt_alpha); /* The particle force values are now set. Do _NOT_ try to read any particle density variables! */ @@ -1162,7 +1225,7 @@ void runner_do_ghost(struct runner *r, struct cell *c, int timer) { for (struct cell *finger = c; finger != NULL; finger = finger->parent) { /* Run through this cell's density interactions. */ - for (struct link *l = finger->density; l != NULL; l = l->next) { + for (struct link *l = finger->hydro.density; l != NULL; l = l->next) { #ifdef SWIFT_DEBUG_CHECKS if (l->t->ti_run < r->e->ti_current) @@ -1226,7 +1289,7 @@ void runner_do_ghost(struct runner *r, struct cell *c, int timer) { static void runner_do_unskip_hydro(struct cell *c, struct engine *e) { /* Ignore empty cells. */ - if (c->count == 0) return; + if (c->hydro.count == 0) return; /* Skip inactive cells. */ if (!cell_is_active_hydro(c, e)) return; @@ -1255,7 +1318,7 @@ static void runner_do_unskip_hydro(struct cell *c, struct engine *e) { static void runner_do_unskip_stars(struct cell *c, struct engine *e) { /* Ignore empty cells. */ - if (c->scount == 0) return; + if (c->stars.count == 0) return; /* Skip inactive cells. */ if (!cell_is_active_stars(c, e)) return; @@ -1284,7 +1347,7 @@ static void runner_do_unskip_stars(struct cell *c, struct engine *e) { static void runner_do_unskip_gravity(struct cell *c, struct engine *e) { /* Ignore empty cells. */ - if (c->gcount == 0) return; + if (c->grav.count == 0) return; /* Skip inactive cells. */ if (!cell_is_active_gravity(c, e)) return; @@ -1379,13 +1442,13 @@ void runner_do_kick1(struct runner *r, struct cell *c, int timer) { const struct cosmology *cosmo = e->cosmology; const struct hydro_props *hydro_props = e->hydro_properties; const int with_cosmology = (e->policy & engine_policy_cosmology); - struct part *restrict parts = c->parts; - struct xpart *restrict xparts = c->xparts; - struct gpart *restrict gparts = c->gparts; - struct spart *restrict sparts = c->sparts; - const int count = c->count; - const int gcount = c->gcount; - const int scount = c->scount; + struct part *restrict parts = c->hydro.parts; + struct xpart *restrict xparts = c->hydro.xparts; + struct gpart *restrict gparts = c->grav.parts; + struct spart *restrict sparts = c->stars.parts; + const int count = c->hydro.count; + const int gcount = c->grav.count; + const int scount = c->stars.count; const integertime_t ti_current = e->ti_current; const double time_base = e->time_base; @@ -1553,13 +1616,13 @@ void runner_do_kick2(struct runner *r, struct cell *c, int timer) { const struct cosmology *cosmo = e->cosmology; const struct hydro_props *hydro_props = e->hydro_properties; const int with_cosmology = (e->policy & engine_policy_cosmology); - const int count = c->count; - const int gcount = c->gcount; - const int scount = c->scount; - struct part *restrict parts = c->parts; - struct xpart *restrict xparts = c->xparts; - struct gpart *restrict gparts = c->gparts; - struct spart *restrict sparts = c->sparts; + const int count = c->hydro.count; + const int gcount = c->grav.count; + const int scount = c->stars.count; + struct part *restrict parts = c->hydro.parts; + struct xpart *restrict xparts = c->hydro.xparts; + struct gpart *restrict gparts = c->grav.parts; + struct spart *restrict sparts = c->stars.parts; const integertime_t ti_current = e->ti_current; const double time_base = e->time_base; @@ -1727,25 +1790,26 @@ void runner_do_timestep(struct runner *r, struct cell *c, int timer) { const struct engine *e = r->e; const integertime_t ti_current = e->ti_current; - const int count = c->count; - const int gcount = c->gcount; - const int scount = c->scount; - struct part *restrict parts = c->parts; - struct xpart *restrict xparts = c->xparts; - struct gpart *restrict gparts = c->gparts; - struct spart *restrict sparts = c->sparts; + const int count = c->hydro.count; + const int gcount = c->grav.count; + const int scount = c->stars.count; + struct part *restrict parts = c->hydro.parts; + struct xpart *restrict xparts = c->hydro.xparts; + struct gpart *restrict gparts = c->grav.parts; + struct spart *restrict sparts = c->stars.parts; TIMER_TIC; /* Anything to do here? */ if (!cell_is_active_hydro(c, e) && !cell_is_active_gravity(c, e)) { - c->updated = 0; - c->g_updated = 0; - c->s_updated = 0; + c->hydro.updated = 0; + c->grav.updated = 0; + c->stars.updated = 0; return; } int updated = 0, g_updated = 0, s_updated = 0; + int inhibited = 0, g_inhibited = 0, s_inhibited = 0; integertime_t ti_hydro_end_min = max_nr_timesteps, ti_hydro_end_max = 0, ti_hydro_beg_max = 0; integertime_t ti_gravity_end_min = max_nr_timesteps, ti_gravity_end_max = 0, @@ -1806,6 +1870,9 @@ void runner_do_timestep(struct runner *r, struct cell *c, int timer) { else { /* part is inactive */ + /* Count the number of inhibited particles */ + if (part_is_inhibited(p, e)) inhibited++; + const integertime_t ti_end = get_integer_time_end(ti_current, p->time_bin); @@ -1872,6 +1939,9 @@ void runner_do_timestep(struct runner *r, struct cell *c, int timer) { } else { /* gpart is inactive */ + /* Count the number of inhibited particles */ + if (gpart_is_inhibited(gp, e)) g_inhibited++; + const integertime_t ti_end = get_integer_time_end(ti_current, gp->time_bin); @@ -1923,7 +1993,11 @@ void runner_do_timestep(struct runner *r, struct cell *c, int timer) { /* What is the next starting point for this cell ? */ ti_gravity_beg_max = max(ti_current, ti_gravity_beg_max); - } else { /* stars particle is inactive */ + /* star particle is inactive but not inhibited */ + } else { + + /* Count the number of inhibited particles */ + if (spart_is_inhibited(sp, e)) ++s_inhibited; const integertime_t ti_end = get_integer_time_end(ti_current, sp->time_bin); @@ -1950,35 +2024,41 @@ void runner_do_timestep(struct runner *r, struct cell *c, int timer) { runner_do_timestep(r, cp, 0); /* And aggregate */ - updated += cp->updated; - g_updated += cp->g_updated; - s_updated += cp->s_updated; - ti_hydro_end_min = min(cp->ti_hydro_end_min, ti_hydro_end_min); - ti_hydro_end_max = max(cp->ti_hydro_end_max, ti_hydro_end_max); - ti_hydro_beg_max = max(cp->ti_hydro_beg_max, ti_hydro_beg_max); - ti_gravity_end_min = min(cp->ti_gravity_end_min, ti_gravity_end_min); - ti_gravity_end_max = max(cp->ti_gravity_end_max, ti_gravity_end_max); - ti_gravity_beg_max = max(cp->ti_gravity_beg_max, ti_gravity_beg_max); + updated += cp->hydro.updated; + g_updated += cp->grav.updated; + s_updated += cp->stars.updated; + inhibited += cp->hydro.inhibited; + g_inhibited += cp->grav.inhibited; + s_inhibited += cp->stars.inhibited; + ti_hydro_end_min = min(cp->hydro.ti_end_min, ti_hydro_end_min); + ti_hydro_end_max = max(cp->hydro.ti_end_max, ti_hydro_end_max); + ti_hydro_beg_max = max(cp->hydro.ti_beg_max, ti_hydro_beg_max); + ti_gravity_end_min = min(cp->grav.ti_end_min, ti_gravity_end_min); + ti_gravity_end_max = max(cp->grav.ti_end_max, ti_gravity_end_max); + ti_gravity_beg_max = max(cp->grav.ti_beg_max, ti_gravity_beg_max); } } /* Store the values. */ - c->updated = updated; - c->g_updated = g_updated; - c->s_updated = s_updated; - c->ti_hydro_end_min = ti_hydro_end_min; - c->ti_hydro_end_max = ti_hydro_end_max; - c->ti_hydro_beg_max = ti_hydro_beg_max; - c->ti_gravity_end_min = ti_gravity_end_min; - c->ti_gravity_end_max = ti_gravity_end_max; - c->ti_gravity_beg_max = ti_gravity_beg_max; + c->hydro.updated = updated; + c->grav.updated = g_updated; + c->stars.updated = s_updated; + c->hydro.inhibited = inhibited; + c->grav.inhibited = g_inhibited; + c->stars.inhibited = s_inhibited; + c->hydro.ti_end_min = ti_hydro_end_min; + c->hydro.ti_end_max = ti_hydro_end_max; + c->hydro.ti_beg_max = ti_hydro_beg_max; + c->grav.ti_end_min = ti_gravity_end_min; + c->grav.ti_end_max = ti_gravity_end_max; + c->grav.ti_beg_max = ti_gravity_beg_max; #ifdef SWIFT_DEBUG_CHECKS - if (c->ti_hydro_end_min == e->ti_current && - c->ti_hydro_end_min < max_nr_timesteps) + if (c->hydro.ti_end_min == e->ti_current && + c->hydro.ti_end_min < max_nr_timesteps) error("End of next hydro step is current time!"); - if (c->ti_gravity_end_min == e->ti_current && - c->ti_gravity_end_min < max_nr_timesteps) + if (c->grav.ti_end_min == e->ti_current && + c->grav.ti_end_min < max_nr_timesteps) error("End of next gravity step is current time!"); #endif @@ -1998,12 +2078,12 @@ void runner_do_end_force(struct runner *r, struct cell *c, int timer) { const struct engine *e = r->e; const struct space *s = e->s; const struct cosmology *cosmo = e->cosmology; - const int count = c->count; - const int gcount = c->gcount; - const int scount = c->scount; - struct part *restrict parts = c->parts; - struct gpart *restrict gparts = c->gparts; - struct spart *restrict sparts = c->sparts; + const int count = c->hydro.count; + const int gcount = c->grav.count; + const int scount = c->stars.count; + struct part *restrict parts = c->hydro.parts; + struct gpart *restrict gparts = c->grav.parts; + struct spart *restrict sparts = c->stars.parts; const int periodic = s->periodic; const float G_newton = e->physical_constants->const_newton_G; @@ -2089,7 +2169,8 @@ void runner_do_end_force(struct runner *r, struct cell *c, int timer) { /* Check that this gpart has interacted with all the other * particles (via direct or multipoles) in the box */ - if (gp->num_interacted != e->total_nr_gparts) { + if (gp->num_interacted != + e->total_nr_gparts - e->count_inhibited_gparts) { /* Get the ID of the gpart */ long long my_id = 0; @@ -2106,9 +2187,9 @@ void runner_do_end_force(struct runner *r, struct cell *c, int timer) { "g-particle (id=%lld, type=%s) did not interact " "gravitationally with all other gparts " "gp->num_interacted=%lld, total_gparts=%lld (local " - "num_gparts=%zd)", + "num_gparts=%zd inhibited_gparts=%lld)", my_id, part_type_names[gp->type], gp->num_interacted, - e->total_nr_gparts, e->s->nr_gparts); + e->total_nr_gparts, e->s->nr_gparts, e->count_inhibited_gparts); } } #endif @@ -2144,8 +2225,8 @@ void runner_do_recv_part(struct runner *r, struct cell *c, int clear_sorts, #ifdef WITH_MPI - const struct part *restrict parts = c->parts; - const size_t nr_parts = c->count; + const struct part *restrict parts = c->hydro.parts; + const size_t nr_parts = c->hydro.count; const integertime_t ti_current = r->e->ti_current; TIMER_TIC; @@ -2161,7 +2242,7 @@ void runner_do_recv_part(struct runner *r, struct cell *c, int clear_sorts, #endif /* Clear this cell's sorted mask. */ - if (clear_sorts) c->sorted = 0; + if (clear_sorts) c->hydro.sorted = 0; /* If this cell is a leaf, collect the particle data. */ if (!c->split) { @@ -2182,13 +2263,13 @@ void runner_do_recv_part(struct runner *r, struct cell *c, int clear_sorts, /* Otherwise, recurse and collect. */ else { for (int k = 0; k < 8; k++) { - if (c->progeny[k] != NULL && c->progeny[k]->count > 0) { + if (c->progeny[k] != NULL && c->progeny[k]->hydro.count > 0) { runner_do_recv_part(r, c->progeny[k], clear_sorts, 0); ti_hydro_end_min = - min(ti_hydro_end_min, c->progeny[k]->ti_hydro_end_min); + min(ti_hydro_end_min, c->progeny[k]->hydro.ti_end_min); ti_hydro_end_max = - max(ti_hydro_end_max, c->progeny[k]->ti_hydro_end_max); - h_max = max(h_max, c->progeny[k]->h_max); + max(ti_hydro_end_max, c->progeny[k]->hydro.ti_end_max); + h_max = max(h_max, c->progeny[k]->hydro.h_max); } } } @@ -2202,10 +2283,10 @@ void runner_do_recv_part(struct runner *r, struct cell *c, int clear_sorts, #endif /* ... and store. */ - // c->ti_hydro_end_min = ti_hydro_end_min; - // c->ti_hydro_end_max = ti_hydro_end_max; - c->ti_old_part = ti_current; - c->h_max = h_max; + // c->hydro.ti_end_min = ti_hydro_end_min; + // c->hydro.ti_end_max = ti_hydro_end_max; + c->hydro.ti_old_part = ti_current; + c->hydro.h_max = h_max; if (timer) TIMER_TOC(timer_dorecv_part); @@ -2225,8 +2306,8 @@ void runner_do_recv_gpart(struct runner *r, struct cell *c, int timer) { #ifdef WITH_MPI - const struct gpart *restrict gparts = c->gparts; - const size_t nr_gparts = c->gcount; + const struct gpart *restrict gparts = c->grav.parts; + const size_t nr_gparts = c->grav.count; const integertime_t ti_current = r->e->ti_current; TIMER_TIC; @@ -2258,12 +2339,12 @@ void runner_do_recv_gpart(struct runner *r, struct cell *c, int timer) { /* Otherwise, recurse and collect. */ else { for (int k = 0; k < 8; k++) { - if (c->progeny[k] != NULL && c->progeny[k]->gcount > 0) { + if (c->progeny[k] != NULL && c->progeny[k]->grav.count > 0) { runner_do_recv_gpart(r, c->progeny[k], 0); ti_gravity_end_min = - min(ti_gravity_end_min, c->progeny[k]->ti_gravity_end_min); + min(ti_gravity_end_min, c->progeny[k]->grav.ti_end_min); ti_gravity_end_max = - max(ti_gravity_end_max, c->progeny[k]->ti_gravity_end_max); + max(ti_gravity_end_max, c->progeny[k]->grav.ti_end_max); } } } @@ -2277,9 +2358,9 @@ void runner_do_recv_gpart(struct runner *r, struct cell *c, int timer) { #endif /* ... and store. */ - // c->ti_gravity_end_min = ti_gravity_end_min; - // c->ti_gravity_end_max = ti_gravity_end_max; - c->ti_old_gpart = ti_current; + // c->grav.ti_end_min = ti_gravity_end_min; + // c->grav.ti_end_max = ti_gravity_end_max; + c->grav.ti_old_part = ti_current; if (timer) TIMER_TOC(timer_dorecv_gpart); @@ -2299,10 +2380,12 @@ void runner_do_recv_spart(struct runner *r, struct cell *c, int timer) { #ifdef WITH_MPI - const struct spart *restrict sparts = c->sparts; - const size_t nr_sparts = c->scount; + const struct spart *restrict sparts = c->stars.parts; + const size_t nr_sparts = c->stars.count; const integertime_t ti_current = r->e->ti_current; + error("Need to add h_max computation"); + TIMER_TIC; integertime_t ti_gravity_end_min = max_nr_timesteps; @@ -2332,12 +2415,12 @@ void runner_do_recv_spart(struct runner *r, struct cell *c, int timer) { /* Otherwise, recurse and collect. */ else { for (int k = 0; k < 8; k++) { - if (c->progeny[k] != NULL && c->progeny[k]->scount > 0) { + if (c->progeny[k] != NULL && c->progeny[k]->stars.count > 0) { runner_do_recv_spart(r, c->progeny[k], 0); ti_gravity_end_min = - min(ti_gravity_end_min, c->progeny[k]->ti_gravity_end_min); + min(ti_gravity_end_min, c->progeny[k]->grav.ti_end_min); ti_gravity_end_max = - max(ti_gravity_end_max, c->progeny[k]->ti_gravity_end_max); + max(ti_gravity_end_max, c->progeny[k]->grav.ti_end_max); } } } @@ -2351,9 +2434,9 @@ void runner_do_recv_spart(struct runner *r, struct cell *c, int timer) { #endif /* ... and store. */ - // c->ti_gravity_end_min = ti_gravity_end_min; - // c->ti_gravity_end_max = ti_gravity_end_max; - c->ti_old_gpart = ti_current; + // c->grav.ti_end_min = ti_gravity_end_min; + // c->grav.ti_end_max = ti_gravity_end_max; + c->grav.ti_old_part = ti_current; if (timer) TIMER_TOC(timer_dorecv_spart); @@ -2494,7 +2577,8 @@ void *runner_main(void *data) { case task_type_sort: /* Cleanup only if any of the indices went stale. */ runner_do_sort(r, ci, t->flags, - ci->dx_max_sort_old > space_maxreldx * ci->dmin, 1); + ci->hydro.dx_max_sort_old > space_maxreldx * ci->dmin, + 1); /* Reset the sort flags as our work here is done. */ t->flags = 0; break; @@ -2527,6 +2611,9 @@ void *runner_main(void *data) { case task_type_end_force: runner_do_end_force(r, ci, 1); break; + case task_type_logger: + runner_do_logger(r, ci, 1); + break; case task_type_timestep: runner_do_timestep(r, ci, 1); break; @@ -2573,6 +2660,9 @@ void *runner_main(void *data) { case task_type_cooling: runner_do_cooling(r, t->ci, 1); break; + 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; @@ -2602,3 +2692,70 @@ void *runner_main(void *data) { /* Be kind, rewind. */ return NULL; } + +/** + * @brief Write the required particles through the logger. + * + * @param r The runner thread. + * @param c The cell. + * @param timer Are we timing this ? + */ +void runner_do_logger(struct runner *r, struct cell *c, int timer) { + +#ifdef WITH_LOGGER + TIMER_TIC; + + const struct engine *e = r->e; + struct part *restrict parts = c->hydro.parts; + struct xpart *restrict xparts = c->hydro.xparts; + const int count = c->hydro.count; + + /* Anything to do here? */ + if (!cell_is_starting_hydro(c, e) && !cell_is_starting_gravity(c, e)) return; + + /* Recurse? Avoid spending too much time in useless cells. */ + if (c->split) { + for (int k = 0; k < 8; k++) + if (c->progeny[k] != NULL) runner_do_logger(r, c->progeny[k], 0); + } else { + + /* Loop over the parts in this cell. */ + for (int k = 0; k < count; k++) { + + /* Get a handle on the part. */ + struct part *restrict p = &parts[k]; + struct xpart *restrict xp = &xparts[k]; + + /* If particle needs to be log */ + /* This is the same function than part_is_active, except for + * debugging checks */ + if (part_is_starting(p, e)) { + + if (logger_should_write(&xp->logger_data, e->logger)) { + /* Write particle */ + /* Currently writing everything, should adapt it through time */ + logger_log_part(e->logger, p, + logger_mask_x | logger_mask_v | logger_mask_a | + logger_mask_u | logger_mask_h | logger_mask_rho | + logger_mask_consts, + &xp->logger_data.last_offset); + + /* Set counter back to zero */ + xp->logger_data.steps_since_last_output = 0; + } else + /* Update counter */ + xp->logger_data.steps_since_last_output += 1; + } + } + } + + if (c->grav.count > 0) error("gparts not implemented"); + + if (c->stars.count > 0) error("sparts not implemented"); + + if (timer) TIMER_TOC(timer_logger); + +#else + error("Logger disabled, please enable it during configuration"); +#endif +} diff --git a/src/runner.h b/src/runner.h index e33a3e380e6097a67258d116d617483caca35086..29c42da405255c217d43cc905e87dde9b69276f9 100644 --- a/src/runner.h +++ b/src/runner.h @@ -80,6 +80,7 @@ void runner_do_init(struct runner *r, struct cell *c, int timer); void runner_do_cooling(struct runner *r, struct cell *c, int timer); void runner_do_grav_external(struct runner *r, struct cell *c, int timer); void runner_do_grav_fft(struct runner *r, int timer); +void runner_do_logger(struct runner *r, struct cell *c, int timer); void *runner_main(void *data); void runner_do_unskip_mapper(void *map_data, int num_elements, void *extra_data); diff --git a/src/runner_doiact.h b/src/runner_doiact.h index 942455194da947c3d3ef170f674d9d7b816f9381..53cf51ed400f82d0e195e38dd08fcc5af16f1ad7 100644 --- a/src/runner_doiact.h +++ b/src/runner_doiact.h @@ -145,10 +145,10 @@ void DOPAIR1_NAIVE(struct runner *r, struct cell *restrict ci, /* Anything to do here? */ if (!cell_is_active_hydro(ci, e) && !cell_is_active_hydro(cj, e)) return; - const int count_i = ci->count; - const int count_j = cj->count; - struct part *restrict parts_i = ci->parts; - struct part *restrict parts_j = cj->parts; + const int count_i = ci->hydro.count; + const int count_j = cj->hydro.count; + struct part *restrict parts_i = ci->hydro.parts; + struct part *restrict parts_j = cj->hydro.parts; /* Cosmological terms */ const float a = cosmo->a; @@ -169,6 +169,7 @@ void DOPAIR1_NAIVE(struct runner *r, struct cell *restrict ci, /* Get a hold of the ith part in ci. */ struct part *restrict pi = &parts_i[pid]; const int pi_active = part_is_active(pi, e); + const int pi_inhibited = part_is_inhibited(pi, e); const float hi = pi->h; const float hig2 = hi * hi * kernel_gamma2; const float pix[3] = {(float)(pi->x[0] - (cj->loc[0] + shift[0])), @@ -183,6 +184,7 @@ void DOPAIR1_NAIVE(struct runner *r, struct cell *restrict ci, const float hj = pj->h; const float hjg2 = hj * hj * kernel_gamma2; const int pj_active = part_is_active(pj, e); + const int pj_inhibited = part_is_inhibited(pj, e); /* Compute the pairwise distance. */ const float pjx[3] = {(float)(pj->x[0] - cj->loc[0]), @@ -193,21 +195,21 @@ void DOPAIR1_NAIVE(struct runner *r, struct cell *restrict ci, #ifdef SWIFT_DEBUG_CHECKS /* Check that particles have been drifted to the current time */ - if (pi->ti_drift != e->ti_current) + if (pi->ti_drift != e->ti_current && !pi_inhibited) error("Particle pi not drifted to current time"); - if (pj->ti_drift != e->ti_current) + if (pj->ti_drift != e->ti_current && !pj_inhibited) error("Particle pj not drifted to current time"); #endif /* Hit or miss? */ - if (r2 < hig2 && pi_active) { + if (r2 < hig2 && pi_active && !pj_inhibited) { IACT_NONSYM(r2, dx, hi, hj, pi, pj, a, H); #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj, a, H); #endif } - if (r2 < hjg2 && pj_active) { + if (r2 < hjg2 && pj_active && !pi_inhibited) { dx[0] = -dx[0]; dx[1] = -dx[1]; @@ -245,10 +247,10 @@ void DOPAIR2_NAIVE(struct runner *r, struct cell *restrict ci, /* Anything to do here? */ if (!cell_is_active_hydro(ci, e) && !cell_is_active_hydro(cj, e)) return; - const int count_i = ci->count; - const int count_j = cj->count; - struct part *restrict parts_i = ci->parts; - struct part *restrict parts_j = cj->parts; + const int count_i = ci->hydro.count; + const int count_j = cj->hydro.count; + struct part *restrict parts_i = ci->hydro.parts; + struct part *restrict parts_j = cj->hydro.parts; /* Cosmological terms */ const float a = cosmo->a; @@ -269,6 +271,7 @@ void DOPAIR2_NAIVE(struct runner *r, struct cell *restrict ci, /* Get a hold of the ith part in ci. */ struct part *restrict pi = &parts_i[pid]; const int pi_active = part_is_active(pi, e); + const int pi_inhibited = part_is_inhibited(pi, e); const float hi = pi->h; const float hig2 = hi * hi * kernel_gamma2; const float pix[3] = {(float)(pi->x[0] - (cj->loc[0] + shift[0])), @@ -281,6 +284,7 @@ void DOPAIR2_NAIVE(struct runner *r, struct cell *restrict ci, /* Get a pointer to the jth particle. */ struct part *restrict pj = &parts_j[pjd]; const int pj_active = part_is_active(pj, e); + const int pj_inhibited = part_is_inhibited(pj, e); const float hj = pj->h; const float hjg2 = hj * hj * kernel_gamma2; @@ -293,28 +297,28 @@ void DOPAIR2_NAIVE(struct runner *r, struct cell *restrict ci, #ifdef SWIFT_DEBUG_CHECKS /* Check that particles have been drifted to the current time */ - if (pi->ti_drift != e->ti_current) + if (pi->ti_drift != e->ti_current && !pj_inhibited) error("Particle pi not drifted to current time"); - if (pj->ti_drift != e->ti_current) + if (pj->ti_drift != e->ti_current && !pi_inhibited) error("Particle pj not drifted to current time"); #endif /* Hit or miss? */ if (r2 < hig2 || r2 < hjg2) { - if (pi_active && pj_active) { + if (pi_active && pj_active && !pi_inhibited && !pj_inhibited) { IACT(r2, dx, hi, hj, pi, pj, a, H); #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) runner_iact_chemistry(r2, dx, hi, hj, pi, pj, a, H); #endif - } else if (pi_active) { + } else if (pi_active && !pj_inhibited) { IACT_NONSYM(r2, dx, hi, hj, pi, pj, a, H); #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj, a, H); #endif - } else if (pj_active) { + } else if (pj_active && !pi_inhibited) { dx[0] = -dx[0]; dx[1] = -dx[1]; @@ -354,8 +358,8 @@ void DOSELF1_NAIVE(struct runner *r, struct cell *restrict c) { const float a = cosmo->a; const float H = cosmo->H; - const int count = c->count; - struct part *restrict parts = c->parts; + const int count = c->hydro.count; + struct part *restrict parts = c->hydro.parts; /* Loop over the parts in ci. */ for (int pid = 0; pid < count; pid++) { @@ -363,6 +367,7 @@ void DOSELF1_NAIVE(struct runner *r, struct cell *restrict c) { /* Get a hold of the ith part in ci. */ struct part *restrict pi = &parts[pid]; const int pi_active = part_is_active(pi, e); + const int pi_inhibited = part_is_inhibited(pi, e); const float hi = pi->h; const float hig2 = hi * hi * kernel_gamma2; const float pix[3] = {(float)(pi->x[0] - c->loc[0]), @@ -377,6 +382,7 @@ void DOSELF1_NAIVE(struct runner *r, struct cell *restrict c) { const float hj = pj->h; const float hjg2 = hj * hj * kernel_gamma2; const int pj_active = part_is_active(pj, e); + const int pj_inhibited = part_is_inhibited(pj, e); /* Compute the pairwise distance. */ const float pjx[3] = {(float)(pj->x[0] - c->loc[0]), @@ -385,14 +391,14 @@ void DOSELF1_NAIVE(struct runner *r, struct cell *restrict c) { float dx[3] = {pix[0] - pjx[0], pix[1] - pjx[1], pix[2] - pjx[2]}; const float r2 = dx[0] * dx[0] + dx[1] * dx[1] + dx[2] * dx[2]; - const int doi = pi_active && (r2 < hig2); - const int doj = pj_active && (r2 < hjg2); + const int doi = pi_active && (r2 < hig2) && !pj_inhibited; + const int doj = pj_active && (r2 < hjg2) && !pi_inhibited; #ifdef SWIFT_DEBUG_CHECKS /* Check that particles have been drifted to the current time */ - if (pi->ti_drift != e->ti_current) + if (pi->ti_drift != e->ti_current && !pi_inhibited) error("Particle pi not drifted to current time"); - if (pj->ti_drift != e->ti_current) + if (pj->ti_drift != e->ti_current && !pj_inhibited) error("Particle pj not drifted to current time"); #endif @@ -448,8 +454,8 @@ void DOSELF2_NAIVE(struct runner *r, struct cell *restrict c) { const float a = cosmo->a; const float H = cosmo->H; - const int count = c->count; - struct part *restrict parts = c->parts; + const int count = c->hydro.count; + struct part *restrict parts = c->hydro.parts; /* Loop over the parts in ci. */ for (int pid = 0; pid < count; pid++) { @@ -457,6 +463,7 @@ void DOSELF2_NAIVE(struct runner *r, struct cell *restrict c) { /* Get a hold of the ith part in ci. */ struct part *restrict pi = &parts[pid]; const int pi_active = part_is_active(pi, e); + const int pi_inhibited = part_is_inhibited(pi, e); const float hi = pi->h; const float hig2 = hi * hi * kernel_gamma2; const float pix[3] = {(float)(pi->x[0] - c->loc[0]), @@ -471,6 +478,7 @@ void DOSELF2_NAIVE(struct runner *r, struct cell *restrict c) { const float hj = pj->h; const float hjg2 = hj * hj * kernel_gamma2; const int pj_active = part_is_active(pj, e); + const int pj_inhibited = part_is_inhibited(pj, e); /* Compute the pairwise distance. */ const float pjx[3] = {(float)(pj->x[0] - c->loc[0]), @@ -479,14 +487,16 @@ void DOSELF2_NAIVE(struct runner *r, struct cell *restrict c) { float dx[3] = {pix[0] - pjx[0], pix[1] - pjx[1], pix[2] - pjx[2]}; const float r2 = dx[0] * dx[0] + dx[1] * dx[1] + dx[2] * dx[2]; - const int doi = pi_active && ((r2 < hig2) || (r2 < hjg2)); - const int doj = pj_active && ((r2 < hig2) || (r2 < hjg2)); + const int doi = + pi_active && ((r2 < hig2) || (r2 < hjg2)) && !pj_inhibited; + const int doj = + pj_active && ((r2 < hig2) || (r2 < hjg2)) && !pi_inhibited; #ifdef SWIFT_DEBUG_CHECKS /* Check that particles have been drifted to the current time */ - if (pi->ti_drift != e->ti_current) + if (pi->ti_drift != e->ti_current && !pi_inhibited) error("Particle pi not drifted to current time"); - if (pj->ti_drift != e->ti_current) + if (pj->ti_drift != e->ti_current && !pj_inhibited) error("Particle pj not drifted to current time"); #endif @@ -544,8 +554,8 @@ void DOPAIR_SUBSET_NAIVE(struct runner *r, struct cell *restrict ci, TIMER_TIC; - const int count_j = cj->count; - struct part *restrict parts_j = cj->parts; + const int count_j = cj->hydro.count; + struct part *restrict parts_j = cj->hydro.parts; /* Cosmological terms */ const float a = cosmo->a; @@ -571,6 +581,7 @@ void DOPAIR_SUBSET_NAIVE(struct runner *r, struct cell *restrict ci, /* Get a pointer to the jth particle. */ struct part *restrict pj = &parts_j[pjd]; + const int pj_inhibited = part_is_inhibited(pj, e); /* Compute the pairwise distance. */ float r2 = 0.0f; @@ -584,12 +595,12 @@ void DOPAIR_SUBSET_NAIVE(struct runner *r, struct cell *restrict ci, /* Check that particles have been drifted to the current time */ if (pi->ti_drift != e->ti_current) error("Particle pi not drifted to current time"); - if (pj->ti_drift != e->ti_current) + if (pj->ti_drift != e->ti_current && !pj_inhibited) error("Particle pj not drifted to current time"); #endif /* Hit or miss? */ - if (r2 < hig2) { + if (r2 < hig2 && !pj_inhibited) { IACT_NONSYM(r2, dx, hi, pj->h, pi, pj, a, H); #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) @@ -626,16 +637,16 @@ void DOPAIR_SUBSET(struct runner *r, struct cell *restrict ci, TIMER_TIC; - const int count_j = cj->count; - struct part *restrict parts_j = cj->parts; + const int count_j = cj->hydro.count; + struct part *restrict parts_j = cj->hydro.parts; /* Cosmological terms */ const float a = cosmo->a; const float H = cosmo->H; /* Pick-out the sorted lists. */ - const struct entry *restrict sort_j = cj->sort[sid]; - const float dxj = cj->dx_max_sort; + const struct entry *restrict sort_j = cj->hydro.sort[sid]; + const float dxj = cj->hydro.dx_max_sort; /* Parts are on the left? */ if (!flipped) { @@ -658,6 +669,7 @@ void DOPAIR_SUBSET(struct runner *r, struct cell *restrict ci, /* Get a pointer to the jth particle. */ struct part *restrict pj = &parts_j[sort_j[pjd].i]; + const int pj_inhibited = part_is_inhibited(pj, e); const float hj = pj->h; const double pjx = pj->x[0]; const double pjy = pj->x[1]; @@ -672,12 +684,12 @@ void DOPAIR_SUBSET(struct runner *r, struct cell *restrict ci, /* Check that particles have been drifted to the current time */ if (pi->ti_drift != e->ti_current) error("Particle pi not drifted to current time"); - if (pj->ti_drift != e->ti_current) + if (pj->ti_drift != e->ti_current && !pj_inhibited) error("Particle pj not drifted to current time"); #endif /* Hit or miss? */ - if (r2 < hig2) { + if (r2 < hig2 && !pj_inhibited) { IACT_NONSYM(r2, dx, hi, hj, pi, pj, a, H); #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) @@ -709,6 +721,7 @@ void DOPAIR_SUBSET(struct runner *r, struct cell *restrict ci, /* Get a pointer to the jth particle. */ struct part *restrict pj = &parts_j[sort_j[pjd].i]; + const int pj_inhibited = part_is_inhibited(pj, e); const float hj = pj->h; const double pjx = pj->x[0]; const double pjy = pj->x[1]; @@ -723,12 +736,12 @@ void DOPAIR_SUBSET(struct runner *r, struct cell *restrict ci, /* Check that particles have been drifted to the current time */ if (pi->ti_drift != e->ti_current) error("Particle pi not drifted to current time"); - if (pj->ti_drift != e->ti_current) + if (pj->ti_drift != e->ti_current && !pj_inhibited) error("Particle pj not drifted to current time"); #endif /* Hit or miss? */ - if (r2 < hig2) { + if (r2 < hig2 && !pj_inhibited) { IACT_NONSYM(r2, dx, hi, hj, pi, pj, a, H); #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) @@ -782,8 +795,8 @@ void DOPAIR_SUBSET_BRANCH(struct runner *r, struct cell *restrict ci, sid = sortlistID[sid]; /* Has the cell cj been sorted? */ - if (!(cj->sorted & (1 << sid)) || - cj->dx_max_sort_old > space_maxreldx * cj->dmin) + if (!(cj->hydro.sorted & (1 << sid)) || + cj->hydro.dx_max_sort_old > space_maxreldx * cj->dmin) error("Interacting unsorted cells."); #endif @@ -822,8 +835,8 @@ void DOSELF_SUBSET(struct runner *r, struct cell *restrict ci, const float a = cosmo->a; const float H = cosmo->H; - const int count_i = ci->count; - struct part *restrict parts_j = ci->parts; + const int count_i = ci->hydro.count; + struct part *restrict parts_j = ci->hydro.parts; /* Loop over the parts in ci. */ for (int pid = 0; pid < count; pid++) { @@ -845,6 +858,7 @@ void DOSELF_SUBSET(struct runner *r, struct cell *restrict ci, /* Get a pointer to the jth particle. */ struct part *restrict pj = &parts_j[pjd]; + const int pj_inhibited = part_is_inhibited(pj, e); const float hj = pj->h; /* Compute the pairwise distance. */ @@ -858,12 +872,12 @@ void DOSELF_SUBSET(struct runner *r, struct cell *restrict ci, /* Check that particles have been drifted to the current time */ if (pi->ti_drift != e->ti_current) error("Particle pi not drifted to current time"); - if (pj->ti_drift != e->ti_current) + if (pj->ti_drift != e->ti_current && !pj_inhibited) error("Particle pj not drifted to current time"); #endif /* Hit or miss? */ - if (r2 > 0.f && r2 < hig2) { + if (r2 > 0.f && r2 < hig2 && !pj_inhibited) { IACT_NONSYM(r2, dx, hi, hj, pi, pj, a, H); #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) @@ -919,29 +933,32 @@ void DOPAIR1(struct runner *r, struct cell *ci, struct cell *cj, const int sid, for (int k = 0; k < 3; k++) rshift += shift[k] * runner_shift[sid][k]; /* Pick-out the sorted lists. */ - const struct entry *restrict sort_i = ci->sort[sid]; - const struct entry *restrict sort_j = cj->sort[sid]; + const struct entry *restrict sort_i = ci->hydro.sort[sid]; + const struct entry *restrict sort_j = cj->hydro.sort[sid]; #ifdef SWIFT_DEBUG_CHECKS /* Some constants used to checks that the parts are in the right frame */ const float shift_threshold_x = - 2. * ci->width[0] + 2. * max(ci->dx_max_part, cj->dx_max_part); + 2. * ci->width[0] + + 2. * max(ci->hydro.dx_max_part, cj->hydro.dx_max_part); const float shift_threshold_y = - 2. * ci->width[1] + 2. * max(ci->dx_max_part, cj->dx_max_part); + 2. * ci->width[1] + + 2. * max(ci->hydro.dx_max_part, cj->hydro.dx_max_part); const float shift_threshold_z = - 2. * ci->width[2] + 2. * max(ci->dx_max_part, cj->dx_max_part); + 2. * ci->width[2] + + 2. * max(ci->hydro.dx_max_part, cj->hydro.dx_max_part); #endif /* SWIFT_DEBUG_CHECKS */ /* Get some other useful values. */ - const double hi_max = ci->h_max * kernel_gamma - rshift; - const double hj_max = cj->h_max * kernel_gamma; - const int count_i = ci->count; - const int count_j = cj->count; - struct part *restrict parts_i = ci->parts; - struct part *restrict parts_j = cj->parts; + const double hi_max = ci->hydro.h_max * kernel_gamma - rshift; + const double hj_max = cj->hydro.h_max * kernel_gamma; + const int count_i = ci->hydro.count; + const int count_j = cj->hydro.count; + struct part *restrict parts_i = ci->hydro.parts; + struct part *restrict parts_j = cj->hydro.parts; const double di_max = sort_i[count_i - 1].d - rshift; const double dj_min = sort_j[0].d; - const float dx_max = (ci->dx_max_sort + cj->dx_max_sort); + const float dx_max = (ci->hydro.dx_max_sort + cj->hydro.dx_max_sort); /* Cosmological terms */ const float a = cosmo->a; @@ -975,6 +992,7 @@ void DOPAIR1(struct runner *r, struct cell *ci, struct cell *cj, const int sid, /* Recover pj */ struct part *pj = &parts_j[sort_j[pjd].i]; + const int pj_inhibited = part_is_inhibited(pj, e); const float hj = pj->h; const float pjx = pj->x[0] - cj->loc[0]; const float pjy = pj->x[1] - cj->loc[1]; @@ -1014,12 +1032,12 @@ void DOPAIR1(struct runner *r, struct cell *ci, struct cell *cj, const int sid, /* Check that particles have been drifted to the current time */ if (pi->ti_drift != e->ti_current) error("Particle pi not drifted to current time"); - if (pj->ti_drift != e->ti_current) + if (pj->ti_drift != e->ti_current && !pj_inhibited) error("Particle pj not drifted to current time"); #endif /* Hit or miss? */ - if (r2 < hig2) { + if (r2 < hig2 && !pj_inhibited) { IACT_NONSYM(r2, dx, hi, hj, pi, pj, a, H); #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) @@ -1058,6 +1076,7 @@ void DOPAIR1(struct runner *r, struct cell *ci, struct cell *cj, const int sid, /* Recover pi */ struct part *pi = &parts_i[sort_i[pid].i]; + const int pi_inhibited = part_is_inhibited(pi, e); const float hi = pi->h; const float pix = pi->x[0] - (cj->loc[0] + shift[0]); const float piy = pi->x[1] - (cj->loc[1] + shift[1]); @@ -1095,14 +1114,14 @@ void DOPAIR1(struct runner *r, struct cell *ci, struct cell *cj, const int sid, pjz, ci->width[2]); /* Check that particles have been drifted to the current time */ - if (pi->ti_drift != e->ti_current) + if (pi->ti_drift != e->ti_current && !pi_inhibited) error("Particle pi not drifted to current time"); if (pj->ti_drift != e->ti_current) error("Particle pj not drifted to current time"); #endif /* Hit or miss? */ - if (r2 < hjg2) { + if (r2 < hjg2 && !pi_inhibited) { IACT_NONSYM(r2, dx, hj, hi, pj, pi, a, H); #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) @@ -1141,49 +1160,55 @@ void DOPAIR1_BRANCH(struct runner *r, struct cell *ci, struct cell *cj) { const int sid = space_getsid(e->s, &ci, &cj, shift); /* Have the cells been sorted? */ - if (!(ci->sorted & (1 << sid)) || - ci->dx_max_sort_old > space_maxreldx * ci->dmin) + if (!(ci->hydro.sorted & (1 << sid)) || + ci->hydro.dx_max_sort_old > space_maxreldx * ci->dmin) error("Interacting unsorted cells."); - if (!(cj->sorted & (1 << sid)) || - cj->dx_max_sort_old > space_maxreldx * cj->dmin) + if (!(cj->hydro.sorted & (1 << sid)) || + cj->hydro.dx_max_sort_old > space_maxreldx * cj->dmin) error("Interacting unsorted cells."); #ifdef SWIFT_DEBUG_CHECKS /* Pick-out the sorted lists. */ - const struct entry *restrict sort_i = ci->sort[sid]; - const struct entry *restrict sort_j = cj->sort[sid]; + const struct entry *restrict sort_i = ci->hydro.sort[sid]; + const struct entry *restrict sort_j = cj->hydro.sort[sid]; /* Check that the dx_max_sort values in the cell are indeed an upper bound on particle movement. */ - for (int pid = 0; pid < ci->count; pid++) { - const struct part *p = &ci->parts[sort_i[pid].i]; + for (int pid = 0; pid < ci->hydro.count; pid++) { + const struct part *p = &ci->hydro.parts[sort_i[pid].i]; + if (part_is_inhibited(p, e)) continue; + const float d = p->x[0] * runner_shift[sid][0] + p->x[1] * runner_shift[sid][1] + p->x[2] * runner_shift[sid][2]; - if (fabsf(d - sort_i[pid].d) - ci->dx_max_sort > - 1.0e-4 * max(fabsf(d), ci->dx_max_sort_old) && - fabsf(d - sort_i[pid].d) - ci->dx_max_sort > ci->width[0] * 1.0e-10) + if (fabsf(d - sort_i[pid].d) - ci->hydro.dx_max_sort > + 1.0e-4 * max(fabsf(d), ci->hydro.dx_max_sort_old) && + fabsf(d - sort_i[pid].d) - ci->hydro.dx_max_sort > + ci->width[0] * 1.0e-10) error( "particle shift diff exceeds dx_max_sort in cell ci. ci->nodeID=%d " - "cj->nodeID=%d d=%e sort_i[pid].d=%e ci->dx_max_sort=%e " - "ci->dx_max_sort_old=%e", - ci->nodeID, cj->nodeID, d, sort_i[pid].d, ci->dx_max_sort, - ci->dx_max_sort_old); + "cj->nodeID=%d d=%e sort_i[pid].d=%e ci->hydro.dx_max_sort=%e " + "ci->hydro.dx_max_sort_old=%e", + ci->nodeID, cj->nodeID, d, sort_i[pid].d, ci->hydro.dx_max_sort, + ci->hydro.dx_max_sort_old); } - for (int pjd = 0; pjd < cj->count; pjd++) { - const struct part *p = &cj->parts[sort_j[pjd].i]; + for (int pjd = 0; pjd < cj->hydro.count; pjd++) { + const struct part *p = &cj->hydro.parts[sort_j[pjd].i]; + if (part_is_inhibited(p, e)) continue; + const float d = p->x[0] * runner_shift[sid][0] + p->x[1] * runner_shift[sid][1] + p->x[2] * runner_shift[sid][2]; - if ((fabsf(d - sort_j[pjd].d) - cj->dx_max_sort) > - 1.0e-4 * max(fabsf(d), cj->dx_max_sort_old) && - (fabsf(d - sort_j[pjd].d) - cj->dx_max_sort) > cj->width[0] * 1.0e-10) + if ((fabsf(d - sort_j[pjd].d) - cj->hydro.dx_max_sort) > + 1.0e-4 * max(fabsf(d), cj->hydro.dx_max_sort_old) && + (fabsf(d - sort_j[pjd].d) - cj->hydro.dx_max_sort) > + cj->width[0] * 1.0e-10) error( "particle shift diff exceeds dx_max_sort in cell cj. cj->nodeID=%d " - "ci->nodeID=%d d=%e sort_j[pjd].d=%e cj->dx_max_sort=%e " - "cj->dx_max_sort_old=%e", - cj->nodeID, ci->nodeID, d, sort_j[pjd].d, cj->dx_max_sort, - cj->dx_max_sort_old); + "ci->nodeID=%d d=%e sort_j[pjd].d=%e cj->hydro.dx_max_sort=%e " + "cj->hydro.dx_max_sort_old=%e", + cj->nodeID, ci->nodeID, d, sort_j[pjd].d, cj->hydro.dx_max_sort, + cj->hydro.dx_max_sort_old); } #endif /* SWIFT_DEBUG_CHECKS */ @@ -1222,33 +1247,36 @@ void DOPAIR2(struct runner *r, struct cell *ci, struct cell *cj, const int sid, for (int k = 0; k < 3; k++) rshift += shift[k] * runner_shift[sid][k]; /* Pick-out the sorted lists. */ - struct entry *restrict sort_i = ci->sort[sid]; - struct entry *restrict sort_j = cj->sort[sid]; + struct entry *restrict sort_i = ci->hydro.sort[sid]; + struct entry *restrict sort_j = cj->hydro.sort[sid]; #ifdef SWIFT_DEBUG_CHECKS /* Some constants used to checks that the parts are in the right frame */ const float shift_threshold_x = - 2. * ci->width[0] + 2. * max(ci->dx_max_part, cj->dx_max_part); + 2. * ci->width[0] + + 2. * max(ci->hydro.dx_max_part, cj->hydro.dx_max_part); const float shift_threshold_y = - 2. * ci->width[1] + 2. * max(ci->dx_max_part, cj->dx_max_part); + 2. * ci->width[1] + + 2. * max(ci->hydro.dx_max_part, cj->hydro.dx_max_part); const float shift_threshold_z = - 2. * ci->width[2] + 2. * max(ci->dx_max_part, cj->dx_max_part); + 2. * ci->width[2] + + 2. * max(ci->hydro.dx_max_part, cj->hydro.dx_max_part); #endif /* SWIFT_DEBUG_CHECKS */ /* Get some other useful values. */ - const double hi_max = ci->h_max; - const double hj_max = cj->h_max; - const int count_i = ci->count; - const int count_j = cj->count; - struct part *restrict parts_i = ci->parts; - struct part *restrict parts_j = cj->parts; + const double hi_max = ci->hydro.h_max; + const double hj_max = cj->hydro.h_max; + const int count_i = ci->hydro.count; + const int count_j = cj->hydro.count; + struct part *restrict parts_i = ci->hydro.parts; + struct part *restrict parts_j = cj->hydro.parts; /* Cosmological terms */ const float a = cosmo->a; const float H = cosmo->H; /* Maximal displacement since last rebuild */ - const double dx_max = (ci->dx_max_sort + cj->dx_max_sort); + const double dx_max = (ci->hydro.dx_max_sort + cj->hydro.dx_max_sort); /* Position on the axis of the particles closest to the interface */ const double di_max = sort_i[count_i - 1].d; @@ -1307,6 +1335,7 @@ void DOPAIR2(struct runner *r, struct cell *ci, struct cell *cj, const int sid, /* Get a hold of the ith part in ci. */ struct part *pi = &parts_i[sort_i[pid].i]; + const int pi_inhibited = part_is_inhibited(pi, e); const float hi = pi->h; /* Is there anything we need to interact with (for this specific hi) ? */ @@ -1337,7 +1366,7 @@ void DOPAIR2(struct runner *r, struct cell *ci, struct cell *cj, const int sid, const float pjz = pj->x[2] - shift_j[2]; /* Compute the pairwise distance. */ - float dx[3] = {pjx - pix, pjy - piy, pjz - piz}; + const float dx[3] = {pjx - pix, pjy - piy, pjz - piz}; const float r2 = dx[0] * dx[0] + dx[1] * dx[1] + dx[2] * dx[2]; #ifdef SWIFT_DEBUG_CHECKS @@ -1368,7 +1397,7 @@ void DOPAIR2(struct runner *r, struct cell *ci, struct cell *cj, const int sid, pjz, ci->width[2]); /* Check that particles have been drifted to the current time */ - if (pi->ti_drift != e->ti_current) + if (pi->ti_drift != e->ti_current && !pi_inhibited) error("Particle pi not drifted to current time"); if (pj->ti_drift != e->ti_current) error("Particle pj not drifted to current time"); @@ -1376,7 +1405,7 @@ void DOPAIR2(struct runner *r, struct cell *ci, struct cell *cj, const int sid, /* Hit or miss? (note that we will do the other condition in the reverse loop) */ - if (r2 < hig2) { + if (r2 < hig2 && !pi_inhibited) { IACT_NONSYM(r2, dx, hj, hi, pj, pi, a, H); #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) runner_iact_nonsym_chemistry(r2, dx, hj, hi, pj, pi, a, H); @@ -1392,6 +1421,7 @@ void DOPAIR2(struct runner *r, struct cell *ci, struct cell *cj, const int sid, /* Recover pj */ struct part *pj = &parts_j[sort_j[pjd].i]; + const int pj_inhibited = part_is_inhibited(pj, e); const float hj = pj->h; /* Get the position of pj in the right frame */ @@ -1400,7 +1430,7 @@ void DOPAIR2(struct runner *r, struct cell *ci, struct cell *cj, const int sid, const float pjz = pj->x[2] - shift_j[2]; /* Compute the pairwise distance. */ - float dx[3] = {pix - pjx, piy - pjy, piz - pjz}; + const float dx[3] = {pix - pjx, piy - pjy, piz - pjz}; const float r2 = dx[0] * dx[0] + dx[1] * dx[1] + dx[2] * dx[2]; #ifdef SWIFT_DEBUG_CHECKS @@ -1431,14 +1461,14 @@ void DOPAIR2(struct runner *r, struct cell *ci, struct cell *cj, const int sid, pjz, ci->width[2]); /* Check that particles have been drifted to the current time */ - if (pi->ti_drift != e->ti_current) + if (pi->ti_drift != e->ti_current && !pi_inhibited) error("Particle pi not drifted to current time"); - if (pj->ti_drift != e->ti_current) + if (pj->ti_drift != e->ti_current && !pj_inhibited) error("Particle pj not drifted to current time"); #endif /* Hit or miss? (note that we will do the other condition in the reverse loop) */ - if (r2 < hig2) { + if (r2 < hig2 && !pj_inhibited) { /* Does pj need to be updated too? */ if (part_is_active(pj, e)) { @@ -1466,6 +1496,7 @@ void DOPAIR2(struct runner *r, struct cell *ci, struct cell *cj, const int sid, /* Get a hold of the jth part in cj. */ struct part *pj = &parts_j[sort_j[pjd].i]; + const int pj_inhibited = part_is_inhibited(pj, e); const float hj = pj->h; /* Is there anything we need to interact with (for this specific hj) ? */ @@ -1497,7 +1528,7 @@ void DOPAIR2(struct runner *r, struct cell *ci, struct cell *cj, const int sid, const float piz = pi->x[2] - shift_i[2]; /* Compute the pairwise distance. */ - float dx[3] = {pix - pjx, piy - pjy, piz - pjz}; + const float dx[3] = {pix - pjx, piy - pjy, piz - pjz}; const float r2 = dx[0] * dx[0] + dx[1] * dx[1] + dx[2] * dx[2]; #ifdef SWIFT_DEBUG_CHECKS @@ -1530,13 +1561,13 @@ void DOPAIR2(struct runner *r, struct cell *ci, struct cell *cj, const int sid, /* Check that particles have been drifted to the current time */ if (pi->ti_drift != e->ti_current) error("Particle pi not drifted to current time"); - if (pj->ti_drift != e->ti_current) + if (pj->ti_drift != e->ti_current && !pj_inhibited) error("Particle pj not drifted to current time"); #endif /* Hit or miss? (note that we must avoid the r2 < hig2 cases we already processed) */ - if (r2 < hjg2 && r2 >= hig2) { + if (r2 < hjg2 && r2 >= hig2 && !pj_inhibited) { IACT_NONSYM(r2, dx, hi, hj, pi, pj, a, H); #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj, a, H); @@ -1553,6 +1584,7 @@ void DOPAIR2(struct runner *r, struct cell *ci, struct cell *cj, const int sid, /* Recover pi */ struct part *pi = &parts_i[sort_i[pid].i]; + const int pi_inhibited = part_is_inhibited(pi, e); const float hi = pi->h; const float hig2 = hi * hi * kernel_gamma2; @@ -1562,7 +1594,7 @@ void DOPAIR2(struct runner *r, struct cell *ci, struct cell *cj, const int sid, const float piz = pi->x[2] - shift_i[2]; /* Compute the pairwise distance. */ - float dx[3] = {pjx - pix, pjy - piy, pjz - piz}; + const float dx[3] = {pjx - pix, pjy - piy, pjz - piz}; const float r2 = dx[0] * dx[0] + dx[1] * dx[1] + dx[2] * dx[2]; #ifdef SWIFT_DEBUG_CHECKS @@ -1593,15 +1625,15 @@ void DOPAIR2(struct runner *r, struct cell *ci, struct cell *cj, const int sid, pjz, ci->width[2]); /* Check that particles have been drifted to the current time */ - if (pi->ti_drift != e->ti_current) + if (pi->ti_drift != e->ti_current && !pi_inhibited) error("Particle pi not drifted to current time"); - if (pj->ti_drift != e->ti_current) + if (pj->ti_drift != e->ti_current && !pj_inhibited) error("Particle pj not drifted to current time"); #endif /* Hit or miss? (note that we must avoid the r2 < hig2 cases we already processed) */ - if (r2 < hjg2 && r2 >= hig2) { + if (r2 < hjg2 && r2 >= hig2 && !pi_inhibited) { /* Does pi need to be updated too? */ if (part_is_active(pi, e)) { @@ -1654,49 +1686,55 @@ void DOPAIR2_BRANCH(struct runner *r, struct cell *ci, struct cell *cj) { const int sid = space_getsid(e->s, &ci, &cj, shift); /* Have the cells been sorted? */ - if (!(ci->sorted & (1 << sid)) || - ci->dx_max_sort_old > space_maxreldx * ci->dmin) + if (!(ci->hydro.sorted & (1 << sid)) || + ci->hydro.dx_max_sort_old > space_maxreldx * ci->dmin) error("Interacting unsorted cells."); - if (!(cj->sorted & (1 << sid)) || - cj->dx_max_sort_old > space_maxreldx * cj->dmin) + if (!(cj->hydro.sorted & (1 << sid)) || + cj->hydro.dx_max_sort_old > space_maxreldx * cj->dmin) error("Interacting unsorted cells."); #ifdef SWIFT_DEBUG_CHECKS /* Pick-out the sorted lists. */ - const struct entry *restrict sort_i = ci->sort[sid]; - const struct entry *restrict sort_j = cj->sort[sid]; + const struct entry *restrict sort_i = ci->hydro.sort[sid]; + const struct entry *restrict sort_j = cj->hydro.sort[sid]; /* Check that the dx_max_sort values in the cell are indeed an upper bound on particle movement. */ - for (int pid = 0; pid < ci->count; pid++) { - const struct part *p = &ci->parts[sort_i[pid].i]; + for (int pid = 0; pid < ci->hydro.count; pid++) { + const struct part *p = &ci->hydro.parts[sort_i[pid].i]; + if (part_is_inhibited(p, e)) continue; + const float d = p->x[0] * runner_shift[sid][0] + p->x[1] * runner_shift[sid][1] + p->x[2] * runner_shift[sid][2]; - if (fabsf(d - sort_i[pid].d) - ci->dx_max_sort > - 1.0e-4 * max(fabsf(d), ci->dx_max_sort_old) && - fabsf(d - sort_i[pid].d) - ci->dx_max_sort > ci->width[0] * 1.0e-10) + if (fabsf(d - sort_i[pid].d) - ci->hydro.dx_max_sort > + 1.0e-4 * max(fabsf(d), ci->hydro.dx_max_sort_old) && + fabsf(d - sort_i[pid].d) - ci->hydro.dx_max_sort > + ci->width[0] * 1.0e-10) error( "particle shift diff exceeds dx_max_sort in cell ci. ci->nodeID=%d " - "cj->nodeID=%d d=%e sort_i[pid].d=%e ci->dx_max_sort=%e " - "ci->dx_max_sort_old=%e", - ci->nodeID, cj->nodeID, d, sort_i[pid].d, ci->dx_max_sort, - ci->dx_max_sort_old); + "cj->nodeID=%d d=%e sort_i[pid].d=%e ci->hydro.dx_max_sort=%e " + "ci->hydro.dx_max_sort_old=%e", + ci->nodeID, cj->nodeID, d, sort_i[pid].d, ci->hydro.dx_max_sort, + ci->hydro.dx_max_sort_old); } - for (int pjd = 0; pjd < cj->count; pjd++) { - const struct part *p = &cj->parts[sort_j[pjd].i]; + for (int pjd = 0; pjd < cj->hydro.count; pjd++) { + const struct part *p = &cj->hydro.parts[sort_j[pjd].i]; + if (part_is_inhibited(p, e)) continue; + const float d = p->x[0] * runner_shift[sid][0] + p->x[1] * runner_shift[sid][1] + p->x[2] * runner_shift[sid][2]; - if (fabsf(d - sort_j[pjd].d) - cj->dx_max_sort > - 1.0e-4 * max(fabsf(d), cj->dx_max_sort_old) && - fabsf(d - sort_j[pjd].d) - cj->dx_max_sort > cj->width[0] * 1.0e-10) + if (fabsf(d - sort_j[pjd].d) - cj->hydro.dx_max_sort > + 1.0e-4 * max(fabsf(d), cj->hydro.dx_max_sort_old) && + fabsf(d - sort_j[pjd].d) - cj->hydro.dx_max_sort > + cj->width[0] * 1.0e-10) error( "particle shift diff exceeds dx_max_sort in cell cj. cj->nodeID=%d " - "ci->nodeID=%d d=%e sort_j[pjd].d=%e cj->dx_max_sort=%e " - "cj->dx_max_sort_old=%e", - cj->nodeID, ci->nodeID, d, sort_j[pjd].d, cj->dx_max_sort, - cj->dx_max_sort_old); + "ci->nodeID=%d d=%e sort_j[pjd].d=%e cj->hydro.dx_max_sort=%e " + "cj->hydro.dx_max_sort_old=%e", + cj->nodeID, ci->nodeID, d, sort_j[pjd].d, cj->hydro.dx_max_sort, + cj->hydro.dx_max_sort_old); } #endif /* SWIFT_DEBUG_CHECKS */ @@ -1726,8 +1764,8 @@ void DOSELF1(struct runner *r, struct cell *restrict c) { TIMER_TIC; - struct part *restrict parts = c->parts; - const int count = c->count; + struct part *restrict parts = c->hydro.parts; + const int count = c->hydro.count; /* Set up indt. */ int *indt = NULL; @@ -1750,6 +1788,7 @@ void DOSELF1(struct runner *r, struct cell *restrict c) { /* Get a pointer to the ith particle. */ struct part *restrict pi = &parts[pid]; + const int pi_inhibited = part_is_inhibited(pi, e); /* Get the particle position and radius. */ double pix[3]; @@ -1769,7 +1808,7 @@ void DOSELF1(struct runner *r, struct cell *restrict c) { #ifdef SWIFT_DEBUG_CHECKS /* Check that particles have been drifted to the current time */ - if (pi->ti_drift != e->ti_current) + if (pi->ti_drift != e->ti_current && !pi_inhibited) error("Particle pi not drifted to current time"); if (pj->ti_drift != e->ti_current) error("Particle pj not drifted to current time"); @@ -1784,7 +1823,7 @@ void DOSELF1(struct runner *r, struct cell *restrict c) { } /* Hit or miss? */ - if (r2 < hj * hj * kernel_gamma2) { + if (r2 < hj * hj * kernel_gamma2 && !pi_inhibited) { IACT_NONSYM(r2, dx, hj, hi, pj, pi, a, H); #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) @@ -1805,6 +1844,7 @@ void DOSELF1(struct runner *r, struct cell *restrict c) { /* Get a pointer to the jth particle. */ struct part *restrict pj = &parts[pjd]; + const int pj_inhibited = part_is_inhibited(pj, e); const float hj = pj->h; /* Compute the pairwise distance. */ @@ -1817,29 +1857,34 @@ void DOSELF1(struct runner *r, struct cell *restrict c) { const int doj = (part_is_active(pj, e)) && (r2 < hj * hj * kernel_gamma2); + const int doi = (r2 < hig2); + #ifdef SWIFT_DEBUG_CHECKS /* Check that particles have been drifted to the current time */ - if (pi->ti_drift != e->ti_current) + if (pi->ti_drift != e->ti_current && !pi_inhibited) error("Particle pi not drifted to current time"); - if (pj->ti_drift != e->ti_current) + if (pj->ti_drift != e->ti_current && !pj_inhibited) error("Particle pj not drifted to current time"); #endif /* Hit or miss? */ - if (r2 < hig2 || doj) { + if (doi || doj) { /* Which parts need to be updated? */ - if (r2 < hig2 && doj) { + if (doi && doj) { + IACT(r2, dx, hi, hj, pi, pj, a, H); #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) runner_iact_chemistry(r2, dx, hi, hj, pi, pj, a, H); #endif - } else if (!doj) { + } else if (doi && !pj_inhibited) { + IACT_NONSYM(r2, dx, hi, hj, pi, pj, a, H); #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) runner_iact_nonsym_chemistry(r2, dx, hi, hj, pi, pj, a, H); #endif - } else { + } else if (doj && !pi_inhibited) { + dx[0] = -dx[0]; dx[1] = -dx[1]; dx[2] = -dx[2]; @@ -1874,7 +1919,7 @@ void DOSELF1_BRANCH(struct runner *r, struct cell *c) { if (!cell_is_active_hydro(c, e)) return; /* Did we mess up the recursion? */ - if (c->h_max_old * kernel_gamma > c->dmin) + if (c->hydro.h_max_old * kernel_gamma > c->dmin) error("Cell smaller than smoothing length"); /* Check that cells are drifted. */ @@ -1903,8 +1948,8 @@ void DOSELF2(struct runner *r, struct cell *restrict c) { TIMER_TIC; - struct part *restrict parts = c->parts; - const int count = c->count; + struct part *restrict parts = c->hydro.parts; + const int count = c->hydro.count; /* Set up indt. */ int *indt = NULL; @@ -1927,6 +1972,7 @@ void DOSELF2(struct runner *r, struct cell *restrict c) { /* Get a pointer to the ith particle. */ struct part *restrict pi = &parts[pid]; + const int pi_inhibited = part_is_inhibited(pi, e); /* Get the particle position and radius. */ double pix[3]; @@ -1954,14 +2000,14 @@ void DOSELF2(struct runner *r, struct cell *restrict c) { #ifdef SWIFT_DEBUG_CHECKS /* Check that particles have been drifted to the current time */ - if (pi->ti_drift != e->ti_current) + if (pi->ti_drift != e->ti_current && !pi_inhibited) error("Particle pi not drifted to current time"); if (pj->ti_drift != e->ti_current) error("Particle pj not drifted to current time"); #endif /* Hit or miss? */ - if (r2 < hig2 || r2 < hj * hj * kernel_gamma2) { + if ((r2 < hig2 || r2 < hj * hj * kernel_gamma2) && !pi_inhibited) { IACT_NONSYM(r2, dx, hj, hi, pj, pi, a, H); #if (FUNCTION_TASK_LOOP == TASK_LOOP_DENSITY) @@ -1982,6 +2028,7 @@ void DOSELF2(struct runner *r, struct cell *restrict c) { /* Get a pointer to the jth particle. */ struct part *restrict pj = &parts[pjd]; + const int pj_inhibited = part_is_inhibited(pj, e); const float hj = pj->h; /* Compute the pairwise distance. */ @@ -1994,14 +2041,14 @@ void DOSELF2(struct runner *r, struct cell *restrict c) { #ifdef SWIFT_DEBUG_CHECKS /* Check that particles have been drifted to the current time */ - if (pi->ti_drift != e->ti_current) + if (pi->ti_drift != e->ti_current && !pi_inhibited) error("Particle pi not drifted to current time"); - if (pj->ti_drift != e->ti_current) + if (pj->ti_drift != e->ti_current && !pj_inhibited) error("Particle pj not drifted to current time"); #endif /* Hit or miss? */ - if (r2 < hig2 || r2 < hj * hj * kernel_gamma2) { + if ((r2 < hig2 || r2 < hj * hj * kernel_gamma2) && !pj_inhibited) { /* Does pj need to be updated too? */ if (part_is_active(pj, e)) { @@ -2041,7 +2088,7 @@ void DOSELF2_BRANCH(struct runner *r, struct cell *c) { if (!cell_is_active_hydro(c, e)) return; /* Did we mess up the recursion? */ - if (c->h_max_old * kernel_gamma > c->dmin) + if (c->hydro.h_max_old * kernel_gamma > c->dmin) error("Cell smaller than smoothing length"); /* Check that cells are drifted. */ @@ -2079,7 +2126,7 @@ void DOSUB_PAIR1(struct runner *r, struct cell *ci, struct cell *cj, int sid, /* Should we even bother? */ if (!cell_is_active_hydro(ci, e) && !cell_is_active_hydro(cj, e)) return; - if (ci->count == 0 || cj->count == 0) return; + if (ci->hydro.count == 0 || cj->hydro.count == 0) return; /* Get the type of pair if not specified explicitly. */ double shift[3]; @@ -2295,18 +2342,18 @@ void DOSUB_PAIR1(struct runner *r, struct cell *ci, struct cell *cj, int sid, error("Interacting undrifted cells."); /* Do any of the cells need to be sorted first? */ - if (!(ci->sorted & (1 << sid)) || - ci->dx_max_sort_old > ci->dmin * space_maxreldx) + if (!(ci->hydro.sorted & (1 << sid)) || + ci->hydro.dx_max_sort_old > ci->dmin * space_maxreldx) error( - "Interacting unsorted cell. ci->dx_max_sort_old=%e ci->dmin=%e " + "Interacting unsorted cell. ci->hydro.dx_max_sort_old=%e ci->dmin=%e " "ci->sorted=%d sid=%d", - ci->dx_max_sort_old, ci->dmin, ci->sorted, sid); - if (!(cj->sorted & (1 << sid)) || - cj->dx_max_sort_old > cj->dmin * space_maxreldx) + ci->hydro.dx_max_sort_old, ci->dmin, ci->hydro.sorted, sid); + if (!(cj->hydro.sorted & (1 << sid)) || + cj->hydro.dx_max_sort_old > cj->dmin * space_maxreldx) error( - "Interacting unsorted cell. cj->dx_max_sort_old=%e cj->dmin=%e " + "Interacting unsorted cell. cj->hydro.dx_max_sort_old=%e cj->dmin=%e " "cj->sorted=%d sid=%d", - cj->dx_max_sort_old, cj->dmin, cj->sorted, sid); + cj->hydro.dx_max_sort_old, cj->dmin, cj->hydro.sorted, sid); /* Compute the interactions. */ DOPAIR1_BRANCH(r, ci, cj); @@ -2327,7 +2374,7 @@ void DOSUB_SELF1(struct runner *r, struct cell *ci, int gettimer) { TIMER_TIC; /* Should we even bother? */ - if (ci->count == 0 || !cell_is_active_hydro(ci, r->e)) return; + if (ci->hydro.count == 0 || !cell_is_active_hydro(ci, r->e)) return; /* Recurse? */ if (cell_can_recurse_in_self_hydro_task(ci)) { @@ -2376,7 +2423,7 @@ void DOSUB_PAIR2(struct runner *r, struct cell *ci, struct cell *cj, int sid, /* Should we even bother? */ if (!cell_is_active_hydro(ci, e) && !cell_is_active_hydro(cj, e)) return; - if (ci->count == 0 || cj->count == 0) return; + if (ci->hydro.count == 0 || cj->hydro.count == 0) return; /* Get the type of pair if not specified explicitly. */ double shift[3]; @@ -2592,18 +2639,18 @@ void DOSUB_PAIR2(struct runner *r, struct cell *ci, struct cell *cj, int sid, error("Interacting undrifted cells."); /* Do any of the cells need to be sorted first? */ - if (!(ci->sorted & (1 << sid)) || - ci->dx_max_sort_old > ci->dmin * space_maxreldx) + if (!(ci->hydro.sorted & (1 << sid)) || + ci->hydro.dx_max_sort_old > ci->dmin * space_maxreldx) error( - "Interacting unsorted cell. ci->dx_max_sort_old=%e ci->dmin=%e " + "Interacting unsorted cell. ci->hydro.dx_max_sort_old=%e ci->dmin=%e " "ci->sorted=%d sid=%d", - ci->dx_max_sort_old, ci->dmin, ci->sorted, sid); - if (!(cj->sorted & (1 << sid)) || - cj->dx_max_sort_old > cj->dmin * space_maxreldx) + ci->hydro.dx_max_sort_old, ci->dmin, ci->hydro.sorted, sid); + if (!(cj->hydro.sorted & (1 << sid)) || + cj->hydro.dx_max_sort_old > cj->dmin * space_maxreldx) error( - "Interacting unsorted cell. cj->dx_max_sort_old=%e cj->dmin=%e " + "Interacting unsorted cell. cj->hydro.dx_max_sort_old=%e cj->dmin=%e " "cj->sorted=%d sid=%d", - cj->dx_max_sort_old, cj->dmin, cj->sorted, sid); + cj->hydro.dx_max_sort_old, cj->dmin, cj->hydro.sorted, sid); /* Compute the interactions. */ DOPAIR2_BRANCH(r, ci, cj); @@ -2624,7 +2671,7 @@ void DOSUB_SELF2(struct runner *r, struct cell *ci, int gettimer) { TIMER_TIC; /* Should we even bother? */ - if (ci->count == 0 || !cell_is_active_hydro(ci, r->e)) return; + if (ci->hydro.count == 0 || !cell_is_active_hydro(ci, r->e)) return; /* Recurse? */ if (cell_can_recurse_in_self_hydro_task(ci)) { @@ -2659,15 +2706,16 @@ void DOSUB_SUBSET(struct runner *r, struct cell *ci, struct part *parts, if (!cell_is_active_hydro(ci, e) && (cj == NULL || !cell_is_active_hydro(cj, e))) return; - if (ci->count == 0 || (cj != NULL && cj->count == 0)) return; + if (ci->hydro.count == 0 || (cj != NULL && cj->hydro.count == 0)) return; /* Find out in which sub-cell of ci the parts are. */ struct cell *sub = NULL; if (ci->split) { for (int k = 0; k < 8; k++) { if (ci->progeny[k] != NULL) { - if (&parts[ind[0]] >= &ci->progeny[k]->parts[0] && - &parts[ind[0]] < &ci->progeny[k]->parts[ci->progeny[k]->count]) { + if (&parts[ind[0]] >= &ci->progeny[k]->hydro.parts[0] && + &parts[ind[0]] < + &ci->progeny[k]->hydro.parts[ci->progeny[k]->hydro.count]) { sub = ci->progeny[k]; break; } diff --git a/src/runner_doiact_grav.h b/src/runner_doiact_grav.h index 26e3cfdca0dc37449c90e1c85fa9fb0597ff68a8..1e15df821e7068458203b55a147694deee8510a9 100644 --- a/src/runner_doiact_grav.h +++ b/src/runner_doiact_grav.h @@ -48,8 +48,9 @@ static INLINE void runner_do_grav_down(struct runner *r, struct cell *c, TIMER_TIC; #ifdef SWIFT_DEBUG_CHECKS - if (c->ti_old_multipole != e->ti_current) error("c->multipole not drifted."); - if (c->multipole->pot.ti_init != e->ti_current) + if (c->grav.ti_old_multipole != e->ti_current) + error("c->multipole not drifted."); + if (c->grav.multipole->pot.ti_init != e->ti_current) error("c->field tensor not initialised"); #endif @@ -65,22 +66,22 @@ static INLINE void runner_do_grav_down(struct runner *r, struct cell *c, if (cp != NULL && cell_is_active_gravity(cp, e)) { #ifdef SWIFT_DEBUG_CHECKS - if (cp->ti_old_multipole != e->ti_current) + if (cp->grav.ti_old_multipole != e->ti_current) error("cp->multipole not drifted."); - if (cp->multipole->pot.ti_init != e->ti_current) + if (cp->grav.multipole->pot.ti_init != e->ti_current) error("cp->field tensor not initialised"); #endif /* If the tensor received any contribution, push it down */ - if (c->multipole->pot.interacted) { + if (c->grav.multipole->pot.interacted) { struct grav_tensor shifted_tensor; /* Shift the field tensor */ - gravity_L2L(&shifted_tensor, &c->multipole->pot, cp->multipole->CoM, - c->multipole->CoM); + gravity_L2L(&shifted_tensor, &c->grav.multipole->pot, + cp->grav.multipole->CoM, c->grav.multipole->CoM); /* Add it to this level's tensor */ - gravity_field_tensors_add(&cp->multipole->pot, &shifted_tensor); + gravity_field_tensors_add(&cp->grav.multipole->pot, &shifted_tensor); } /* Recurse */ @@ -93,16 +94,16 @@ static INLINE void runner_do_grav_down(struct runner *r, struct cell *c, /* Leaf case */ /* We can abort early if no interactions via multipole happened */ - if (!c->multipole->pot.interacted) return; + if (!c->grav.multipole->pot.interacted) return; if (!cell_are_gpart_drifted(c, e)) error("Un-drifted gparts"); /* Cell properties */ - struct gpart *gparts = c->gparts; - const int gcount = c->gcount; - const struct grav_tensor *pot = &c->multipole->pot; - const double CoM[3] = {c->multipole->CoM[0], c->multipole->CoM[1], - c->multipole->CoM[2]}; + struct gpart *gparts = c->grav.parts; + const int gcount = c->grav.count; + const struct grav_tensor *pot = &c->grav.multipole->pot; + const double CoM[3] = {c->grav.multipole->CoM[0], c->grav.multipole->CoM[1], + c->grav.multipole->CoM[2]}; /* Apply accelerations to the particles */ for (int i = 0; i < gcount; ++i) { @@ -117,9 +118,12 @@ static INLINE void runner_do_grav_down(struct runner *r, struct cell *c, /* Check that particles have been drifted to the current time */ if (gp->ti_drift != e->ti_current) error("gpart not drifted to current time"); - if (c->multipole->pot.ti_init != e->ti_current) + if (c->grav.multipole->pot.ti_init != e->ti_current) error("c->field tensor not initialised"); + /* Check that we are not updated an inhibited particle */ + if (gpart_is_inhibited(gp, e)) error("Updating an inhibited particle!"); + /* Check that the particle was initialised */ if (gp->initialised == 0) error("Adding forces to an un-initialised gpart."); @@ -225,9 +229,19 @@ static INLINE void runner_dopair_grav_pp_full( /* Check that particles have been drifted to the current time */ if (gparts_i[pid].ti_drift != e->ti_current) error("gpi not drifted to current time"); - if (pjd < gcount_j && gparts_j[pjd].ti_drift != e->ti_current) + if (pjd < gcount_j && gparts_j[pjd].ti_drift != e->ti_current && + !gpart_is_inhibited(&gparts_j[pjd], e)) error("gpj not drifted to current time"); + /* Check that we are not updated an inhibited particle */ + if (gpart_is_inhibited(&gparts_i[pid], e)) + error("Updating an inhibited particle!"); + + /* Check that the particle we interact with was not inhibited */ + if (pjd < gcount_j && gpart_is_inhibited(&gparts_j[pjd], e) && + mass_j != 0.f) + error("Inhibited particle used as gravity source."); + /* Check that the particle was initialised */ if (gparts_i[pid].initialised == 0) error("Adding forces to an un-initialised gpart."); @@ -246,7 +260,8 @@ static INLINE void runner_dopair_grav_pp_full( #ifdef SWIFT_DEBUG_CHECKS /* Update the interaction counter if it's not a padded gpart */ - if (pjd < gcount_j) gparts_i[pid].num_interacted++; + if (pjd < gcount_j && !gpart_is_inhibited(&gparts_j[pjd], e)) + gparts_i[pid].num_interacted++; #endif } @@ -355,9 +370,19 @@ static INLINE void runner_dopair_grav_pp_truncated( /* Check that particles have been drifted to the current time */ if (gparts_i[pid].ti_drift != e->ti_current) error("gpi not drifted to current time"); - if (pjd < gcount_j && gparts_j[pjd].ti_drift != e->ti_current) + if (pjd < gcount_j && gparts_j[pjd].ti_drift != e->ti_current && + !gpart_is_inhibited(&gparts_j[pjd], e)) error("gpj not drifted to current time"); + /* Check that we are not updated an inhibited particle */ + if (gpart_is_inhibited(&gparts_i[pid], e)) + error("Updating an inhibited particle!"); + + /* Check that the particle we interact with was not inhibited */ + if (pjd < gcount_j && gpart_is_inhibited(&gparts_j[pjd], e) && + mass_j != 0.f) + error("Inhibited particle used as gravity source."); + /* Check that the particle was initialised */ if (gparts_i[pid].initialised == 0) error("Adding forces to an un-initialised gpart."); @@ -376,7 +401,8 @@ static INLINE void runner_dopair_grav_pp_truncated( #ifdef SWIFT_DEBUG_CHECKS /* Update the interaction counter if it's not a padded gpart */ - if (pjd < gcount_j) gparts_i[pid].num_interacted++; + if (pjd < gcount_j && !gpart_is_inhibited(&gparts_j[pjd], e)) + gparts_i[pid].num_interacted++; #endif } @@ -449,6 +475,10 @@ static INLINE void runner_dopair_grav_pm_full( if (gparts_i[pid].ti_drift != e->ti_current) error("gpi not drifted to current time"); + /* Check that we are not updated an inhibited particle */ + if (gpart_is_inhibited(&gparts_i[pid], e)) + error("Updating an inhibited particle!"); + /* Check that the particle was initialised */ if (gparts_i[pid].initialised == 0) error("Adding forces to an un-initialised gpart."); @@ -479,7 +509,7 @@ static INLINE void runner_dopair_grav_pm_full( const float r2 = dx * dx + dy * dy + dz * dz; #ifdef SWIFT_DEBUG_CHECKS - const float r_max_j = cj->multipole->r_max; + const float r_max_j = cj->grav.multipole->r_max; const float r_max2 = r_max_j * r_max_j; const float theta_crit2 = e->gravity_properties->theta_crit2; @@ -505,7 +535,7 @@ static INLINE void runner_dopair_grav_pm_full( #ifdef SWIFT_DEBUG_CHECKS /* Update the interaction counter */ if (pid < gcount_i) - gparts_i[pid].num_interacted += cj->multipole->m_pole.num_gpart; + gparts_i[pid].num_interacted += cj->grav.multipole->m_pole.num_gpart; #endif } } @@ -578,6 +608,10 @@ static INLINE void runner_dopair_grav_pm_truncated( if (gparts_i[pid].ti_drift != e->ti_current) error("gpi not drifted to current time"); + /* Check that we are not updated an inhibited particle */ + if (gpart_is_inhibited(&gparts_i[pid], e)) + error("Updating an inhibited particle!"); + /* Check that the particle was initialised */ if (gparts_i[pid].initialised == 0) error("Adding forces to an un-initialised gpart."); @@ -606,7 +640,7 @@ static INLINE void runner_dopair_grav_pm_truncated( const float r2 = dx * dx + dy * dy + dz * dz; #ifdef SWIFT_DEBUG_CHECKS - const float r_max_j = cj->multipole->r_max; + const float r_max_j = cj->grav.multipole->r_max; const float r_max2 = r_max_j * r_max_j; const float theta_crit2 = e->gravity_properties->theta_crit2; @@ -632,7 +666,7 @@ static INLINE void runner_dopair_grav_pm_truncated( #ifdef SWIFT_DEBUG_CHECKS /* Update the interaction counter */ if (pid < gcount_i) - gparts_i[pid].num_interacted += cj->multipole->m_pole.num_gpart; + gparts_i[pid].num_interacted += cj->grav.multipole->m_pole.num_gpart; #endif } } @@ -685,9 +719,9 @@ static INLINE void runner_dopair_grav_pp(struct runner *r, struct cell *ci, /* Let's start by checking things are drifted */ if (!cell_are_gpart_drifted(ci, e)) error("Un-drifted gparts"); if (!cell_are_gpart_drifted(cj, e)) error("Un-drifted gparts"); - if (cj_active && ci->ti_old_multipole != e->ti_current) + if (cj_active && ci->grav.ti_old_multipole != e->ti_current) error("Un-drifted multipole"); - if (ci_active && cj->ti_old_multipole != e->ti_current) + if (ci_active && cj->grav.ti_old_multipole != e->ti_current) error("Un-drifted multipole"); /* Caches to play with */ @@ -699,24 +733,24 @@ static INLINE void runner_dopair_grav_pp(struct runner *r, struct cell *ci, const double shift_j[3] = {0., 0., 0.}; /* Recover the multipole info and shift the CoM locations */ - const float rmax_i = ci->multipole->r_max; - const float rmax_j = cj->multipole->r_max; + const float rmax_i = ci->grav.multipole->r_max; + const float rmax_j = cj->grav.multipole->r_max; const float rmax2_i = rmax_i * rmax_i; const float rmax2_j = rmax_j * rmax_j; - const struct multipole *multi_i = &ci->multipole->m_pole; - const struct multipole *multi_j = &cj->multipole->m_pole; - const float CoM_i[3] = {(float)(ci->multipole->CoM[0] - shift_i[0]), - (float)(ci->multipole->CoM[1] - shift_i[1]), - (float)(ci->multipole->CoM[2] - shift_i[2])}; - const float CoM_j[3] = {(float)(cj->multipole->CoM[0] - shift_j[0]), - (float)(cj->multipole->CoM[1] - shift_j[1]), - (float)(cj->multipole->CoM[2] - shift_j[2])}; + const struct multipole *multi_i = &ci->grav.multipole->m_pole; + const struct multipole *multi_j = &cj->grav.multipole->m_pole; + const float CoM_i[3] = {(float)(ci->grav.multipole->CoM[0] - shift_i[0]), + (float)(ci->grav.multipole->CoM[1] - shift_i[1]), + (float)(ci->grav.multipole->CoM[2] - shift_i[2])}; + const float CoM_j[3] = {(float)(cj->grav.multipole->CoM[0] - shift_j[0]), + (float)(cj->grav.multipole->CoM[1] - shift_j[1]), + (float)(cj->grav.multipole->CoM[2] - shift_j[2])}; /* Start by constructing particle caches */ /* Computed the padded counts */ - const int gcount_i = ci->gcount; - const int gcount_j = cj->gcount; + const int gcount_i = ci->grav.count; + const int gcount_j = cj->grav.count; const int gcount_padded_i = gcount_i - (gcount_i % VEC_SIZE) + VEC_SIZE; const int gcount_padded_j = gcount_j - (gcount_j % VEC_SIZE) + VEC_SIZE; @@ -729,10 +763,10 @@ static INLINE void runner_dopair_grav_pp(struct runner *r, struct cell *ci, /* Fill the caches */ gravity_cache_populate(e->max_active_bin, allow_mpole, periodic, dim, - ci_cache, ci->gparts, gcount_i, gcount_padded_i, + ci_cache, ci->grav.parts, gcount_i, gcount_padded_i, shift_i, CoM_j, rmax2_j, ci, e->gravity_properties); gravity_cache_populate(e->max_active_bin, allow_mpole, periodic, dim, - cj_cache, cj->gparts, gcount_j, gcount_padded_j, + cj_cache, cj->grav.parts, gcount_j, gcount_padded_j, shift_j, CoM_i, rmax2_i, cj, e->gravity_properties); /* Can we use the Newtonian version or do we need the truncated one ? */ @@ -745,25 +779,27 @@ static INLINE void runner_dopair_grav_pp(struct runner *r, struct cell *ci, /* First the P2P */ runner_dopair_grav_pp_full(ci_cache, cj_cache, gcount_i, gcount_j, - gcount_padded_j, periodic, dim, e, ci->gparts, - cj->gparts); + gcount_padded_j, periodic, dim, e, + ci->grav.parts, cj->grav.parts); /* Then the M2P */ if (allow_mpole) runner_dopair_grav_pm_full(ci_cache, gcount_padded_i, CoM_j, multi_j, - periodic, dim, e, ci->gparts, gcount_i, cj); + periodic, dim, e, ci->grav.parts, gcount_i, + cj); } if (cj_active && symmetric) { /* First the P2P */ runner_dopair_grav_pp_full(cj_cache, ci_cache, gcount_j, gcount_i, - gcount_padded_i, periodic, dim, e, cj->gparts, - ci->gparts); + gcount_padded_i, periodic, dim, e, + cj->grav.parts, ci->grav.parts); /* Then the M2P */ if (allow_mpole) runner_dopair_grav_pm_full(cj_cache, gcount_padded_j, CoM_i, multi_i, - periodic, dim, e, cj->gparts, gcount_j, ci); + periodic, dim, e, cj->grav.parts, gcount_j, + ci); } } else { /* Periodic BC */ @@ -787,26 +823,26 @@ static INLINE void runner_dopair_grav_pp(struct runner *r, struct cell *ci, /* First the (truncated) P2P */ runner_dopair_grav_pp_truncated(ci_cache, cj_cache, gcount_i, gcount_j, gcount_padded_j, dim, r_s_inv, e, - ci->gparts, cj->gparts); + ci->grav.parts, cj->grav.parts); /* Then the M2P */ if (allow_mpole) runner_dopair_grav_pm_truncated(ci_cache, gcount_padded_i, CoM_j, - multi_j, dim, r_s_inv, e, ci->gparts, - gcount_i, cj); + multi_j, dim, r_s_inv, e, + ci->grav.parts, gcount_i, cj); } if (cj_active && symmetric) { /* First the (truncated) P2P */ runner_dopair_grav_pp_truncated(cj_cache, ci_cache, gcount_j, gcount_i, gcount_padded_i, dim, r_s_inv, e, - cj->gparts, ci->gparts); + cj->grav.parts, ci->grav.parts); /* Then the M2P */ if (allow_mpole) runner_dopair_grav_pm_truncated(cj_cache, gcount_padded_j, CoM_i, - multi_i, dim, r_s_inv, e, cj->gparts, - gcount_j, ci); + multi_i, dim, r_s_inv, e, + cj->grav.parts, gcount_j, ci); } } else { @@ -819,12 +855,12 @@ static INLINE void runner_dopair_grav_pp(struct runner *r, struct cell *ci, /* First the (Newtonian) P2P */ runner_dopair_grav_pp_full(ci_cache, cj_cache, gcount_i, gcount_j, gcount_padded_j, periodic, dim, e, - ci->gparts, cj->gparts); + ci->grav.parts, cj->grav.parts); /* Then the M2P */ if (allow_mpole) runner_dopair_grav_pm_full(ci_cache, gcount_padded_i, CoM_j, multi_j, - periodic, dim, e, ci->gparts, gcount_i, + periodic, dim, e, ci->grav.parts, gcount_i, cj); } if (cj_active && symmetric) { @@ -832,21 +868,21 @@ static INLINE void runner_dopair_grav_pp(struct runner *r, struct cell *ci, /* First the (Newtonian) P2P */ runner_dopair_grav_pp_full(cj_cache, ci_cache, gcount_j, gcount_i, gcount_padded_i, periodic, dim, e, - cj->gparts, ci->gparts); + cj->grav.parts, ci->grav.parts); /* Then the M2P */ if (allow_mpole) runner_dopair_grav_pm_full(cj_cache, gcount_padded_j, CoM_i, multi_i, - periodic, dim, e, cj->gparts, gcount_j, + periodic, dim, e, cj->grav.parts, gcount_j, ci); } } } /* Write back to the particles */ - if (ci_active) gravity_cache_write_back(ci_cache, ci->gparts, gcount_i); + if (ci_active) gravity_cache_write_back(ci_cache, ci->grav.parts, gcount_i); if (cj_active && symmetric) - gravity_cache_write_back(cj_cache, cj->gparts, gcount_j); + gravity_cache_write_back(cj_cache, cj->grav.parts, gcount_j); TIMER_TOC(timer_dopair_grav_pp); } @@ -922,9 +958,18 @@ static INLINE void runner_doself_grav_pp_full( /* Check that particles have been drifted to the current time */ if (gparts[pid].ti_drift != e->ti_current) error("gpi not drifted to current time"); - if (pjd < gcount && gparts[pjd].ti_drift != e->ti_current) + if (pjd < gcount && gparts[pjd].ti_drift != e->ti_current && + !gpart_is_inhibited(&gparts[pjd], e)) error("gpj not drifted to current time"); + /* Check that we are not updated an inhibited particle */ + if (gpart_is_inhibited(&gparts[pid], e)) + error("Updating an inhibited particle!"); + + /* Check that the particle we interact with was not inhibited */ + if (pjd < gcount && gpart_is_inhibited(&gparts[pjd], e) && mass_j != 0.f) + error("Inhibited particle used as gravity source."); + /* Check that the particle was initialised */ if (gparts[pid].initialised == 0) error("Adding forces to an un-initialised gpart."); @@ -943,7 +988,8 @@ static INLINE void runner_doself_grav_pp_full( #ifdef SWIFT_DEBUG_CHECKS /* Update the interaction counter if it's not a padded gpart */ - if (pjd < gcount) gparts[pid].num_interacted++; + if (pjd < gcount && !gpart_is_inhibited(&gparts[pjd], e)) + gparts[pid].num_interacted++; #endif } @@ -1036,9 +1082,18 @@ static INLINE void runner_doself_grav_pp_truncated( /* Check that particles have been drifted to the current time */ if (gparts[pid].ti_drift != e->ti_current) error("gpi not drifted to current time"); - if (pjd < gcount && gparts[pjd].ti_drift != e->ti_current) + if (pjd < gcount && gparts[pjd].ti_drift != e->ti_current && + !gpart_is_inhibited(&gparts[pjd], e)) error("gpj not drifted to current time"); + /* Check that we are not updated an inhibited particle */ + if (gpart_is_inhibited(&gparts[pid], e)) + error("Updating an inhibited particle!"); + + /* Check that the particle we interact with was not inhibited */ + if (pjd < gcount && gpart_is_inhibited(&gparts[pjd], e) && mass_j != 0.f) + error("Inhibited particle used as gravity source."); + /* Check that the particle was initialised */ if (gparts[pid].initialised == 0) error("Adding forces to an un-initialised gpart."); @@ -1057,7 +1112,8 @@ static INLINE void runner_doself_grav_pp_truncated( #ifdef SWIFT_DEBUG_CHECKS /* Update the interaction counter if it's not a padded gpart */ - if (pjd < gcount) gparts[pid].num_interacted++; + if (pjd < gcount && !gpart_is_inhibited(&gparts[pjd], e)) + gparts[pid].num_interacted++; #endif } @@ -1094,7 +1150,7 @@ static INLINE void runner_doself_grav_pp(struct runner *r, struct cell *c) { TIMER_TIC; #ifdef SWIFT_DEBUG_CHECKS - if (c->gcount == 0) error("Doing self gravity on an empty cell !"); + if (c->grav.count == 0) error("Doing self gravity on an empty cell !"); #endif /* Anything to do here? */ @@ -1115,7 +1171,7 @@ static INLINE void runner_doself_grav_pp(struct runner *r, struct cell *c) { c->loc[2] + 0.5 * c->width[2]}; /* Computed the padded counts */ - const int gcount = c->gcount; + const int gcount = c->grav.count; const int gcount_padded = gcount - (gcount % VEC_SIZE) + VEC_SIZE; #ifdef SWIFT_DEBUG_CHECKS @@ -1125,7 +1181,7 @@ static INLINE void runner_doself_grav_pp(struct runner *r, struct cell *c) { #endif /* Fill the cache */ - gravity_cache_populate_no_mpole(e->max_active_bin, ci_cache, c->gparts, + gravity_cache_populate_no_mpole(e->max_active_bin, ci_cache, c->grav.parts, gcount, gcount_padded, loc, c, e->gravity_properties); @@ -1133,29 +1189,31 @@ static INLINE void runner_doself_grav_pp(struct runner *r, struct cell *c) { if (!periodic) { /* Not periodic -> Can always use Newtonian potential */ - runner_doself_grav_pp_full(ci_cache, gcount, gcount_padded, e, c->gparts); + runner_doself_grav_pp_full(ci_cache, gcount, gcount_padded, e, + c->grav.parts); } else { /* Get the maximal distance between any two particles */ - const double max_r = 2. * c->multipole->r_max; + const double max_r = 2. * c->grav.multipole->r_max; /* Do we need to use the truncated interactions ? */ if (max_r > min_trunc) { /* Periodic but far-away cells must use the truncated potential */ runner_doself_grav_pp_truncated(ci_cache, gcount, gcount_padded, r_s_inv, - e, c->gparts); + e, c->grav.parts); } else { /* Periodic but close-by cells can use the full Newtonian potential */ - runner_doself_grav_pp_full(ci_cache, gcount, gcount_padded, e, c->gparts); + runner_doself_grav_pp_full(ci_cache, gcount, gcount_padded, e, + c->grav.parts); } } /* Write back to the particles */ - gravity_cache_write_back(ci_cache, c->gparts, gcount); + gravity_cache_write_back(ci_cache, c->grav.parts, gcount); TIMER_TOC(timer_doself_grav_pp); } @@ -1187,8 +1245,8 @@ static INLINE void runner_dopair_grav_mm_symmetric(struct runner *r, error("Invalid state in symmetric M-M calculation!"); /* Short-cut to the multipole */ - const struct multipole *multi_i = &ci->multipole->m_pole; - const struct multipole *multi_j = &cj->multipole->m_pole; + const struct multipole *multi_i = &ci->grav.multipole->m_pole; + const struct multipole *multi_j = &cj->grav.multipole->m_pole; #ifdef SWIFT_DEBUG_CHECKS if (ci == cj) error("Interacting a cell with itself using M2L"); @@ -1199,29 +1257,29 @@ static INLINE void runner_dopair_grav_mm_symmetric(struct runner *r, if (multi_j->num_gpart == 0) error("Multipole j does not seem to have been set."); - if (ci->multipole->pot.ti_init != e->ti_current) + if (ci->grav.multipole->pot.ti_init != e->ti_current) error("ci->grav tensor not initialised."); - if (ci->multipole->pot.ti_init != e->ti_current) + if (ci->grav.multipole->pot.ti_init != e->ti_current) error("cj->grav tensor not initialised."); - if (ci->ti_old_multipole != e->ti_current) + if (ci->grav.ti_old_multipole != e->ti_current) error( - "Undrifted multipole ci->ti_old_multipole=%lld ci->nodeID=%d " + "Undrifted multipole ci->grav.ti_old_multipole=%lld ci->nodeID=%d " "cj->nodeID=%d e->ti_current=%lld", - ci->ti_old_multipole, ci->nodeID, cj->nodeID, e->ti_current); + ci->grav.ti_old_multipole, ci->nodeID, cj->nodeID, e->ti_current); - if (cj->ti_old_multipole != e->ti_current) + if (cj->grav.ti_old_multipole != e->ti_current) error( - "Undrifted multipole cj->ti_old_multipole=%lld cj->nodeID=%d " + "Undrifted multipole cj->grav.ti_old_multipole=%lld cj->nodeID=%d " "ci->nodeID=%d e->ti_current=%lld", - cj->ti_old_multipole, cj->nodeID, ci->nodeID, e->ti_current); + cj->grav.ti_old_multipole, cj->nodeID, ci->nodeID, e->ti_current); #endif /* Let's interact at this level */ - gravity_M2L_symmetric(&ci->multipole->pot, &cj->multipole->pot, multi_i, - multi_j, ci->multipole->CoM, cj->multipole->CoM, props, - periodic, dim, r_s_inv); + gravity_M2L_symmetric(&ci->grav.multipole->pot, &cj->grav.multipole->pot, + multi_i, multi_j, ci->grav.multipole->CoM, + cj->grav.multipole->CoM, props, periodic, dim, r_s_inv); TIMER_TOC(timer_dopair_grav_mm); } @@ -1251,7 +1309,7 @@ static INLINE void runner_dopair_grav_mm_nonsym( if (!cell_is_active_gravity_mm(ci, e) || ci->nodeID != engine_rank) return; /* Short-cut to the multipole */ - const struct multipole *multi_j = &cj->multipole->m_pole; + const struct multipole *multi_j = &cj->grav.multipole->m_pole; #ifdef SWIFT_DEBUG_CHECKS if (ci == cj) error("Interacting a cell with itself using M2L"); @@ -1259,19 +1317,19 @@ static INLINE void runner_dopair_grav_mm_nonsym( if (multi_j->num_gpart == 0) error("Multipole does not seem to have been set."); - if (ci->multipole->pot.ti_init != e->ti_current) + if (ci->grav.multipole->pot.ti_init != e->ti_current) error("ci->grav tensor not initialised."); - if (cj->ti_old_multipole != e->ti_current) + if (cj->grav.ti_old_multipole != e->ti_current) error( - "Undrifted multipole cj->ti_old_multipole=%lld cj->nodeID=%d " + "Undrifted multipole cj->grav.ti_old_multipole=%lld cj->nodeID=%d " "ci->nodeID=%d e->ti_current=%lld", - cj->ti_old_multipole, cj->nodeID, ci->nodeID, e->ti_current); + cj->grav.ti_old_multipole, cj->nodeID, ci->nodeID, e->ti_current); #endif /* Let's interact at this level */ - gravity_M2L_nonsym(&ci->multipole->pot, multi_j, ci->multipole->CoM, - cj->multipole->CoM, props, periodic, dim, r_s_inv); + gravity_M2L_nonsym(&ci->grav.multipole->pot, multi_j, ci->grav.multipole->CoM, + cj->grav.multipole->CoM, props, periodic, dim, r_s_inv); TIMER_TOC(timer_dopair_grav_mm); } @@ -1296,8 +1354,8 @@ static INLINE void runner_dopair_grav_mm(struct runner *r, cell_is_active_gravity_mm(cj, e) && (cj->nodeID == e->nodeID); /* Do we need drifting first? */ - if (ci->ti_old_multipole < e->ti_current) cell_drift_multipole(ci, e); - if (cj->ti_old_multipole < e->ti_current) cell_drift_multipole(cj, e); + if (ci->grav.ti_old_multipole < e->ti_current) cell_drift_multipole(ci, e); + if (cj->grav.ti_old_multipole < e->ti_current) cell_drift_multipole(cj, e); /* Interact! */ if (do_i && do_j) @@ -1335,7 +1393,7 @@ static INLINE void runner_dopair_grav_mm_progenies(struct runner *r, const int flag = i * 8 + j; /* Did we agree to use an M-M interaction here at the last rebuild? */ - if (flags & (1LL << flag)) runner_dopair_grav_mm(r, cpi, cpj); + if (flags & (1ULL << flag)) runner_dopair_grav_mm(r, cpi, cpj); } } } @@ -1356,14 +1414,14 @@ static INLINE void runner_dopair_recursive_grav_pm(struct runner *r, #ifdef SWIFT_DEBUG_CHECKS /* Early abort? */ - if (ci->gcount == 0 || cj->gcount == 0) + if (ci->grav.count == 0 || cj->grav.count == 0) error("Doing pair gravity on an empty cell !"); /* Sanity check */ if (ci == cj) error("Pair interaction between a cell and itself."); - if (cj->ti_old_multipole != e->ti_current) - error("cj->multipole not drifted."); + if (cj->grav.ti_old_multipole != e->ti_current) + error("cj->grav.multipole not drifted."); #endif /* Can we recurse further? */ @@ -1384,7 +1442,7 @@ static INLINE void runner_dopair_recursive_grav_pm(struct runner *r, struct gravity_cache *const ci_cache = &r->ci_gravity_cache; /* Computed the padded counts */ - const int gcount_i = ci->gcount; + const int gcount_i = ci->grav.count; const int gcount_padded_i = gcount_i - (gcount_i % VEC_SIZE) + VEC_SIZE; #ifdef SWIFT_DEBUG_CHECKS @@ -1394,32 +1452,33 @@ static INLINE void runner_dopair_recursive_grav_pm(struct runner *r, #endif /* Recover the multipole info and the CoM locations */ - const struct multipole *multi_j = &cj->multipole->m_pole; - const float r_max = cj->multipole->r_max; - const float CoM_j[3] = {(float)(cj->multipole->CoM[0]), - (float)(cj->multipole->CoM[1]), - (float)(cj->multipole->CoM[2])}; + const struct multipole *multi_j = &cj->grav.multipole->m_pole; + const float r_max = cj->grav.multipole->r_max; + const float CoM_j[3] = {(float)(cj->grav.multipole->CoM[0]), + (float)(cj->grav.multipole->CoM[1]), + (float)(cj->grav.multipole->CoM[2])}; /* Fill the cache */ gravity_cache_populate_all_mpole( - e->max_active_bin, periodic, dim, ci_cache, ci->gparts, gcount_i, + e->max_active_bin, periodic, dim, ci_cache, ci->grav.parts, gcount_i, gcount_padded_i, ci, CoM_j, r_max * r_max, e->gravity_properties); /* Can we use the Newtonian version or do we need the truncated one ? */ if (!periodic) { runner_dopair_grav_pm_full(ci_cache, gcount_padded_i, CoM_j, multi_j, - periodic, dim, e, ci->gparts, gcount_i, cj); + periodic, dim, e, ci->grav.parts, gcount_i, + cj); } else { runner_dopair_grav_pm_truncated(ci_cache, gcount_padded_i, CoM_j, multi_j, - dim, r_s_inv, e, ci->gparts, gcount_i, + dim, r_s_inv, e, ci->grav.parts, gcount_i, cj); } /* Write back to the particles */ - gravity_cache_write_back(ci_cache, ci->gparts, gcount_i); + gravity_cache_write_back(ci_cache, ci->grav.parts, gcount_i); } } @@ -1457,8 +1516,8 @@ static INLINE void runner_dopair_recursive_grav(struct runner *r, #ifdef SWIFT_DEBUG_CHECKS - const int gcount_i = ci->gcount; - const int gcount_j = cj->gcount; + const int gcount_i = ci->grav.count; + const int gcount_j = cj->grav.count; /* Early abort? */ if (gcount_i == 0 || gcount_j == 0) @@ -1467,17 +1526,19 @@ static INLINE void runner_dopair_recursive_grav(struct runner *r, /* Sanity check */ if (ci == cj) error("Pair interaction between a cell and itself."); - if (cell_is_active_gravity(ci, e) && ci->ti_old_multipole != e->ti_current) - error("ci->multipole not drifted."); - if (cell_is_active_gravity(cj, e) && cj->ti_old_multipole != e->ti_current) - error("cj->multipole not drifted."); + if (cell_is_active_gravity(ci, e) && + ci->grav.ti_old_multipole != e->ti_current) + error("ci->grav.multipole not drifted."); + if (cell_is_active_gravity(cj, e) && + cj->grav.ti_old_multipole != e->ti_current) + error("cj->grav.multipole not drifted."); #endif TIMER_TIC; /* Recover the multipole information */ - struct gravity_tensors *const multi_i = ci->multipole; - struct gravity_tensors *const multi_j = cj->multipole; + struct gravity_tensors *const multi_i = ci->grav.multipole; + struct gravity_tensors *const multi_j = cj->grav.multipole; /* Get the distance between the CoMs */ double dx = multi_i->CoM[0] - multi_j->CoM[0]; @@ -1599,7 +1660,7 @@ static INLINE void runner_doself_recursive_grav(struct runner *r, #ifdef SWIFT_DEBUG_CHECKS /* Early abort? */ - if (c->gcount == 0) error("Doing self gravity on an empty cell !"); + if (c->grav.count == 0) error("Doing self gravity on an empty cell !"); #endif TIMER_TIC; @@ -1657,7 +1718,8 @@ static INLINE void runner_do_grav_long_range(struct runner *r, struct cell *ci, /* Recover the list of top-level cells */ struct cell *cells = e->s->cells_top; - const int nr_cells = e->s->nr_cells; + int *cells_with_particles = e->s->cells_with_particles_top; + const int nr_cells_with_particles = e->s->nr_cells_with_particles; /* Anything to do here? */ if (!cell_is_active_gravity(ci, e)) return; @@ -1666,28 +1728,28 @@ static INLINE void runner_do_grav_long_range(struct runner *r, struct cell *ci, error("Non-local cell in long-range gravity task!"); /* Check multipole has been drifted */ - if (ci->ti_old_multipole < e->ti_current) cell_drift_multipole(ci, e); + if (ci->grav.ti_old_multipole < e->ti_current) cell_drift_multipole(ci, e); /* Get this cell's multipole information */ - struct gravity_tensors *const multi_i = ci->multipole; + struct gravity_tensors *const multi_i = ci->grav.multipole; /* Find this cell's top-level (great-)parent */ struct cell *top = ci; while (top->parent != NULL) top = top->parent; /* Recover the top-level multipole (for distance checks) */ - struct gravity_tensors *const multi_top = top->multipole; + struct gravity_tensors *const multi_top = top->grav.multipole; const double CoM_rebuild_top[3] = {multi_top->CoM_rebuild[0], multi_top->CoM_rebuild[1], multi_top->CoM_rebuild[2]}; /* Loop over all the top-level cells and go for a M-M interaction if * well-separated */ - for (int n = 0; n < nr_cells; ++n) { + for (int n = 0; n < nr_cells_with_particles; ++n) { /* Handle on the top-level cell and it's gravity business*/ - struct cell *cj = &cells[n]; - const struct gravity_tensors *const multi_j = cj->multipole; + const struct cell *cj = &cells[cells_with_particles[n]]; + const struct gravity_tensors *const multi_j = cj->grav.multipole; /* Avoid self contributions */ if (top == cj) continue; diff --git a/src/runner_doiact_stars.h b/src/runner_doiact_stars.h index 7941fdc926e83e5a1806afa70fde9ad7e6c4a502..e696e4fd10853536008d9d9fafc90e6475fd291a 100644 --- a/src/runner_doiact_stars.h +++ b/src/runner_doiact_stars.h @@ -40,10 +40,10 @@ void runner_doself_stars_density(struct runner *r, struct cell *c, int timer) { const float a = cosmo->a; const float H = cosmo->H; - const int scount = c->scount; - const int count = c->count; - struct spart *restrict sparts = c->sparts; - struct part *restrict parts = c->parts; + const int scount = c->stars.count; + const int count = c->hydro.count; + struct spart *restrict sparts = c->stars.parts; + struct part *restrict parts = c->hydro.parts; /* Loop over the sparts in ci. */ for (int sid = 0; sid < scount; sid++) { @@ -101,10 +101,10 @@ void runner_dosubpair_stars_density(struct runner *r, struct cell *restrict ci, /* Anything to do here? */ if (!cell_is_active_stars(ci, e) && !cell_is_active_stars(cj, e)) return; - const int scount_i = ci->scount; - const int count_j = cj->count; - struct spart *restrict sparts_i = ci->sparts; - struct part *restrict parts_j = cj->parts; + const int scount_i = ci->stars.count; + const int count_j = cj->hydro.count; + struct spart *restrict sparts_i = ci->stars.parts; + struct part *restrict parts_j = cj->hydro.parts; /* Cosmological terms */ const float a = cosmo->a; @@ -194,8 +194,8 @@ void runner_dopair_subset_stars_density(struct runner *r, TIMER_TIC; - const int count_j = cj->count; - struct part *restrict parts_j = cj->parts; + const int count_j = cj->hydro.count; + struct part *restrict parts_j = cj->hydro.parts; /* Cosmological terms */ const float a = cosmo->a; @@ -269,8 +269,8 @@ void runner_doself_subset_stars_density(struct runner *r, const float a = cosmo->a; const float H = cosmo->H; - const int count_i = ci->count; - struct part *restrict parts_j = ci->parts; + const int count_i = ci->hydro.count; + struct part *restrict parts_j = ci->hydro.parts; /* Loop over the parts in ci. */ for (int spid = 0; spid < scount; spid++) { @@ -382,15 +382,16 @@ void runner_dosub_subset_stars_density(struct runner *r, struct cell *ci, if (!cell_is_active_stars(ci, e) && (cj == NULL || !cell_is_active_stars(cj, e))) return; - if (ci->scount == 0 || (cj != NULL && cj->scount == 0)) return; + if (ci->stars.count == 0 || (cj != NULL && cj->stars.count == 0)) return; /* Find out in which sub-cell of ci the parts are. */ struct cell *sub = NULL; if (ci->split) { for (int k = 0; k < 8; k++) { if (ci->progeny[k] != NULL) { - if (&sparts[ind[0]] >= &ci->progeny[k]->sparts[0] && - &sparts[ind[0]] < &ci->progeny[k]->sparts[ci->progeny[k]->scount]) { + if (&sparts[ind[0]] >= &ci->progeny[k]->stars.parts[0] && + &sparts[ind[0]] < + &ci->progeny[k]->stars.parts[ci->progeny[k]->stars.count]) { sub = ci->progeny[k]; break; } @@ -962,7 +963,7 @@ void runner_doself_branch_stars_density(struct runner *r, struct cell *c) { if (!cell_is_active_stars(c, e)) return; /* Did we mess up the recursion? */ - if (c->h_max_old * kernel_gamma > c->dmin) + if (c->stars.h_max_old * kernel_gamma > c->dmin) error("Cell smaller than smoothing length"); runner_doself_stars_density(r, c, 1); @@ -994,49 +995,51 @@ void runner_dopair_branch_stars_density(struct runner *r, struct cell *ci, const int sid = space_getsid(e->s, &ci, &cj, shift); /* Have the cells been sorted? */ - if (!(ci->sorted & (1 << sid)) || - ci->dx_max_sort_old > space_maxreldx * ci->dmin) + if (!(ci->hydro.sorted & (1 << sid)) || + ci->hydro.dx_max_sort_old > space_maxreldx * ci->dmin) error("Interacting unsorted cells."); - if (!(cj->sorted & (1 << sid)) || - cj->dx_max_sort_old > space_maxreldx * cj->dmin) + if (!(cj->hydro.sorted & (1 << sid)) || + cj->hydro.dx_max_sort_old > space_maxreldx * cj->dmin) error("Interacting unsorted cells."); #ifdef SWIFT_DEBUG_CHECKS /* Pick-out the sorted lists. */ - const struct entry *restrict sort_i = ci->sort[sid]; - const struct entry *restrict sort_j = cj->sort[sid]; + const struct entry *restrict sort_i = ci->hydro.sort[sid]; + const struct entry *restrict sort_j = cj->hydro.sort[sid]; /* Check that the dx_max_sort values in the cell are indeed an upper bound on particle movement. */ - for (int pid = 0; pid < ci->count; pid++) { - const struct part *p = &ci->parts[sort_i[pid].i]; + for (int pid = 0; pid < ci->hydro.count; pid++) { + const struct part *p = &ci->hydro.parts[sort_i[pid].i]; const float d = p->x[0] * runner_shift[sid][0] + p->x[1] * runner_shift[sid][1] + p->x[2] * runner_shift[sid][2]; - if (fabsf(d - sort_i[pid].d) - ci->dx_max_sort > - 1.0e-4 * max(fabsf(d), ci->dx_max_sort_old) && - fabsf(d - sort_i[pid].d) - ci->dx_max_sort > ci->width[0] * 1.0e-10) + if (fabsf(d - sort_i[pid].d) - ci->hydro.dx_max_sort > + 1.0e-4 * max(fabsf(d), ci->hydro.dx_max_sort_old) && + fabsf(d - sort_i[pid].d) - ci->hydro.dx_max_sort > + ci->width[0] * 1.0e-10) error( "particle shift diff exceeds dx_max_sort in cell ci. ci->nodeID=%d " - "cj->nodeID=%d d=%e sort_i[pid].d=%e ci->dx_max_sort=%e " - "ci->dx_max_sort_old=%e", - ci->nodeID, cj->nodeID, d, sort_i[pid].d, ci->dx_max_sort, - ci->dx_max_sort_old); + "cj->nodeID=%d d=%e sort_i[pid].d=%e ci->hydro.dx_max_sort=%e " + "ci->hydro.dx_max_sort_old=%e", + ci->nodeID, cj->nodeID, d, sort_i[pid].d, ci->hydro.dx_max_sort, + ci->hydro.dx_max_sort_old); } - for (int pjd = 0; pjd < cj->count; pjd++) { - const struct part *p = &cj->parts[sort_j[pjd].i]; + for (int pjd = 0; pjd < cj->hydro.count; pjd++) { + const struct part *p = &cj->hydro.parts[sort_j[pjd].i]; const float d = p->x[0] * runner_shift[sid][0] + p->x[1] * runner_shift[sid][1] + p->x[2] * runner_shift[sid][2]; - if ((fabsf(d - sort_j[pjd].d) - cj->dx_max_sort) > - 1.0e-4 * max(fabsf(d), cj->dx_max_sort_old) && - (fabsf(d - sort_j[pjd].d) - cj->dx_max_sort) > cj->width[0] * 1.0e-10) + if ((fabsf(d - sort_j[pjd].d) - cj->hydro.dx_max_sort) > + 1.0e-4 * max(fabsf(d), cj->hydro.dx_max_sort_old) && + (fabsf(d - sort_j[pjd].d) - cj->hydro.dx_max_sort) > + cj->width[0] * 1.0e-10) error( "particle shift diff exceeds dx_max_sort in cell cj. cj->nodeID=%d " - "ci->nodeID=%d d=%e sort_j[pjd].d=%e cj->dx_max_sort=%e " - "cj->dx_max_sort_old=%e", - cj->nodeID, ci->nodeID, d, sort_j[pjd].d, cj->dx_max_sort, - cj->dx_max_sort_old); + "ci->nodeID=%d d=%e sort_j[pjd].d=%e cj->hydro.dx_max_sort=%e " + "cj->hydro.dx_max_sort_old=%e", + cj->nodeID, ci->nodeID, d, sort_j[pjd].d, cj->hydro.dx_max_sort, + cj->hydro.dx_max_sort_old); } #endif /* SWIFT_DEBUG_CHECKS */ @@ -1065,7 +1068,7 @@ void runner_dosub_pair_stars_density(struct runner *r, struct cell *ci, /* Should we even bother? */ if (!cell_is_active_stars(ci, e) && !cell_is_active_stars(cj, e)) return; - if (ci->scount == 0 || cj->scount == 0) return; + if (ci->stars.count == 0 || cj->stars.count == 0) return; /* Get the type of pair if not specified explicitly. */ double shift[3]; @@ -1357,11 +1360,11 @@ void runner_dosub_pair_stars_density(struct runner *r, struct cell *ci, error("Interacting undrifted cells."); /* Do any of the cells need to be sorted first? */ - if (!(ci->sorted & (1 << sid)) || - ci->dx_max_sort_old > ci->dmin * space_maxreldx) + if (!(ci->hydro.sorted & (1 << sid)) || + ci->hydro.dx_max_sort_old > ci->dmin * space_maxreldx) error("Interacting unsorted cell."); - if (!(cj->sorted & (1 << sid)) || - cj->dx_max_sort_old > cj->dmin * space_maxreldx) + if (!(cj->hydro.sorted & (1 << sid)) || + cj->hydro.dx_max_sort_old > cj->dmin * space_maxreldx) error("Interacting unsorted cell."); /* Compute the interactions. */ @@ -1384,7 +1387,7 @@ void runner_dosub_self_stars_density(struct runner *r, struct cell *ci, TIMER_TIC; /* Should we even bother? */ - if (ci->scount == 0 || !cell_is_active_stars(ci, r->e)) return; + if (ci->stars.count == 0 || !cell_is_active_stars(ci, r->e)) return; /* Recurse? */ if (cell_can_recurse_in_self_stars_task(ci)) { diff --git a/src/runner_doiact_vec.c b/src/runner_doiact_vec.c index 2e86280d64491ee1750f41c2cd22ab01c08e30b8..c74fa7c8f53576f2e80578488fdf3378c59c0400 100644 --- a/src/runner_doiact_vec.c +++ b/src/runner_doiact_vec.c @@ -270,10 +270,10 @@ __attribute__((always_inline)) INLINE static void populate_max_index_density( int *max_index_i, int *max_index_j, int *init_pi, int *init_pj, const timebin_t max_active_bin, const int active_ci, const int active_cj) { - const struct part *restrict parts_i = ci->parts; - const struct part *restrict parts_j = cj->parts; + const struct part *restrict parts_i = ci->hydro.parts; + const struct part *restrict parts_j = cj->hydro.parts; - int first_pi = 0, last_pj = cj->count - 1; + int first_pi = 0, last_pj = cj->hydro.count - 1; int temp, active_id; /* Only populate max_index array for local actve cells. */ @@ -281,7 +281,7 @@ __attribute__((always_inline)) INLINE static void populate_max_index_density( /* Find the leftmost active particle in cell i that interacts with any * particle in cell j. */ - first_pi = ci->count; + first_pi = ci->hydro.count; active_id = first_pi - 1; while (first_pi > 0 && sort_i[first_pi - 1].d + dx_max + hi_max > dj_min) { first_pi--; @@ -295,7 +295,7 @@ __attribute__((always_inline)) INLINE static void populate_max_index_density( /* Find the maximum index into cell j for each particle in range in cell i. */ - if (first_pi < ci->count) { + if (first_pi < ci->hydro.count) { /* Start from the first particle in cell j. */ temp = 0; @@ -305,33 +305,33 @@ __attribute__((always_inline)) INLINE static void populate_max_index_density( sort_i[first_pi].d + pi->h * kernel_gamma + dx_max - rshift; /* Loop through particles in cell j until they are not in range of pi. - * Make sure that temp stays between 0 and cj->count - 1.*/ - while (temp < cj->count - 1 && first_di > sort_j[temp].d) temp++; + * Make sure that temp stays between 0 and cj->hydro.count - 1.*/ + while (temp < cj->hydro.count - 1 && first_di > sort_j[temp].d) temp++; max_index_i[first_pi] = temp; /* Populate max_index_i for remaining particles that are within range. */ - for (int i = first_pi + 1; i < ci->count; i++) { + for (int i = first_pi + 1; i < ci->hydro.count; i++) { temp = max_index_i[i - 1]; pi = &parts_i[sort_i[i].i]; const float di = sort_i[i].d + pi->h * kernel_gamma + dx_max - rshift; - /* Make sure that temp stays between 0 and cj->count - 1.*/ - while (temp < cj->count - 1 && di > sort_j[temp].d) temp++; + /* Make sure that temp stays between 0 and cj->hydro.count - 1.*/ + while (temp < cj->hydro.count - 1 && di > sort_j[temp].d) temp++; max_index_i[i] = temp; } } else { /* Make sure that max index is set to first particle in cj.*/ - max_index_i[ci->count - 1] = 0; + max_index_i[ci->hydro.count - 1] = 0; } } else { /* Make sure that foreign cells are only read into the cache if the local * cell requires it. * Also ensure that it does not require any particles from cj. */ - first_pi = ci->count - 1; - max_index_i[ci->count - 1] = 0; + first_pi = ci->hydro.count - 1; + max_index_i[ci->hydro.count - 1] = 0; } /* Only populate max_index array for local actve cells. */ @@ -340,7 +340,7 @@ __attribute__((always_inline)) INLINE static void populate_max_index_density( * particle in cell i. */ last_pj = -1; active_id = last_pj; - while (last_pj < cj->count && + while (last_pj < cj->hydro.count && sort_j[last_pj + 1].d - hj_max - dx_max < di_max) { last_pj++; /* Store the index of the particle if it is active. */ @@ -356,7 +356,7 @@ __attribute__((always_inline)) INLINE static void populate_max_index_density( if (last_pj >= 0) { /* Start from the last particle in cell i. */ - temp = ci->count - 1; + temp = ci->hydro.count - 1; const struct part *pj = &parts_j[sort_j[last_pj].i]; const float last_dj = @@ -379,14 +379,14 @@ __attribute__((always_inline)) INLINE static void populate_max_index_density( } } else { /* Make sure that max index is set to last particle in ci.*/ - max_index_j[0] = ci->count - 1; + max_index_j[0] = ci->hydro.count - 1; } } else { /* Make sure that foreign cells are only read into the cache if the local * cell requires it. * Also ensure that it does not require any particles from ci. */ last_pj = 0; - max_index_j[0] = ci->count - 1; + max_index_j[0] = ci->hydro.count - 1; } *init_pi = first_pi; @@ -430,10 +430,10 @@ __attribute__((always_inline)) INLINE static void populate_max_index_force( int *init_pj, const timebin_t max_active_bin, const int active_ci, const int active_cj) { - const struct part *restrict parts_i = ci->parts; - const struct part *restrict parts_j = cj->parts; + const struct part *restrict parts_i = ci->hydro.parts; + const struct part *restrict parts_j = cj->hydro.parts; - int first_pi = 0, last_pj = cj->count - 1; + int first_pi = 0, last_pj = cj->hydro.count - 1; int temp, active_id; /* Only populate max_index array for local actve cells. */ @@ -441,7 +441,7 @@ __attribute__((always_inline)) INLINE static void populate_max_index_force( /* Find the leftmost active particle in cell i that interacts with any * particle in cell j. */ - first_pi = ci->count; + first_pi = ci->hydro.count; active_id = first_pi - 1; while (first_pi > 0 && sort_i[first_pi - 1].d + dx_max + h_max > dj_min) { first_pi--; @@ -455,7 +455,7 @@ __attribute__((always_inline)) INLINE static void populate_max_index_force( /* Find the maximum index into cell j for each particle in range in cell i. */ - if (first_pi < ci->count) { + if (first_pi < ci->hydro.count) { /* Start from the first particle in cell j. */ temp = 0; @@ -466,34 +466,34 @@ __attribute__((always_inline)) INLINE static void populate_max_index_force( rshift; /* Loop through particles in cell j until they are not in range of pi. - * Make sure that temp stays between 0 and cj->count - 1.*/ - while (temp < cj->count - 1 && first_di > sort_j[temp].d) temp++; + * Make sure that temp stays between 0 and cj->hydro.count - 1.*/ + while (temp < cj->hydro.count - 1 && first_di > sort_j[temp].d) temp++; max_index_i[first_pi] = temp; /* Populate max_index_i for remaining particles that are within range. */ - for (int i = first_pi + 1; i < ci->count; i++) { + for (int i = first_pi + 1; i < ci->hydro.count; i++) { temp = max_index_i[i - 1]; pi = &parts_i[sort_i[i].i]; const float di = sort_i[i].d + max(pi->h, hj_max_raw) * kernel_gamma + dx_max - rshift; - /* Make sure that temp stays between 0 and cj->count - 1.*/ - while (temp < cj->count - 1 && di > sort_j[temp].d) temp++; + /* Make sure that temp stays between 0 and cj->hydro.count - 1.*/ + while (temp < cj->hydro.count - 1 && di > sort_j[temp].d) temp++; max_index_i[i] = temp; } } else { /* Make sure that max index is set to first particle in cj.*/ - max_index_i[ci->count - 1] = 0; + max_index_i[ci->hydro.count - 1] = 0; } } else { /* Make sure that foreign cells are only read into the cache if the local * cell requires it. * Also ensure that it does not require any particles from cj. */ - first_pi = ci->count - 1; - max_index_i[ci->count - 1] = 0; + first_pi = ci->hydro.count - 1; + max_index_i[ci->hydro.count - 1] = 0; } /* Only populate max_index array for local actve cells. */ @@ -502,7 +502,7 @@ __attribute__((always_inline)) INLINE static void populate_max_index_force( * particle in cell i. */ last_pj = -1; active_id = last_pj; - while (last_pj < cj->count && + while (last_pj < cj->hydro.count && sort_j[last_pj + 1].d - h_max - dx_max < di_max) { last_pj++; /* Store the index of the particle if it is active. */ @@ -518,7 +518,7 @@ __attribute__((always_inline)) INLINE static void populate_max_index_force( if (last_pj >= 0) { /* Start from the last particle in cell i. */ - temp = ci->count - 1; + temp = ci->hydro.count - 1; const struct part *pj = &parts_j[sort_j[last_pj].i]; const float last_dj = sort_j[last_pj].d - dx_max - @@ -543,14 +543,14 @@ __attribute__((always_inline)) INLINE static void populate_max_index_force( } } else { /* Make sure that max index is set to last particle in ci.*/ - max_index_j[0] = ci->count - 1; + max_index_j[0] = ci->hydro.count - 1; } } else { /* Make sure that foreign cells are only read into the cache if the local * cell requires it. * Also ensure that it does not require any particles from ci. */ last_pj = 0; - max_index_j[0] = ci->count - 1; + max_index_j[0] = ci->hydro.count - 1; } *init_pi = first_pi; @@ -655,8 +655,8 @@ void runner_doself1_density_vec(struct runner *r, struct cell *restrict c) { /* Get some local variables */ const struct engine *e = r->e; const timebin_t max_active_bin = e->max_active_bin; - struct part *restrict parts = c->parts; - const int count = c->count; + struct part *restrict parts = c->hydro.parts; + const int count = c->hydro.count; TIMER_TIC; @@ -888,7 +888,7 @@ void runner_doself_subset_density_vec(struct runner *r, struct cell *restrict c, #if defined(WITH_VECTORIZATION) && defined(GADGET2_SPH) - const int count = c->count; + const int count = c->hydro.count; TIMER_TIC; @@ -1016,7 +1016,7 @@ void runner_doself_subset_density_vec(struct runner *r, struct cell *restrict c, vec_is_mask_true(v_doi_mask2_self_check); #ifdef DEBUG_INTERACTIONS_SPH - struct part *restrict parts_i = c->parts; + struct part *restrict parts_i = c->hydro.parts; for (int bit_index = 0; bit_index < VEC_SIZE; bit_index++) { if (doi_mask & (1 << bit_index)) { if (pi->num_ngb_density < MAX_NUM_OF_NEIGHBOURS) @@ -1113,8 +1113,8 @@ void runner_doself2_force_vec(struct runner *r, struct cell *restrict c) { const struct engine *e = r->e; const struct cosmology *restrict cosmo = e->cosmology; const timebin_t max_active_bin = e->max_active_bin; - struct part *restrict parts = c->parts; - const int count = c->count; + struct part *restrict parts = c->hydro.parts; + const int count = c->hydro.count; TIMER_TIC; @@ -1322,19 +1322,19 @@ void runner_dopair1_density_vec(struct runner *r, struct cell *ci, for (int k = 0; k < 3; k++) rshift += shift[k] * runner_shift[sid][k]; /* Pick-out the sorted lists. */ - const struct entry *restrict sort_i = ci->sort[sid]; - const struct entry *restrict sort_j = cj->sort[sid]; + const struct entry *restrict sort_i = ci->hydro.sort[sid]; + const struct entry *restrict sort_j = cj->hydro.sort[sid]; /* Get some other useful values. */ - const int count_i = ci->count; - const int count_j = cj->count; - const double hi_max = ci->h_max * kernel_gamma - rshift; - const double hj_max = cj->h_max * kernel_gamma; - struct part *restrict parts_i = ci->parts; - struct part *restrict parts_j = cj->parts; + const int count_i = ci->hydro.count; + const int count_j = cj->hydro.count; + const double hi_max = ci->hydro.h_max * kernel_gamma - rshift; + const double hj_max = cj->hydro.h_max * kernel_gamma; + struct part *restrict parts_i = ci->hydro.parts; + struct part *restrict parts_j = cj->hydro.parts; const double di_max = sort_i[count_i - 1].d - rshift; const double dj_min = sort_j[0].d; - const float dx_max = (ci->dx_max_sort + cj->dx_max_sort); + const float dx_max = (ci->hydro.dx_max_sort + cj->hydro.dx_max_sort); const int active_ci = cell_is_active_hydro(ci, e) && ci_local; const int active_cj = cell_is_active_hydro(cj, e) && cj_local; @@ -1693,11 +1693,11 @@ void runner_dopair_subset_density_vec(struct runner *r, TIMER_TIC; - const int count_j = cj->count; + const int count_j = cj->hydro.count; /* Pick-out the sorted lists. */ - const struct entry *restrict sort_j = cj->sort[sid]; - const float dxj = cj->dx_max_sort; + const struct entry *restrict sort_j = cj->hydro.sort[sid]; + const float dxj = cj->hydro.dx_max_sort; /* Get both particle caches from the runner and re-allocate * them if they are not big enough for the cells. */ @@ -1806,7 +1806,7 @@ void runner_dopair_subset_density_vec(struct runner *r, vec_create_mask(v_doi_mask, vec_cmp_lt(v_r2.v, v_hig2.v)); #ifdef DEBUG_INTERACTIONS_SPH - struct part *restrict parts_j = cj->parts; + struct part *restrict parts_j = cj->hydro.parts; for (int bit_index = 0; bit_index < VEC_SIZE; bit_index++) { if (vec_is_mask_true(v_doi_mask) & (1 << bit_index)) { if (pi->num_ngb_density < MAX_NUM_OF_NEIGHBOURS) { @@ -1935,7 +1935,7 @@ void runner_dopair_subset_density_vec(struct runner *r, vec_create_mask(v_doi_mask, vec_cmp_lt(v_r2.v, v_hig2.v)); #ifdef DEBUG_INTERACTIONS_SPH - struct part *restrict parts_j = cj->parts; + struct part *restrict parts_j = cj->hydro.parts; for (int bit_index = 0; bit_index < VEC_SIZE; bit_index++) { if (vec_is_mask_true(v_doi_mask) & (1 << bit_index)) { if (pi->num_ngb_density < MAX_NUM_OF_NEIGHBOURS) { @@ -2007,21 +2007,21 @@ void runner_dopair2_force_vec(struct runner *r, struct cell *ci, for (int k = 0; k < 3; k++) rshift += shift[k] * runner_shift[sid][k]; /* Pick-out the sorted lists. */ - const struct entry *restrict sort_i = ci->sort[sid]; - const struct entry *restrict sort_j = cj->sort[sid]; + const struct entry *restrict sort_i = ci->hydro.sort[sid]; + const struct entry *restrict sort_j = cj->hydro.sort[sid]; /* Get some other useful values. */ - const int count_i = ci->count; - const int count_j = cj->count; - const double hi_max = ci->h_max * kernel_gamma; - const double hj_max = cj->h_max * kernel_gamma; - const double hi_max_raw = ci->h_max; - const double hj_max_raw = cj->h_max; - struct part *restrict parts_i = ci->parts; - struct part *restrict parts_j = cj->parts; + const int count_i = ci->hydro.count; + const int count_j = cj->hydro.count; + const double hi_max = ci->hydro.h_max * kernel_gamma; + const double hj_max = cj->hydro.h_max * kernel_gamma; + const double hi_max_raw = ci->hydro.h_max; + const double hj_max_raw = cj->hydro.h_max; + struct part *restrict parts_i = ci->hydro.parts; + struct part *restrict parts_j = cj->hydro.parts; const double di_max = sort_i[count_i - 1].d - rshift; const double dj_min = sort_j[0].d; - const float dx_max = (ci->dx_max_sort + cj->dx_max_sort); + const float dx_max = (ci->hydro.dx_max_sort + cj->hydro.dx_max_sort); const int active_ci = cell_is_active_hydro(ci, e) && ci_local; const int active_cj = cell_is_active_hydro(cj, e) && cj_local; diff --git a/src/scheduler.c b/src/scheduler.c index d582ee9ce17c397c8cfe65f55cf8671591af3ea3..28fb4146983ee40144ff30693453f7e3b27eac3b 100644 --- a/src/scheduler.c +++ b/src/scheduler.c @@ -380,10 +380,13 @@ void scheduler_write_dependencies(struct scheduler *s, int verbose) { } } - /* Be clean */ + /* Close the file */ fprintf(f, "}"); fclose(f); + + /* Be clean */ free(table); + free(count_rel); if (verbose) message("Printing task graph took %.3f %s.", @@ -407,7 +410,7 @@ static void scheduler_splittask_hydro(struct task *t, struct scheduler *s) { /* Non-splittable task? */ if ((t->ci == NULL) || (t->type == task_type_pair && t->cj == NULL) || - t->ci->count == 0 || (t->cj != NULL && t->cj->count == 0)) { + t->ci->hydro.count == 0 || (t->cj != NULL && t->cj->hydro.count == 0)) { t->type = task_type_none; t->subtype = task_subtype_none; t->cj = NULL; @@ -431,7 +434,7 @@ static void scheduler_splittask_hydro(struct task *t, struct scheduler *s) { if (cell_can_split_self_hydro_task(ci)) { /* Make a sub? */ - if (scheduler_dosub && ci->count < space_subsize_self_hydro) { + if (scheduler_dosub && ci->hydro.count < space_subsize_self_hydro) { /* convert to a self-subtask. */ t->type = task_type_sub_self; @@ -447,7 +450,7 @@ static void scheduler_splittask_hydro(struct task *t, struct scheduler *s) { while (ci->progeny[first_child] == NULL) first_child++; t->ci = ci->progeny[first_child]; for (int k = first_child + 1; k < 8; k++) - if (ci->progeny[k] != NULL && ci->progeny[k]->count) + if (ci->progeny[k] != NULL && ci->progeny[k]->hydro.count) scheduler_splittask_hydro( scheduler_addtask(s, task_type_self, t->subtype, 0, 0, ci->progeny[k], NULL), @@ -455,9 +458,9 @@ static void scheduler_splittask_hydro(struct task *t, struct scheduler *s) { /* Make a task for each pair of progeny */ for (int j = 0; j < 8; j++) - if (ci->progeny[j] != NULL && ci->progeny[j]->count) + if (ci->progeny[j] != NULL && ci->progeny[j]->hydro.count) for (int k = j + 1; k < 8; k++) - if (ci->progeny[k] != NULL && ci->progeny[k]->count) + if (ci->progeny[k] != NULL && ci->progeny[k]->hydro.count) scheduler_splittask_hydro( scheduler_addtask(s, task_type_pair, t->subtype, sub_sid_flag[j][k], 0, ci->progeny[j], @@ -492,7 +495,8 @@ static void scheduler_splittask_hydro(struct task *t, struct scheduler *s) { /* Replace by a single sub-task? */ if (scheduler_dosub && /* Use division to avoid integer overflow. */ - ci->count * sid_scale[sid] < space_subsize_pair_hydro / cj->count && + ci->hydro.count * sid_scale[sid] < + space_subsize_pair_hydro / cj->hydro.count && !sort_is_corner(sid)) { /* Make this task a sub task. */ @@ -841,18 +845,18 @@ static void scheduler_splittask_hydro(struct task *t, struct scheduler *s) { /* Otherwise, break it up if it is too large? */ } else if (scheduler_doforcesplit && ci->split && cj->split && - (ci->count > space_maxsize / cj->count)) { + (ci->hydro.count > space_maxsize / cj->hydro.count)) { - // message( "force splitting pair with %i and %i parts." , ci->count , - // cj->count ); + // message( "force splitting pair with %i and %i parts." , + // ci->hydro.count , cj->hydro.count ); /* Replace the current task. */ t->type = task_type_none; for (int j = 0; j < 8; j++) - if (ci->progeny[j] != NULL && ci->progeny[j]->count) + if (ci->progeny[j] != NULL && ci->progeny[j]->hydro.count) for (int k = 0; k < 8; k++) - if (cj->progeny[k] != NULL && cj->progeny[k]->count) { + if (cj->progeny[k] != NULL && cj->progeny[k]->hydro.count) { struct task *tl = scheduler_addtask(s, task_type_pair, t->subtype, 0, 0, ci->progeny[j], cj->progeny[k]); @@ -872,8 +876,6 @@ static void scheduler_splittask_hydro(struct task *t, struct scheduler *s) { */ static void scheduler_splittask_stars(struct task *t, struct scheduler *s) { - // LOIC: This is un-tested. Need to verify that it works. - /* Iterate on this task until we're done with it. */ int redo = 1; while (redo) { @@ -883,7 +885,7 @@ static void scheduler_splittask_stars(struct task *t, struct scheduler *s) { /* Non-splittable task? */ if ((t->ci == NULL) || (t->type == task_type_pair && t->cj == NULL) || - t->ci->scount == 0 || (t->cj != NULL && t->cj->scount == 0)) { + t->ci->stars.count == 0 || (t->cj != NULL && t->cj->stars.count == 0)) { t->type = task_type_none; t->subtype = task_subtype_none; t->cj = NULL; @@ -907,7 +909,7 @@ static void scheduler_splittask_stars(struct task *t, struct scheduler *s) { if (cell_can_split_self_stars_task(ci)) { /* Make a sub? */ - if (scheduler_dosub && ci->scount < space_subsize_self_stars) { + if (scheduler_dosub && ci->stars.count < space_subsize_self_stars) { /* convert to a self-subtask. */ t->type = task_type_sub_self; @@ -923,7 +925,7 @@ static void scheduler_splittask_stars(struct task *t, struct scheduler *s) { while (ci->progeny[first_child] == NULL) first_child++; t->ci = ci->progeny[first_child]; for (int k = first_child + 1; k < 8; k++) - if (ci->progeny[k] != NULL && ci->progeny[k]->scount) + if (ci->progeny[k] != NULL && ci->progeny[k]->stars.count) scheduler_splittask_stars( scheduler_addtask(s, task_type_self, t->subtype, 0, 0, ci->progeny[k], NULL), @@ -931,9 +933,9 @@ static void scheduler_splittask_stars(struct task *t, struct scheduler *s) { /* Make a task for each pair of progeny */ for (int j = 0; j < 8; j++) - if (ci->progeny[j] != NULL && ci->progeny[j]->scount) + if (ci->progeny[j] != NULL && ci->progeny[j]->stars.count) for (int k = j + 1; k < 8; k++) - if (ci->progeny[k] != NULL && ci->progeny[k]->scount) + if (ci->progeny[k] != NULL && ci->progeny[k]->stars.count) scheduler_splittask_stars( scheduler_addtask(s, task_type_pair, t->subtype, sub_sid_flag[j][k], 0, ci->progeny[j], @@ -968,8 +970,8 @@ static void scheduler_splittask_stars(struct task *t, struct scheduler *s) { /* Replace by a single sub-task? */ if (scheduler_dosub && /* Use division to avoid integer overflow. */ - ci->scount * sid_scale[sid] < - space_subsize_pair_stars / cj->scount && + ci->stars.count * sid_scale[sid] < + space_subsize_pair_stars / cj->stars.count && !sort_is_corner(sid)) { /* Make this task a sub task. */ @@ -1318,15 +1320,15 @@ static void scheduler_splittask_stars(struct task *t, struct scheduler *s) { /* Otherwise, break it up if it is too large? */ } else if (scheduler_doforcesplit && ci->split && cj->split && - (ci->scount > space_maxsize / cj->scount)) { + (ci->stars.count > space_maxsize / cj->stars.count)) { /* Replace the current task. */ t->type = task_type_none; for (int j = 0; j < 8; j++) - if (ci->progeny[j] != NULL && ci->progeny[j]->scount) + if (ci->progeny[j] != NULL && ci->progeny[j]->stars.count) for (int k = 0; k < 8; k++) - if (cj->progeny[k] != NULL && cj->progeny[k]->scount) { + if (cj->progeny[k] != NULL && cj->progeny[k]->stars.count) { struct task *tl = scheduler_addtask(s, task_type_pair, t->subtype, 0, 0, ci->progeny[j], cj->progeny[k]); @@ -1380,7 +1382,7 @@ static void scheduler_splittask_gravity(struct task *t, struct scheduler *s) { /* Should we split this task? */ if (cell_can_split_self_gravity_task(ci)) { - if (scheduler_dosub && ci->gcount < space_subsize_self_grav) { + if (scheduler_dosub && ci->grav.count < space_subsize_self_grav) { /* Otherwise, split it. */ } else { @@ -1434,8 +1436,8 @@ static void scheduler_splittask_gravity(struct task *t, struct scheduler *s) { if (cell_can_split_pair_gravity_task(ci) && cell_can_split_pair_gravity_task(cj)) { - const long long gcount_i = ci->gcount; - const long long gcount_j = cj->gcount; + const long long gcount_i = ci->grav.count; + const long long gcount_j = cj->grav.count; /* Replace by a single sub-task? */ if (scheduler_dosub && @@ -1466,7 +1468,7 @@ static void scheduler_splittask_gravity(struct task *t, struct scheduler *s) { * the information and operate according to the choices * made here. */ const int flag = i * 8 + j; - t->flags |= (1LL << flag); + t->flags |= (1ULL << flag); } else { @@ -1820,35 +1822,44 @@ void scheduler_reweight(struct scheduler *s, int verbose) { int partcost = 1; #endif - const float count_i = (t->ci != NULL) ? t->ci->count : 0.f; - const float count_j = (t->cj != NULL) ? t->cj->count : 0.f; - const float gcount_i = (t->ci != NULL) ? t->ci->gcount : 0.f; - const float gcount_j = (t->cj != NULL) ? t->cj->gcount : 0.f; - const float scount_i = (t->ci != NULL) ? t->ci->scount : 0.f; + const float count_i = (t->ci != NULL) ? t->ci->hydro.count : 0.f; + const float count_j = (t->cj != NULL) ? t->cj->hydro.count : 0.f; + const float gcount_i = (t->ci != NULL) ? t->ci->grav.count : 0.f; + const float gcount_j = (t->cj != NULL) ? t->cj->grav.count : 0.f; + const float scount_i = (t->ci != NULL) ? t->ci->stars.count : 0.f; + const float scount_j = (t->cj != NULL) ? t->cj->stars.count : 0.f; switch (t->type) { case task_type_sort: cost = wscale * intrinsics_popcount(t->flags) * count_i * - (sizeof(int) * 8 - intrinsics_clz(t->ci->count)); + (sizeof(int) * 8 - intrinsics_clz(t->ci->hydro.count)); break; case task_type_self: - // LOIC: Need to do something for stars here if (t->subtype == task_subtype_grav) cost = 1.f * (wscale * gcount_i) * gcount_i; else if (t->subtype == task_subtype_external_grav) cost = 1.f * wscale * gcount_i; + else if (t->subtype == task_subtype_stars_density) + cost = 1.f * wscale * scount_i * count_i; else cost = 1.f * (wscale * count_i) * count_i; break; case task_type_pair: - // LOIC: Need to do something for stars here if (t->subtype == task_subtype_grav) { if (t->ci->nodeID != nodeID || t->cj->nodeID != nodeID) cost = 3.f * (wscale * gcount_i) * gcount_j; else cost = 2.f * (wscale * gcount_i) * gcount_j; + } else if (t->subtype == task_subtype_stars_density) { + if (t->ci->nodeID != nodeID) + cost = 3.f * wscale * count_i * scount_j * sid_scale[t->flags]; + else if (t->cj->nodeID != nodeID) + cost = 3.f * wscale * scount_i * count_j * sid_scale[t->flags]; + else + cost = 2.f * wscale * (scount_i * count_j + scount_j * count_i) * + sid_scale[t->flags]; } else { if (t->ci->nodeID != nodeID || t->cj->nodeID != nodeID) cost = 3.f * (wscale * count_i) * count_j * sid_scale[t->flags]; @@ -1858,32 +1869,43 @@ void scheduler_reweight(struct scheduler *s, int verbose) { break; case task_type_sub_pair: - // LOIC: Need to do something for stars here - if (t->ci->nodeID != nodeID || t->cj->nodeID != nodeID) { #ifdef SWIFT_DEBUG_CHECKS - if (t->flags < 0) error("Negative flag value!"); + if (t->flags < 0) error("Negative flag value!"); #endif - cost = 3.f * (wscale * count_i) * count_j * sid_scale[t->flags]; + if (t->subtype == task_subtype_stars_density) { + if (t->ci->nodeID != nodeID) { + cost = 3.f * (wscale * count_i) * scount_j * sid_scale[t->flags]; + } else if (t->cj->nodeID != nodeID) { + cost = 3.f * (wscale * scount_i) * count_j * sid_scale[t->flags]; + } else { + cost = 2.f * wscale * (scount_i * count_j + scount_j * count_i) * + sid_scale[t->flags]; + } + } else { -#ifdef SWIFT_DEBUG_CHECKS - if (t->flags < 0) error("Negative flag value!"); -#endif - cost = 2.f * (wscale * count_i) * count_j * sid_scale[t->flags]; + if (t->ci->nodeID != nodeID || t->cj->nodeID != nodeID) { + cost = 3.f * (wscale * count_i) * count_j * sid_scale[t->flags]; + } else { + cost = 2.f * (wscale * count_i) * count_j * sid_scale[t->flags]; + } } break; case task_type_sub_self: - // LOIC: Need to do something for stars here - cost = 1.f * (wscale * count_i) * count_i; + if (t->subtype == task_subtype_stars_density) { + cost = 1.f * (wscale * scount_i) * count_i; + } else { + cost = 1.f * (wscale * count_i) * count_i; + } break; case task_type_ghost: - if (t->ci == t->ci->super_hydro) cost = wscale * count_i; + if (t->ci == t->ci->hydro.super) cost = wscale * count_i; break; case task_type_extra_ghost: - if (t->ci == t->ci->super_hydro) cost = wscale * count_i; + if (t->ci == t->ci->hydro.super) cost = wscale * count_i; break; case task_type_stars_ghost: - if (t->ci == t->ci->super_hydro) cost = wscale * scount_i; + if (t->ci == t->ci->hydro.super) cost = wscale * scount_i; break; case task_type_drift_part: cost = wscale * count_i; @@ -2086,21 +2108,22 @@ void scheduler_enqueue(struct scheduler *s, struct task *t) { case task_type_sub_self: if (t->subtype == task_subtype_grav || t->subtype == task_subtype_external_grav) - qid = t->ci->super_gravity->owner; + qid = t->ci->grav.super->owner; else - qid = t->ci->super_hydro->owner; + qid = t->ci->hydro.super->owner; break; case task_type_sort: case task_type_ghost: case task_type_drift_part: - qid = t->ci->super_hydro->owner; + qid = t->ci->hydro.super->owner; break; case task_type_drift_gpart: - qid = t->ci->super_gravity->owner; + qid = t->ci->grav.super->owner; break; case task_type_kick1: case task_type_kick2: case task_type_stars_ghost: + case task_type_logger: case task_type_timestep: qid = t->ci->super->owner; break; @@ -2115,31 +2138,32 @@ void scheduler_enqueue(struct scheduler *s, struct task *t) { #ifdef WITH_MPI if (t->subtype == task_subtype_tend) { t->buff = (struct pcell_step *)malloc(sizeof(struct pcell_step) * - t->ci->pcell_size); - err = MPI_Irecv( - t->buff, t->ci->pcell_size * sizeof(struct pcell_step), MPI_BYTE, - t->ci->nodeID, t->flags, subtaskMPI_comms[t->subtype], &t->req); + t->ci->mpi.pcell_size); + err = MPI_Irecv(t->buff, + t->ci->mpi.pcell_size * sizeof(struct pcell_step), + MPI_BYTE, t->ci->nodeID, t->flags, + subtaskMPI_comms[t->subtype], &t->req); } else if (t->subtype == task_subtype_xv || t->subtype == task_subtype_rho || t->subtype == task_subtype_gradient) { - err = MPI_Irecv(t->ci->parts, t->ci->count, part_mpi_type, + err = MPI_Irecv(t->ci->hydro.parts, t->ci->hydro.count, part_mpi_type, t->ci->nodeID, t->flags, subtaskMPI_comms[t->subtype], &t->req); // message( "receiving %i parts with tag=%i from %i to %i." , - // t->ci->count , t->flags , t->ci->nodeID , s->nodeID ); + // t->ci->hydro.count , t->flags , t->ci->nodeID , s->nodeID ); // fflush(stdout); } else if (t->subtype == task_subtype_gpart) { - err = MPI_Irecv(t->ci->gparts, t->ci->gcount, gpart_mpi_type, + err = MPI_Irecv(t->ci->grav.parts, t->ci->grav.count, gpart_mpi_type, t->ci->nodeID, t->flags, subtaskMPI_comms[t->subtype], &t->req); } else if (t->subtype == task_subtype_spart) { - err = MPI_Irecv(t->ci->sparts, t->ci->scount, spart_mpi_type, - t->ci->nodeID, t->flags, subtaskMPI_comms[t->subtype], - &t->req); + err = MPI_Irecv(t->ci->stars.parts, t->ci->stars.count, + spart_mpi_type, t->ci->nodeID, t->flags, + subtaskMPI_comms[t->subtype], &t->req); } else if (t->subtype == task_subtype_multipole) { t->buff = (struct gravity_tensors *)malloc( - sizeof(struct gravity_tensors) * t->ci->pcell_size); - err = MPI_Irecv(t->buff, t->ci->pcell_size, multipole_mpi_type, + sizeof(struct gravity_tensors) * t->ci->mpi.pcell_size); + err = MPI_Irecv(t->buff, t->ci->mpi.pcell_size, multipole_mpi_type, t->ci->nodeID, t->flags, subtaskMPI_comms[t->subtype], &t->req); } else { @@ -2157,56 +2181,57 @@ void scheduler_enqueue(struct scheduler *s, struct task *t) { #ifdef WITH_MPI if (t->subtype == task_subtype_tend) { t->buff = (struct pcell_step *)malloc(sizeof(struct pcell_step) * - t->ci->pcell_size); + t->ci->mpi.pcell_size); cell_pack_end_step(t->ci, (struct pcell_step *)t->buff); - if ((t->ci->pcell_size * sizeof(struct pcell_step)) > + if ((t->ci->mpi.pcell_size * sizeof(struct pcell_step)) > s->mpi_message_limit) err = MPI_Isend(t->buff, - t->ci->pcell_size * sizeof(struct pcell_step), + t->ci->mpi.pcell_size * sizeof(struct pcell_step), MPI_BYTE, t->cj->nodeID, t->flags, subtaskMPI_comms[t->subtype], &t->req); else err = MPI_Issend(t->buff, - t->ci->pcell_size * sizeof(struct pcell_step), + t->ci->mpi.pcell_size * sizeof(struct pcell_step), MPI_BYTE, t->cj->nodeID, t->flags, subtaskMPI_comms[t->subtype], &t->req); } else if (t->subtype == task_subtype_xv || t->subtype == task_subtype_rho || t->subtype == task_subtype_gradient) { - if ((t->ci->count * sizeof(struct part)) > s->mpi_message_limit) - err = MPI_Isend(t->ci->parts, t->ci->count, part_mpi_type, - t->cj->nodeID, t->flags, + if ((t->ci->hydro.count * sizeof(struct part)) > s->mpi_message_limit) + err = MPI_Isend(t->ci->hydro.parts, t->ci->hydro.count, + part_mpi_type, t->cj->nodeID, t->flags, subtaskMPI_comms[t->subtype], &t->req); else - err = MPI_Issend(t->ci->parts, t->ci->count, part_mpi_type, - t->cj->nodeID, t->flags, + err = MPI_Issend(t->ci->hydro.parts, t->ci->hydro.count, + part_mpi_type, t->cj->nodeID, t->flags, subtaskMPI_comms[t->subtype], &t->req); // message( "sending %i parts with tag=%i from %i to %i." , - // t->ci->count , t->flags , s->nodeID , t->cj->nodeID ); + // t->ci->hydro.count , t->flags , s->nodeID , t->cj->nodeID ); // fflush(stdout); } else if (t->subtype == task_subtype_gpart) { - if ((t->ci->gcount * sizeof(struct gpart)) > s->mpi_message_limit) - err = MPI_Isend(t->ci->gparts, t->ci->gcount, gpart_mpi_type, - t->cj->nodeID, t->flags, + if ((t->ci->grav.count * sizeof(struct gpart)) > s->mpi_message_limit) + err = MPI_Isend(t->ci->grav.parts, t->ci->grav.count, + gpart_mpi_type, t->cj->nodeID, t->flags, subtaskMPI_comms[t->subtype], &t->req); else - err = MPI_Issend(t->ci->gparts, t->ci->gcount, gpart_mpi_type, - t->cj->nodeID, t->flags, + err = MPI_Issend(t->ci->grav.parts, t->ci->grav.count, + gpart_mpi_type, t->cj->nodeID, t->flags, subtaskMPI_comms[t->subtype], &t->req); } else if (t->subtype == task_subtype_spart) { - if ((t->ci->scount * sizeof(struct spart)) > s->mpi_message_limit) - err = MPI_Isend(t->ci->sparts, t->ci->scount, spart_mpi_type, - t->cj->nodeID, t->flags, + if ((t->ci->stars.count * sizeof(struct spart)) > + s->mpi_message_limit) + err = MPI_Isend(t->ci->stars.parts, t->ci->stars.count, + spart_mpi_type, t->cj->nodeID, t->flags, subtaskMPI_comms[t->subtype], &t->req); else - err = MPI_Issend(t->ci->sparts, t->ci->scount, spart_mpi_type, - t->cj->nodeID, t->flags, + err = MPI_Issend(t->ci->stars.parts, t->ci->stars.count, + spart_mpi_type, t->cj->nodeID, t->flags, subtaskMPI_comms[t->subtype], &t->req); } else if (t->subtype == task_subtype_multipole) { t->buff = (struct gravity_tensors *)malloc( - sizeof(struct gravity_tensors) * t->ci->pcell_size); + sizeof(struct gravity_tensors) * t->ci->mpi.pcell_size); cell_pack_multipoles(t->ci, (struct gravity_tensors *)t->buff); - err = MPI_Isend(t->buff, t->ci->pcell_size, multipole_mpi_type, + err = MPI_Isend(t->buff, t->ci->mpi.pcell_size, multipole_mpi_type, t->cj->nodeID, t->flags, subtaskMPI_comms[t->subtype], &t->req); } else { @@ -2520,3 +2545,61 @@ void scheduler_free_tasks(struct scheduler *s) { } s->size = 0; } + +/** + * @brief write down each task level + */ +void scheduler_write_task_level(const struct scheduler *s) { + /* init */ + const int max_depth = 30; + const struct task *tasks = s->tasks; + int nr_tasks = s->nr_tasks; + + /* Init counter */ + int size = task_type_count * task_subtype_count * max_depth; + int *count = (int *)malloc(size * sizeof(int)); + if (count == NULL) error("Failed to allocate memory"); + + for (int i = 0; i < size; i++) count[i] = 0; + + /* Count tasks */ + for (int i = 0; i < nr_tasks; i++) { + const struct task *t = &tasks[i]; + if (t->ci) { + + if ((int)t->ci->depth >= max_depth) + error("Cell is too deep, you need to increase max_depth"); + + int ind = t->type * task_subtype_count * max_depth; + ind += t->subtype * max_depth; + ind += (int)t->ci->depth; + + count[ind] += 1; + } + } + + /* Open file */ + char filename[200] = "task_level.txt"; + FILE *f = fopen(filename, "w"); + if (f == NULL) error("Error opening task level file."); + + /* Print header */ + fprintf(f, "# task_type, task_subtype, depth, count\n"); + + /* Print tasks level */ + for (int i = 0; i < size; i++) { + if (count[i] == 0) continue; + + int type = i / (task_subtype_count * max_depth); + int subtype = i - task_subtype_count * max_depth * type; + subtype /= max_depth; + int depth = i - task_subtype_count * max_depth * type; + depth -= subtype * max_depth; + fprintf(f, "%s %s %i %i\n", taskID_names[type], subtaskID_names[subtype], + depth, count[i]); + } + + /* clean up */ + fclose(f); + free(count); +} diff --git a/src/scheduler.h b/src/scheduler.h index 1a75544de12b8402e553e3ae2b84e2d8a65c56e8..f1e130c6ce2a8538b0126e86ee0cbd79cf5a0e0d 100644 --- a/src/scheduler.h +++ b/src/scheduler.h @@ -173,5 +173,6 @@ void scheduler_print_tasks(const struct scheduler *s, const char *fileName); void scheduler_clean(struct scheduler *s); void scheduler_free_tasks(struct scheduler *s); void scheduler_write_dependencies(struct scheduler *s, int verbose); +void scheduler_write_task_level(const struct scheduler *s); #endif /* SWIFT_SCHEDULER_H */ diff --git a/src/serial_io.c b/src/serial_io.c index 9f874ca8c56c853816c0b52a719267481f443bc4..5e976335e241d07b2fc364e0d5fd2f6618765854 100644 --- a/src/serial_io.c +++ b/src/serial_io.c @@ -153,7 +153,37 @@ void readArray(hid_t grp, const struct io_props props, size_t N, for (size_t i = 0; i < num_elements; ++i) temp_d[i] *= factor; } else { float* temp_f = temp; - for (size_t i = 0; i < num_elements; ++i) temp_f[i] *= factor; + +#ifdef SWIFT_DEBUG_CHECKS + float maximum = 0.f; + float minimum = FLT_MAX; +#endif + + /* Loop that converts the Units */ + for (size_t i = 0; i < num_elements; ++i) { + +#ifdef SWIFT_DEBUG_CHECKS + /* Find the absolute minimum and maximum values */ + const float abstemp_f = fabsf(temp_f[i]); + if (abstemp_f != 0.f) { + maximum = max(maximum, abstemp_f); + minimum = min(minimum, abstemp_f); + } +#endif + + /* Convert the float units */ + temp_f[i] *= factor; + } + +#ifdef SWIFT_DEBUG_CHECKS + /* The two possible errors: larger than float or smaller + * than float precision. */ + if (factor * maximum > FLT_MAX) { + error("Unit conversion results in numbers larger than floats"); + } else if (factor * minimum < FLT_MIN) { + error("Numbers smaller than float precision"); + } +#endif } } @@ -270,8 +300,9 @@ void prepareArray(const struct engine* e, hid_t grp, char* fileName, if (h_data < 0) error("Error while creating dataspace '%s'.", props.name); /* Write XMF description for this data set */ - xmf_write_line(xmfFile, fileName, partTypeGroupName, props.name, N_total, - props.dimension, props.type); + if (xmfFile != NULL) + xmf_write_line(xmfFile, fileName, partTypeGroupName, props.name, N_total, + props.dimension, props.type); /* Write unit conversion factors for this data set */ char buffer[FIELD_BUFFER_SIZE]; @@ -398,7 +429,6 @@ void writeArray(const struct engine* e, hid_t grp, char* fileName, * @param Ngas (output) The number of #part read from the file on that node. * @param Ngparts (output) The number of #gpart read from the file on that node. * @param Nstars (output) The number of #spart read from the file on that node. - * @param periodic (output) 1 if the volume is periodic, 0 if not. * @param flag_entropy (output) 1 if the ICs contained Entropy in the * InternalEnergy field * @param with_hydro Are we reading gas particles ? @@ -427,11 +457,11 @@ void writeArray(const struct engine* e, hid_t grp, char* fileName, void read_ic_serial(char* fileName, const struct unit_system* internal_units, double dim[3], struct part** parts, struct gpart** gparts, struct spart** sparts, size_t* Ngas, size_t* Ngparts, - size_t* Nstars, int* periodic, int* flag_entropy, - int with_hydro, int with_gravity, int with_stars, - int cleanup_h, int cleanup_sqrt_a, double h, double a, - int mpi_rank, int mpi_size, MPI_Comm comm, MPI_Info info, - int n_threads, int dry_run) { + size_t* Nstars, int* flag_entropy, int with_hydro, + int with_gravity, int with_stars, int cleanup_h, + int cleanup_sqrt_a, double h, double a, int mpi_rank, + int mpi_size, MPI_Comm comm, MPI_Info info, int n_threads, + int dry_run) { hid_t h_file = 0, h_grp = 0; /* GADGET has only cubic boxes (in cosmological mode) */ @@ -455,17 +485,6 @@ void read_ic_serial(char* fileName, const struct unit_system* internal_units, if (h_file < 0) error("Error while opening file '%s' for initial read.", fileName); - /* Open header to read simulation properties */ - /* message("Reading runtime parameters..."); */ - h_grp = H5Gopen(h_file, "/RuntimePars", H5P_DEFAULT); - if (h_grp < 0) error("Error while opening runtime parameters\n"); - - /* Read the relevant information */ - io_read_attribute(h_grp, "PeriodicBoundariesOn", INT, periodic); - - /* Close runtime parameters */ - H5Gclose(h_grp); - /* Open header to read simulation properties */ /* message("Reading file header..."); */ h_grp = H5Gopen(h_file, "/Header", H5P_DEFAULT); @@ -560,7 +579,6 @@ void read_ic_serial(char* fileName, const struct unit_system* internal_units, /* Now need to broadcast that information to all ranks. */ MPI_Bcast(flag_entropy, 1, MPI_INT, 0, comm); - MPI_Bcast(periodic, 1, MPI_INT, 0, comm); MPI_Bcast(&N_total, swift_type_count, MPI_LONG_LONG_INT, 0, comm); MPI_Bcast(dim, 3, MPI_DOUBLE, 0, comm); MPI_Bcast(ic_units, sizeof(struct unit_system), MPI_BYTE, 0, comm); @@ -739,22 +757,29 @@ void write_output_serial(struct engine* e, const char* baseName, int mpi_size, MPI_Comm comm, MPI_Info info) { hid_t h_file = 0, h_grp = 0; - const size_t Ngas = e->s->nr_parts; - const size_t Nstars = e->s->nr_sparts; - const size_t Ntot = e->s->nr_gparts; int periodic = e->s->periodic; int numFiles = 1; const struct part* parts = e->s->parts; const struct xpart* xparts = e->s->xparts; const struct gpart* gparts = e->s->gparts; - struct gpart* dmparts = NULL; const struct spart* sparts = e->s->sparts; - const struct cooling_function_data* cooling = e->cooling_func; struct swift_params* params = e->parameter_file; FILE* xmfFile = 0; - /* Number of unassociated gparts */ - const size_t Ndm = Ntot > 0 ? Ntot - (Ngas + Nstars) : 0; + /* Number of particles currently in the arrays */ + const size_t Ntot = e->s->nr_gparts; + const size_t Ngas = e->s->nr_parts; + const size_t Nstars = e->s->nr_sparts; + // const size_t Nbaryons = Ngas + Nstars; + // 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 Nbaryons_written = Ngas_written + Nstars_written; + const size_t Ndm_written = + Ntot_written > 0 ? Ntot_written - Nbaryons_written : 0; /* File name */ char fileName[FILENAME_BUFFER_SIZE]; @@ -766,7 +791,8 @@ void write_output_serial(struct engine* e, const char* baseName, e->snapshot_output_count); /* Compute offset in the file and total number of particles */ - size_t N[swift_type_count] = {Ngas, Ndm, 0, 0, Nstars, 0}; + size_t N[swift_type_count] = { + Ngas_written, Ndm_written, 0, 0, Nstars_written, 0}; long long N_total[swift_type_count] = {0}; long long offset[swift_type_count] = {0}; MPI_Exscan(&N, &offset, swift_type_count, MPI_LONG_LONG_INT, MPI_SUM, comm); @@ -870,7 +896,7 @@ void write_output_serial(struct engine* e, const char* baseName, h_grp = H5Gcreate(h_file, "/SubgridScheme", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); if (h_grp < 0) error("Error while creating subgrid group"); - cooling_write_flavour(h_grp); + cooling_write_flavour(h_grp, e->cooling_func); chemistry_write_flavour(h_grp); H5Gclose(h_grp); @@ -1012,36 +1038,99 @@ void write_output_serial(struct engine* e, const char* baseName, struct io_props list[100]; size_t Nparticles = 0; + struct part* parts_written = NULL; + struct xpart* xparts_written = NULL; + struct gpart* gparts_written = NULL; + struct spart* sparts_written = NULL; + /* Write particle fields from the particle structure */ switch (ptype) { - case swift_type_gas: - 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, cooling); - break; + case swift_type_gas: { + if (Ngas == Ngas_written) { + + /* No inhibted particles: easy case */ + 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); + } else { + + /* Ok, we need to fish out the particles we want */ + Nparticles = Ngas_written; + + /* Allocate temporary arrays */ + if (posix_memalign((void**)&parts_written, part_align, + Ngas_written * sizeof(struct part)) != 0) + error("Error while allocating temporart memory for parts"); + if (posix_memalign((void**)&xparts_written, xpart_align, + Ngas_written * sizeof(struct xpart)) != 0) + error("Error while allocating temporart memory for xparts"); + + /* Collect the particles we want to write */ + io_collect_parts_to_write(parts, xparts, parts_written, + xparts_written, Ngas, Ngas_written); + + /* Select the fields to write */ + hydro_write_particles(parts_written, xparts_written, list, + &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); + } + } break; - case swift_type_dark_matter: - /* Allocate temporary array */ - if (posix_memalign((void*)&dmparts, gpart_align, - Ndm * sizeof(struct gpart)) != 0) - error("Error while allocating temporart memory for DM particles"); - bzero(dmparts, Ndm * sizeof(struct gpart)); - - /* Collect the DM particles from gpart */ - io_collect_dm_gparts(gparts, Ntot, dmparts, Ndm); - - /* Write DM particles */ - Nparticles = Ndm; - darkmatter_write_particles(dmparts, list, &num_fields); - break; + case swift_type_dark_matter: { + if (Ntot == Ndm_written) { - case swift_type_stars: - Nparticles = Nstars; - stars_write_particles(sparts, list, &num_fields); - break; + /* This is a DM-only run without inhibited particles */ + Nparticles = Ntot; + darkmatter_write_particles(gparts, list, &num_fields); + } else { + + /* Ok, we need to fish out the particles we want */ + Nparticles = Ndm_written; + + /* Allocate temporary array */ + if (posix_memalign((void**)&gparts_written, gpart_align, + Ndm_written * sizeof(struct gpart)) != 0) + error("Error while allocating temporart memory for gparts"); + + /* Collect the non-inhibited DM particles from gpart */ + io_collect_gparts_to_write(gparts, gparts_written, Ntot, + Ndm_written); + + /* Write DM particles */ + darkmatter_write_particles(gparts_written, list, &num_fields); + } + } break; + + case swift_type_stars: { + if (Nstars == Nstars_written) { + + /* No inhibted particles: easy case */ + Nparticles = Nstars; + stars_write_particles(sparts, list, &num_fields); + } else { + + /* Ok, we need to fish out the particles we want */ + Nparticles = Nstars_written; + + /* Allocate temporary arrays */ + if (posix_memalign((void**)&sparts_written, spart_align, + Nstars_written * sizeof(struct spart)) != 0) + error("Error while allocating temporart memory for sparts"); + + /* Collect the particles we want to write */ + io_collect_sparts_to_write(sparts, sparts_written, Nstars, + Nstars_written); + + /* Select the fields to write */ + stars_write_particles(sparts, list, &num_fields); + } + } break; default: error("Particle Type %d not yet supported. Aborting", ptype); @@ -1063,10 +1152,10 @@ void write_output_serial(struct engine* e, const char* baseName, } /* Free temporary array */ - if (dmparts) { - free(dmparts); - dmparts = 0; - } + if (parts_written) free(parts_written); + if (xparts_written) free(xparts_written); + if (gparts_written) free(gparts_written); + if (sparts_written) free(sparts_written); /* Close particle group */ H5Gclose(h_grp); diff --git a/src/serial_io.h b/src/serial_io.h index 6644e34bb32bcbd63250f25502563155eda0a293..07df76fe869fa0612bba5cf953faadd8bc63f29e 100644 --- a/src/serial_io.h +++ b/src/serial_io.h @@ -31,23 +31,30 @@ /* Includes. */ #include "engine.h" +#include "io_properties.h" #include "part.h" #include "units.h" void read_ic_serial(char* fileName, const struct unit_system* internal_units, double dim[3], struct part** parts, struct gpart** gparts, struct spart** sparts, size_t* Ngas, size_t* Ngparts, - size_t* Nstars, int* periodic, int* flag_entropy, - int with_hydro, int with_gravity, int with_stars, - int cleanup_h, int cleanup_sqrt_a, double h, double a, - int mpi_rank, int mpi_size, MPI_Comm comm, MPI_Info info, - int nr_threads, int dry_run); + size_t* Nstars, int* flag_entropy, int with_hydro, + int with_gravity, int with_stars, int cleanup_h, + int cleanup_sqrt_a, double h, double a, int mpi_rank, + int mpi_size, MPI_Comm comm, MPI_Info info, int nr_threads, + int dry_run); void write_output_serial(struct engine* e, const char* baseName, const struct unit_system* internal_units, const struct unit_system* snapshot_units, int mpi_rank, int mpi_size, MPI_Comm comm, MPI_Info info); +void writeArray(const struct engine* e, hid_t grp, char* fileName, + FILE* xmfFile, char* partTypeGroupName, + const struct io_props props, size_t N, long long N_total, + int mpi_rank, long long offset, + const struct unit_system* internal_units, + const struct unit_system* snapshot_units); #endif #endif /* SWIFT_SERIAL_IO_H */ diff --git a/src/single_io.c b/src/single_io.c index 33981b6cfa36bd01248b6ba87c28466cb41e0947..99f016809d11abc4f9f31695306850d82fd56c84 100644 --- a/src/single_io.c +++ b/src/single_io.c @@ -127,9 +127,40 @@ void readArray(hid_t h_grp, const struct io_props props, size_t N, if (io_is_double_precision(props.type)) { double* temp_d = (double*)temp; for (size_t i = 0; i < num_elements; ++i) temp_d[i] *= unit_factor; + } else { float* temp_f = (float*)temp; - for (size_t i = 0; i < num_elements; ++i) temp_f[i] *= unit_factor; + +#ifdef SWIFT_DEBUG_CHECKS + float maximum = 0.f; + float minimum = FLT_MAX; +#endif + + /* Loop that converts the Units */ + for (size_t i = 0; i < num_elements; ++i) { + +#ifdef SWIFT_DEBUG_CHECKS + /* Find the absolute minimum and maximum values */ + const float abstemp_f = fabsf(temp_f[i]); + if (abstemp_f != 0.f) { + maximum = max(maximum, abstemp_f); + minimum = min(minimum, abstemp_f); + } +#endif + + /* Convert the float units */ + temp_f[i] *= unit_factor; + } + +#ifdef SWIFT_DEBUG_CHECKS + /* The two possible errors: larger than float or smaller + * than float precision. */ + if (unit_factor * maximum > FLT_MAX) { + error("Unit conversion results in numbers larger than floats"); + } else if (unit_factor * minimum < FLT_MIN) { + error("Numbers smaller than float precision"); + } +#endif } } @@ -281,8 +312,9 @@ void writeArray(const struct engine* e, hid_t grp, char* fileName, if (h_err < 0) error("Error while writing data array '%s'.", props.name); /* Write XMF description for this data set */ - xmf_write_line(xmfFile, fileName, partTypeGroupName, props.name, N, - props.dimension, props.type); + if (xmfFile != NULL) + xmf_write_line(xmfFile, fileName, partTypeGroupName, props.name, N, + props.dimension, props.type); /* Write unit conversion factors for this data set */ char buffer[FIELD_BUFFER_SIZE]; @@ -314,7 +346,6 @@ void writeArray(const struct engine* e, hid_t grp, char* fileName, * @param Ngas (output) number of Gas particles read. * @param Ngparts (output) The number of #gpart read. * @param Nstars (output) The number of #spart read. - * @param periodic (output) 1 if the volume is periodic, 0 if not. * @param flag_entropy (output) 1 if the ICs contained Entropy in the * InternalEnergy field * @param with_hydro Are we reading gas particles ? @@ -339,10 +370,10 @@ void read_ic_single(const char* fileName, const struct unit_system* internal_units, double dim[3], struct part** parts, struct gpart** gparts, struct spart** sparts, size_t* Ngas, size_t* Ngparts, - size_t* Nstars, int* periodic, int* flag_entropy, - int with_hydro, int with_gravity, int with_stars, - int cleanup_h, int cleanup_sqrt_a, double h, double a, - int n_threads, int dry_run) { + size_t* Nstars, int* flag_entropy, int with_hydro, + int with_gravity, int with_stars, int cleanup_h, + int cleanup_sqrt_a, double h, double a, int n_threads, + int dry_run) { hid_t h_file = 0, h_grp = 0; /* GADGET has only cubic boxes (in cosmological mode) */ @@ -359,17 +390,6 @@ void read_ic_single(const char* fileName, h_file = H5Fopen(fileName, H5F_ACC_RDONLY, H5P_DEFAULT); if (h_file < 0) error("Error while opening file '%s'.", fileName); - /* Open header to read simulation properties */ - /* message("Reading runtime parameters..."); */ - h_grp = H5Gopen(h_file, "/RuntimePars", H5P_DEFAULT); - if (h_grp < 0) error("Error while opening runtime parameters\n"); - - /* Read the relevant information */ - io_read_attribute(h_grp, "PeriodicBoundariesOn", INT, periodic); - - /* Close runtime parameters */ - H5Gclose(h_grp); - /* Open header to read simulation properties */ /* message("Reading file header..."); */ h_grp = H5Gopen(h_file, "/Header", H5P_DEFAULT); @@ -603,24 +623,36 @@ void write_output_single(struct engine* e, const char* baseName, const struct unit_system* snapshot_units) { hid_t h_file = 0, h_grp = 0; - const size_t Ngas = e->s->nr_parts; - const size_t Nstars = e->s->nr_sparts; - const size_t Ntot = e->s->nr_gparts; int periodic = e->s->periodic; int numFiles = 1; const struct part* parts = e->s->parts; const struct xpart* xparts = e->s->xparts; const struct gpart* gparts = e->s->gparts; - struct gpart* dmparts = NULL; const struct spart* sparts = e->s->sparts; - const struct cooling_function_data* cooling = e->cooling_func; struct swift_params* params = e->parameter_file; - /* Number of unassociated gparts */ - const size_t Ndm = Ntot > 0 ? Ntot - (Ngas + Nstars) : 0; - - long long N_total[swift_type_count] = { - (long long)Ngas, (long long)Ndm, 0, 0, (long long)Nstars, 0}; + /* Number of particles currently in the arrays */ + const size_t Ntot = e->s->nr_gparts; + const size_t Ngas = e->s->nr_parts; + const size_t Nstars = e->s->nr_sparts; + // const size_t Nbaryons = Ngas + Nstars; + // 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 Nbaryons_written = Ngas_written + Nstars_written; + const size_t Ndm_written = + Ntot_written > 0 ? Ntot_written - Nbaryons_written : 0; + + /* Format things in a Gadget-friendly array */ + long long N_total[swift_type_count] = {(long long)Ngas_written, + (long long)Ndm_written, + 0, + 0, + (long long)Nstars_written, + 0}; /* File name */ char fileName[FILENAME_BUFFER_SIZE]; @@ -720,7 +752,7 @@ void write_output_single(struct engine* e, const char* baseName, h_grp = H5Gcreate(h_file, "/SubgridScheme", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); if (h_grp < 0) error("Error while creating subgrid group"); - cooling_write_flavour(h_grp); + cooling_write_flavour(h_grp, e->cooling_func); chemistry_write_flavour(h_grp); H5Gclose(h_grp); @@ -828,36 +860,98 @@ void write_output_single(struct engine* e, const char* baseName, struct io_props list[100]; size_t N = 0; + struct part* parts_written = NULL; + struct xpart* xparts_written = NULL; + struct gpart* gparts_written = NULL; + struct spart* sparts_written = NULL; + /* Write particle fields from the particle structure */ switch (ptype) { - case swift_type_gas: - 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, cooling); - break; + case swift_type_gas: { + if (Ngas == Ngas_written) { + + /* No inhibted particles: easy case */ + 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); + } else { + + /* Ok, we need to fish out the particles we want */ + N = Ngas_written; + + /* Allocate temporary arrays */ + if (posix_memalign((void**)&parts_written, part_align, + Ngas_written * sizeof(struct part)) != 0) + error("Error while allocating temporart memory for parts"); + if (posix_memalign((void**)&xparts_written, xpart_align, + Ngas_written * sizeof(struct xpart)) != 0) + error("Error while allocating temporart memory for xparts"); + + /* Collect the particles we want to write */ + io_collect_parts_to_write(parts, xparts, parts_written, + xparts_written, Ngas, Ngas_written); + + /* Select the fields to write */ + hydro_write_particles(parts_written, xparts_written, list, + &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); + } + } break; - case swift_type_dark_matter: - /* Allocate temporary array */ - if (posix_memalign((void**)&dmparts, gpart_align, - Ndm * sizeof(struct gpart)) != 0) - error("Error while allocating temporart memory for DM particles"); - bzero(dmparts, Ndm * sizeof(struct gpart)); - - /* Collect the DM particles from gpart */ - io_collect_dm_gparts(gparts, Ntot, dmparts, Ndm); - - /* Write DM particles */ - N = Ndm; - darkmatter_write_particles(dmparts, list, &num_fields); - break; + case swift_type_dark_matter: { + if (Ntot == Ndm_written) { - case swift_type_stars: - N = Nstars; - stars_write_particles(sparts, list, &num_fields); - break; + /* This is a DM-only run without inhibited particles */ + N = Ntot; + darkmatter_write_particles(gparts, list, &num_fields); + } else { + + /* Ok, we need to fish out the particles we want */ + N = Ndm_written; + + /* Allocate temporary array */ + if (posix_memalign((void**)&gparts_written, gpart_align, + Ndm_written * sizeof(struct gpart)) != 0) + error("Error while allocating temporart memory for gparts"); + + /* Collect the non-inhibited DM particles from gpart */ + io_collect_gparts_to_write(gparts, gparts_written, Ntot, Ndm_written); + + /* Write DM particles */ + darkmatter_write_particles(gparts_written, list, &num_fields); + } + } break; + + case swift_type_stars: { + if (Nstars == Nstars_written) { + + /* No inhibted particles: easy case */ + N = Nstars; + stars_write_particles(sparts, list, &num_fields); + } else { + + /* Ok, we need to fish out the particles we want */ + N = Nstars_written; + + /* Allocate temporary arrays */ + if (posix_memalign((void**)&sparts_written, spart_align, + Nstars_written * sizeof(struct spart)) != 0) + error("Error while allocating temporart memory for sparts"); + + /* Collect the particles we want to write */ + io_collect_sparts_to_write(sparts, sparts_written, Nstars, + Nstars_written); + + /* Select the fields to write */ + stars_write_particles(sparts, list, &num_fields); + } + } break; default: error("Particle Type %d not yet supported. Aborting", ptype); @@ -877,11 +971,11 @@ void write_output_single(struct engine* e, const char* baseName, internal_units, snapshot_units); } - /* Free temporary array */ - if (dmparts) { - free(dmparts); - dmparts = NULL; - } + /* Free temporary arrays */ + if (parts_written) free(parts_written); + if (xparts_written) free(xparts_written); + if (gparts_written) free(gparts_written); + if (sparts_written) free(sparts_written); /* Close particle group */ H5Gclose(h_grp); diff --git a/src/single_io.h b/src/single_io.h index a0ce8370dfa1009f28e7c399b3f1db345c23de49..62285c3da210243e76347f33780146604673656f 100644 --- a/src/single_io.h +++ b/src/single_io.h @@ -26,6 +26,7 @@ /* Includes. */ #include "engine.h" +#include "io_properties.h" #include "part.h" #include "units.h" @@ -33,15 +34,21 @@ void read_ic_single(const char* fileName, const struct unit_system* internal_units, double dim[3], struct part** parts, struct gpart** gparts, struct spart** sparts, size_t* Ngas, size_t* Ndm, - size_t* Nstars, int* periodic, int* flag_entropy, - int with_hydro, int with_gravity, int with_stars, - int cleanup_h, int cleanup_sqrt_a, double h, double a, - int nr_threads, int dry_run); + size_t* Nstars, int* flag_entropy, int with_hydro, + int with_gravity, int with_stars, int cleanup_h, + int cleanup_sqrt_a, double h, double a, int nr_threads, + int dry_run); void write_output_single(struct engine* e, const char* baseName, const struct unit_system* internal_units, const struct unit_system* snapshot_units); +void writeArray(const struct engine* e, hid_t grp, char* fileName, + FILE* xmfFile, char* partTypeGroupName, + const struct io_props props, size_t N, + const struct unit_system* internal_units, + const struct unit_system* snapshot_units); + #endif /* HAVE_HDF5 && !WITH_MPI */ #endif /* SWIFT_SINGLE_IO_H */ diff --git a/src/space.c b/src/space.c index 79097fbf22dcbe2477328d113592e86d26ed1f08..e11daf80c26e25e3b13b5fbdc33ea547fbb96839 100644 --- a/src/space.c +++ b/src/space.c @@ -102,9 +102,11 @@ struct parallel_sort { */ struct index_data { struct space *s; - struct cell *cells; int *ind; int *cell_counts; + int count_inhibited_part; + int count_inhibited_gpart; + int count_inhibited_spart; }; /** @@ -135,15 +137,15 @@ void space_rebuild_recycle_rec(struct space *s, struct cell *c, *cell_rec_begin = c->progeny[k]; if (s->gravity) { - c->progeny[k]->multipole->next = *multipole_rec_begin; - *multipole_rec_begin = c->progeny[k]->multipole; + 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) *multipole_rec_end = *multipole_rec_begin; - c->progeny[k]->multipole = NULL; + c->progeny[k]->grav.multipole = NULL; c->progeny[k] = NULL; } } @@ -164,79 +166,86 @@ void space_rebuild_recycle_mapper(void *map_data, int num_elements, if (cell_rec_begin != NULL) space_recycle_list(s, cell_rec_begin, cell_rec_end, multipole_rec_begin, multipole_rec_end); - c->sorts = NULL; + c->hydro.sorts = NULL; c->nr_tasks = 0; - c->nr_mm_tasks = 0; - c->density = NULL; - c->gradient = NULL; - c->force = NULL; - c->grav = NULL; - c->grav_mm = NULL; - c->dx_max_part = 0.0f; - c->dx_max_sort = 0.0f; - c->sorted = 0; - c->count = 0; - c->gcount = 0; - c->scount = 0; - c->init_grav = NULL; - c->init_grav_out = NULL; - c->extra_ghost = NULL; - c->ghost_in = NULL; - c->ghost_out = NULL; - c->ghost = NULL; - c->stars_ghost_in = NULL; - c->stars_ghost_out = NULL; - c->stars_ghost = NULL; - c->stars_density = NULL; + c->grav.nr_mm_tasks = 0; + c->hydro.density = NULL; + c->hydro.gradient = NULL; + c->hydro.force = NULL; + c->grav.grav = NULL; + c->grav.mm = NULL; + c->hydro.dx_max_part = 0.0f; + c->hydro.dx_max_sort = 0.0f; + c->stars.dx_max_part = 0.f; + c->hydro.sorted = 0; + c->hydro.count = 0; + c->hydro.updated = 0; + c->hydro.inhibited = 0; + c->grav.count = 0; + c->grav.updated = 0; + c->grav.inhibited = 0; + c->stars.count = 0; + c->stars.updated = 0; + c->stars.inhibited = 0; + c->grav.init = NULL; + c->grav.init_out = NULL; + c->hydro.extra_ghost = NULL; + c->hydro.ghost_in = NULL; + c->hydro.ghost_out = NULL; + c->hydro.ghost = NULL; + c->stars.ghost_in = NULL; + c->stars.ghost_out = NULL; + c->stars.ghost = NULL; + c->stars.density = NULL; c->kick1 = NULL; c->kick2 = NULL; c->timestep = NULL; c->end_force = NULL; - c->drift_part = NULL; - c->drift_gpart = NULL; - c->cooling = NULL; + c->hydro.drift = NULL; + c->grav.drift = NULL; + c->hydro.cooling = NULL; c->sourceterms = NULL; - c->grav_long_range = NULL; - c->grav_down_in = NULL; - c->grav_down = NULL; - c->grav_mesh = NULL; + c->grav.long_range = NULL; + c->grav.down_in = NULL; + c->grav.down = NULL; + c->grav.mesh = NULL; c->super = c; - c->super_hydro = c; - c->super_gravity = c; - c->parts = NULL; - c->xparts = NULL; - c->gparts = NULL; - c->sparts = NULL; - c->do_sub_sort = 0; - c->do_grav_sub_drift = 0; - c->do_sub_drift = 0; - c->ti_hydro_end_min = -1; - c->ti_hydro_end_max = -1; - c->ti_gravity_end_min = -1; - c->ti_gravity_end_max = -1; + c->hydro.super = c; + c->grav.super = c; + c->hydro.parts = NULL; + c->hydro.xparts = NULL; + c->grav.parts = NULL; + c->stars.parts = NULL; + c->hydro.do_sub_sort = 0; + c->grav.do_sub_drift = 0; + c->hydro.do_sub_drift = 0; + c->hydro.ti_end_min = -1; + c->hydro.ti_end_max = -1; + c->grav.ti_end_min = -1; + c->grav.ti_end_max = -1; #ifdef SWIFT_DEBUG_CHECKS c->cellID = 0; #endif - if (s->gravity) bzero(c->multipole, sizeof(struct gravity_tensors)); + if (s->gravity) bzero(c->grav.multipole, sizeof(struct gravity_tensors)); for (int i = 0; i < 13; i++) - if (c->sort[i] != NULL) { - free(c->sort[i]); - c->sort[i] = NULL; + if (c->hydro.sort[i] != NULL) { + free(c->hydro.sort[i]); + c->hydro.sort[i] = NULL; } #if WITH_MPI - c->tag = -1; - - c->recv_xv = NULL; - c->recv_rho = NULL; - c->recv_gradient = NULL; - c->recv_grav = NULL; - c->recv_ti = NULL; - - c->send_xv = NULL; - c->send_rho = NULL; - c->send_gradient = NULL; - c->send_grav = NULL; - c->send_ti = NULL; + c->mpi.tag = -1; + + c->mpi.hydro.recv_xv = NULL; + c->mpi.hydro.recv_rho = NULL; + c->mpi.hydro.recv_gradient = NULL; + c->mpi.grav.recv = NULL; + c->mpi.recv_ti = NULL; + + c->mpi.hydro.send_xv = NULL; + c->mpi.hydro.send_rho = NULL; + c->mpi.hydro.send_gradient = NULL; + c->mpi.grav.send = NULL; + c->mpi.send_ti = NULL; #endif } } @@ -266,6 +275,7 @@ void space_free_cells(struct space *s) { void space_regrid(struct space *s, int verbose) { const size_t nr_parts = s->nr_parts; + const size_t nr_sparts = s->nr_sparts; const ticks tic = getticks(); const integertime_t ti_current = (s->e != NULL) ? s->e->ti_current : 0; @@ -273,24 +283,40 @@ void space_regrid(struct space *s, int verbose) { // tic = getticks(); float h_max = s->cell_min / kernel_gamma / space_stretch; if (nr_parts > 0) { - if (s->local_cells_top != NULL) { - for (int k = 0; k < s->nr_local_cells; ++k) { - const struct cell *c = &s->cells_top[s->local_cells_top[k]]; - if (c->h_max > h_max) { - h_max = s->cells_top[k].h_max; + + /* Can we use the list of local non-empty top-level cells? */ + if (s->local_cells_with_particles_top != NULL) { + for (int k = 0; k < s->nr_local_cells_with_particles; ++k) { + const struct cell *c = + &s->cells_top[s->local_cells_with_particles_top[k]]; + if (c->hydro.h_max > h_max) { + h_max = c->hydro.h_max; + } + if (c->stars.h_max > h_max) { + h_max = c->stars.h_max; } } + + /* Can we instead use all the top-level cells? */ } else if (s->cells_top != NULL) { for (int k = 0; k < s->nr_cells; k++) { const struct cell *c = &s->cells_top[k]; - if (c->nodeID == engine_rank && c->h_max > h_max) { - h_max = s->cells_top[k].h_max; + if (c->nodeID == engine_rank && c->hydro.h_max > h_max) { + h_max = c->hydro.h_max; + } + if (c->nodeID == engine_rank && c->stars.h_max > h_max) { + h_max = c->stars.h_max; } } + + /* Last option: run through the particles */ } else { for (size_t k = 0; k < nr_parts; k++) { if (s->parts[k].h > h_max) h_max = s->parts[k].h; } + for (size_t k = 0; k < nr_sparts; k++) { + if (s->sparts[k].h > h_max) h_max = s->sparts[k].h; + } } } @@ -382,6 +408,8 @@ void space_regrid(struct space *s, int verbose) { space_free_cells(s); free(s->local_cells_with_tasks_top); free(s->local_cells_top); + free(s->cells_with_particles_top); + free(s->local_cells_with_particles_top); free(s->cells_top); free(s->multipoles_top); } @@ -429,7 +457,7 @@ void space_regrid(struct space *s, int verbose) { /* Allocate the indices of local cells with tasks */ if (posix_memalign((void **)&s->local_cells_with_tasks_top, SWIFT_STRUCT_ALIGNMENT, s->nr_cells * sizeof(int)) != 0) - error("Failed to allocate indices of local top-level cells."); + error("Failed to allocate indices of local top-level cells with tasks."); bzero(s->local_cells_with_tasks_top, s->nr_cells * sizeof(int)); /* Allocate and initialise array of cell indices. */ @@ -439,15 +467,29 @@ void space_regrid(struct space *s, int verbose) { /* Set cell index into list of top-level cells. */ for(int i = 0; i < s->nr_cells; i++) s->cell_index[i] = i; + /* Allocate the indices of cells with particles */ + if (posix_memalign((void **)&s->cells_with_particles_top, + SWIFT_STRUCT_ALIGNMENT, s->nr_cells * sizeof(int)) != 0) + error("Failed to allocate indices of top-level cells with particles."); + bzero(s->cells_with_particles_top, s->nr_cells * sizeof(int)); + + /* Allocate the indices of local cells with particles */ + if (posix_memalign((void **)&s->local_cells_with_particles_top, + SWIFT_STRUCT_ALIGNMENT, s->nr_cells * sizeof(int)) != 0) + error( + "Failed to allocate indices of local top-level cells with " + "particles."); + bzero(s->local_cells_with_particles_top, s->nr_cells * sizeof(int)); + /* Set the cells' locks */ for (int k = 0; k < s->nr_cells; k++) { - if (lock_init(&s->cells_top[k].lock) != 0) + if (lock_init(&s->cells_top[k].hydro.lock) != 0) error("Failed to init spinlock for hydro."); - if (lock_init(&s->cells_top[k].glock) != 0) + if (lock_init(&s->cells_top[k].grav.plock) != 0) error("Failed to init spinlock for gravity."); - if (lock_init(&s->cells_top[k].mlock) != 0) + if (lock_init(&s->cells_top[k].grav.mlock) != 0) error("Failed to init spinlock for multipoles."); - if (lock_init(&s->cells_top[k].slock) != 0) + if (lock_init(&s->cells_top[k].stars.lock) != 0) error("Failed to init spinlock for stars."); } @@ -465,19 +507,20 @@ void space_regrid(struct space *s, int verbose) { c->width[2] = s->width[2]; c->dmin = dmin; c->depth = 0; - c->count = 0; - c->gcount = 0; - c->scount = 0; + c->split = 0; + c->hydro.count = 0; + c->grav.count = 0; + c->stars.count = 0; c->super = c; - c->super_hydro = c; - c->super_gravity = c; - c->ti_old_part = ti_current; - c->ti_old_gpart = ti_current; - c->ti_old_multipole = ti_current; + c->hydro.super = c; + c->grav.super = c; + c->hydro.ti_old_part = ti_current; + c->grav.ti_old_part = ti_current; + c->grav.ti_old_multipole = ti_current; #ifdef WITH_MPI - c->tag = -1; + c->mpi.tag = -1; #endif // WITH_MPI - if (s->gravity) c->multipole = &s->multipoles_top[cid]; + if (s->gravity) c->grav.multipole = &s->multipoles_top[cid]; #ifdef SWIFT_DEBUG_CHECKS c->cellID = -last_cell_id; last_cell_id++; @@ -558,10 +601,10 @@ void space_regrid(struct space *s, int verbose) { * @brief Re-build the cells as well as the tasks. * * @param s The #space in which to update the cells. + * @param repartitioned Did we just repartition? * @param verbose Print messages to stdout or not - * */ -void space_rebuild(struct space *s, int verbose) { +void space_rebuild(struct space *s, int repartitioned, int verbose) { const ticks tic = getticks(); @@ -577,6 +620,9 @@ void space_rebuild(struct space *s, int verbose) { 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; @@ -590,7 +636,8 @@ void space_rebuild(struct space *s, int verbose) { 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, cells_top, verbose); + space_parts_get_cell_index(s, ind, cell_part_counts, &count_inhibited_parts, + verbose); /* Run through the gravity particles and get their cell index. */ const size_t gind_size = s->size_gparts + 100; @@ -600,7 +647,8 @@ void space_rebuild(struct space *s, int verbose) { 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, cells_top, verbose); + 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; @@ -610,137 +658,202 @@ void space_rebuild(struct space *s, int verbose) { 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, cells_top, verbose); + space_sparts_get_cell_index(s, sind, cell_spart_counts, + &count_inhibited_sparts, verbose); + +#ifdef SWIFT_DEBUG_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 -#ifdef WITH_MPI const int local_nodeID = s->e->nodeID; - /* Move non-local parts to the end of the list. */ - for (size_t k = 0; k < nr_parts;) { - if (cells_top[ind[k]].nodeID != local_nodeID) { - nr_parts -= 1; - /* Swap the particle */ - memswap(&s->parts[k], &s->parts[nr_parts], sizeof(struct part)); - /* Swap the link with the gpart */ - if (s->parts[k].gpart != NULL) { - s->parts[k].gpart->id_or_neg_offset = -k; - } - if (s->parts[nr_parts].gpart != NULL) { - s->parts[nr_parts].gpart->id_or_neg_offset = -nr_parts; + /* 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) { + + /* One fewer particle */ + nr_parts -= 1; + + /* Swap the particle */ + memswap(&s->parts[k], &s->parts[nr_parts], sizeof(struct part)); + + /* Swap the link with the gpart */ + if (s->parts[k].gpart != NULL) { + s->parts[k].gpart->id_or_neg_offset = -k; + } + if (s->parts[nr_parts].gpart != NULL) { + s->parts[nr_parts].gpart->id_or_neg_offset = -nr_parts; + } + + /* 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)); + + } else { + /* Increment when not exchanging otherwise we need to retest "k".*/ + k++; } - /* 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)); - } else { - /* Increment when not exchanging otherwise we need to retest "k".*/ - k++; } } #ifdef SWIFT_DEBUG_CHECKS /* Check that all parts are in the correct places. */ + int check_count_inhibited_part = 0; for (size_t k = 0; k < nr_parts; k++) { - if (cells_top[ind[k]].nodeID != local_nodeID) { + if (ind[k] == -1 || cells_top[ind[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 (cells_top[ind[k]].nodeID == local_nodeID) { + if (ind[k] != -1 && cells_top[ind[k]].nodeID == local_nodeID) { error("Failed to remove local parts from send list"); } + if (ind[k] == -1) ++check_count_inhibited_part; } -#endif + if (check_count_inhibited_part != count_inhibited_parts) + error("Counts of inhibited particles do not match!"); +#endif /* SWIFT_DEBUG_CHECKS */ - /* Move non-local sparts to the end of the list. */ - for (size_t k = 0; k < nr_sparts;) { - if (cells_top[sind[k]].nodeID != local_nodeID) { - nr_sparts -= 1; - /* Swap the particle */ - memswap(&s->sparts[k], &s->sparts[nr_sparts], sizeof(struct spart)); - /* Swap the link with the gpart */ - if (s->sparts[k].gpart != NULL) { - s->sparts[k].gpart->id_or_neg_offset = -k; - } - if (s->sparts[nr_sparts].gpart != NULL) { - s->sparts[nr_sparts].gpart->id_or_neg_offset = -nr_sparts; + /* Move non-local sparts and inhibited sparts to the end of the list. */ + if (!repartitioned && (s->e->nr_nodes > 1 || count_inhibited_sparts > 0)) { + 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) { + + /* One fewer particle */ + nr_sparts -= 1; + + /* Swap the particle */ + memswap(&s->sparts[k], &s->sparts[nr_sparts], sizeof(struct spart)); + + /* Swap the link with the gpart */ + if (s->sparts[k].gpart != NULL) { + s->sparts[k].gpart->id_or_neg_offset = -k; + } + if (s->sparts[nr_sparts].gpart != NULL) { + s->sparts[nr_sparts].gpart->id_or_neg_offset = -nr_sparts; + } + + /* Swap the index */ + memswap(&sind[k], &sind[nr_sparts], sizeof(int)); + + } else { + /* Increment when not exchanging otherwise we need to retest "k".*/ + k++; } - /* Swap the index */ - memswap(&sind[k], &sind[nr_sparts], sizeof(int)); - } else { - /* Increment when not exchanging otherwise we need to retest "k".*/ - k++; } } #ifdef SWIFT_DEBUG_CHECKS - /* Check that all sparts are in the correct place (untested). */ + /* Check that all sparts are in the correct place. */ + int check_count_inhibited_spart = 0; for (size_t k = 0; k < nr_sparts; k++) { - if (cells_top[sind[k]].nodeID != local_nodeID) { + if (sind[k] == -1 || cells_top[sind[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 (cells_top[sind[k]].nodeID == local_nodeID) { + if (sind[k] != -1 && cells_top[sind[k]].nodeID == local_nodeID) { error("Failed to remove local sparts from send list"); } + if (sind[k] == -1) ++check_count_inhibited_spart; } -#endif + if (check_count_inhibited_spart != count_inhibited_sparts) + error("Counts of inhibited s-particles do not match!"); +#endif /* SWIFT_DEBUG_CHECKS */ - /* Move non-local gparts to the end of the list. */ - for (size_t k = 0; k < nr_gparts;) { - if (cells_top[gind[k]].nodeID != local_nodeID) { - nr_gparts -= 1; - /* Swap the particle */ - memswap(&s->gparts[k], &s->gparts[nr_gparts], sizeof(struct gpart)); - /* Swap the link with part/spart */ - if (s->gparts[k].type == swift_type_gas) { - s->parts[-s->gparts[k].id_or_neg_offset].gpart = &s->gparts[k]; - } else if (s->gparts[k].type == swift_type_stars) { - s->sparts[-s->gparts[k].id_or_neg_offset].gpart = &s->gparts[k]; - } - if (s->gparts[nr_gparts].type == swift_type_gas) { - s->parts[-s->gparts[nr_gparts].id_or_neg_offset].gpart = - &s->gparts[nr_gparts]; - } else if (s->gparts[nr_gparts].type == swift_type_stars) { - s->sparts[-s->gparts[nr_gparts].id_or_neg_offset].gpart = - &s->gparts[nr_gparts]; + /* Move non-local gparts and inhibited parts to the end of the list. */ + if (!repartitioned && (s->e->nr_nodes > 1 || count_inhibited_gparts > 0)) { + 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) { + + /* One fewer particle */ + nr_gparts -= 1; + + /* Swap the particle */ + memswap(&s->gparts[k], &s->gparts[nr_gparts], sizeof(struct gpart)); + + /* Swap the link with part/spart */ + if (s->gparts[k].type == swift_type_gas) { + s->parts[-s->gparts[k].id_or_neg_offset].gpart = &s->gparts[k]; + } else if (s->gparts[k].type == swift_type_stars) { + s->sparts[-s->gparts[k].id_or_neg_offset].gpart = &s->gparts[k]; + } + if (s->gparts[nr_gparts].type == swift_type_gas) { + s->parts[-s->gparts[nr_gparts].id_or_neg_offset].gpart = + &s->gparts[nr_gparts]; + } else if (s->gparts[nr_gparts].type == swift_type_stars) { + s->sparts[-s->gparts[nr_gparts].id_or_neg_offset].gpart = + &s->gparts[nr_gparts]; + } + + /* Swap the index */ + memswap(&gind[k], &gind[nr_gparts], sizeof(int)); + } else { + /* Increment when not exchanging otherwise we need to retest "k".*/ + k++; } - /* Swap the index */ - memswap(&gind[k], &gind[nr_gparts], sizeof(int)); - } else { - /* Increment when not exchanging otherwise we need to retest "k".*/ - k++; } } #ifdef SWIFT_DEBUG_CHECKS - /* Check that all gparts are in the correct place (untested). */ + /* Check that all gparts are in the correct place. */ + int check_count_inhibited_gpart = 0; for (size_t k = 0; k < nr_gparts; k++) { - if (cells_top[gind[k]].nodeID != local_nodeID) { + if (gind[k] == -1 || cells_top[gind[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 (cells_top[gind[k]].nodeID == local_nodeID) { + if (gind[k] != -1 && cells_top[gind[k]].nodeID == local_nodeID) { error("Failed to remove local gparts from send list"); } + if (gind[k] == -1) ++check_count_inhibited_gpart; } -#endif + if (check_count_inhibited_gpart != count_inhibited_gparts) + error("Counts of inhibited g-particles do not match!"); +#endif /* SWIFT_DEBUG_CHECKS */ + +#ifdef WITH_MPI /* Exchange the strays, note that this potentially re-allocates - the parts arrays. */ - 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); - - /* 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; + the parts arrays. This can be skipped if we just repartitioned aspace + there should be no strays */ + 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); + + /* 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) + error("Number of parts changing after repartition"); + if (s->nr_sparts != nr_sparts) + error("Number of sparts changing after repartition"); + if (s->nr_gparts != nr_gparts) + error("Number of gparts changing after repartition"); +#endif + } /* Clear non-local cell counts. */ for (int k = 0; k < s->nr_cells; k++) { @@ -802,6 +915,12 @@ void space_rebuild(struct space *s, int verbose) { } nr_sparts = s->nr_sparts; +#else /* WITH_MPI */ + + /* Update the part and spart counters */ + s->nr_parts = nr_parts; + s->nr_sparts = nr_sparts; + #endif /* WITH_MPI */ /* Sort the parts according to their cells. */ @@ -814,6 +933,9 @@ void space_rebuild(struct space *s, int verbose) { for (size_t k = 0; k < nr_parts; k++) { const struct part *p = &s->parts[k]; + if (p->time_bin == time_bin_inhibited) + error("Inhibited particle sorted into a cell!"); + /* New cell index */ const int new_ind = cell_getid(s->cdim, p->x[0] * s->iwidth[0], p->x[1] * s->iwidth[1], @@ -830,7 +952,7 @@ void space_rebuild(struct space *s, int verbose) { p->x[2] < c->loc[2] || p->x[2] > c->loc[2] + c->width[2]) error("part not sorted into the right top-level cell!"); } -#endif +#endif /* SWIFT_DEBUG_CHECKS */ /* Sort the sparts according to their cells. */ if (nr_sparts > 0) @@ -841,6 +963,9 @@ void space_rebuild(struct space *s, int verbose) { for (size_t k = 0; k < nr_sparts; k++) { const struct spart *sp = &s->sparts[k]; + if (sp->time_bin == time_bin_inhibited) + error("Inhibited particle sorted into a cell!"); + /* New cell index */ const int new_sind = cell_getid(s->cdim, sp->x[0] * s->iwidth[0], sp->x[1] * s->iwidth[1], @@ -857,14 +982,14 @@ void space_rebuild(struct space *s, int verbose) { sp->x[2] < c->loc[2] || sp->x[2] > c->loc[2] + c->width[2]) error("spart not sorted into the right top-level cell!"); } -#endif +#endif /* SWIFT_DEBUG_CHECKS */ /* Extract the cell counts from the sorted indices. */ size_t last_index = 0; ind[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]].count = k - last_index + 1; + cells_top[ind[k]].hydro.count = k - last_index + 1; last_index = k + 1; } } @@ -874,7 +999,7 @@ void space_rebuild(struct space *s, int verbose) { sind[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]].scount = k - last_sindex + 1; + cells_top[sind[k]].stars.count = k - last_sindex + 1; last_sindex = k + 1; } } @@ -911,8 +1036,18 @@ void space_rebuild(struct space *s, int verbose) { } nr_gparts = s->nr_gparts; +#else /* WITH_MPI */ + + /* Update the gpart counter */ + s->nr_gparts = nr_gparts; + #endif /* WITH_MPI */ + /* Mark that there are no inhibited particles left */ + s->nr_inhibited_parts = 0; + s->nr_inhibited_gparts = 0; + s->nr_inhibited_sparts = 0; + /* Sort the gparts according to their cells. */ if (nr_gparts > 0) space_gparts_sort(s->gparts, s->parts, s->sparts, gind, cell_gpart_counts, @@ -923,6 +1058,9 @@ void space_rebuild(struct space *s, int verbose) { for (size_t k = 0; k < nr_gparts; k++) { const struct gpart *gp = &s->gparts[k]; + if (gp->time_bin == time_bin_inhibited) + error("Inhibited particle sorted into a cell!"); + /* New cell index */ const int new_gind = cell_getid(s->cdim, gp->x[0] * s->iwidth[0], gp->x[1] * s->iwidth[1], @@ -939,14 +1077,14 @@ void space_rebuild(struct space *s, int verbose) { gp->x[2] < c->loc[2] || gp->x[2] > c->loc[2] + c->width[2]) error("gpart not sorted into the right top-level cell!"); } -#endif +#endif /* SWIFT_DEBUG_CHECKS */ /* Extract the cell counts from the sorted indices. */ size_t last_gindex = 0; gind[nr_gparts] = s->nr_cells; for (size_t k = 0; k < nr_gparts; k++) { if (gind[k] < gind[k + 1]) { - cells_top[gind[k]].gcount = k - last_gindex + 1; + cells_top[gind[k]].grav.count = k - last_gindex + 1; last_gindex = k + 1; } } @@ -962,40 +1100,64 @@ void space_rebuild(struct space *s, int verbose) { nr_sparts, verbose); #endif - /* Hook the cells up to the parts. */ - // tic = getticks(); + /* Hook the cells up to the parts. Make list of local and non-empty cells */ + ticks tic2 = getticks(); struct part *finger = s->parts; struct xpart *xfinger = s->xparts; struct gpart *gfinger = s->gparts; struct spart *sfinger = s->sparts; + s->nr_cells_with_particles = 0; + s->nr_local_cells_with_particles = 0; + s->nr_local_cells = 0; for (int k = 0; k < s->nr_cells; k++) { struct cell *restrict c = &cells_top[k]; - c->ti_old_part = ti_current; - c->ti_old_gpart = ti_current; - c->ti_old_multipole = ti_current; + c->hydro.ti_old_part = ti_current; + c->grav.ti_old_part = ti_current; + c->grav.ti_old_multipole = ti_current; #ifdef SWIFT_DEBUG_CHECKS c->cellID = -last_cell_id; last_cell_id++; #endif - if (c->nodeID == engine_rank) { - c->parts = finger; - c->xparts = xfinger; - c->gparts = gfinger; - c->sparts = sfinger; - finger = &finger[c->count]; - xfinger = &xfinger[c->count]; - gfinger = &gfinger[c->gcount]; - sfinger = &sfinger[c->scount]; + const int is_local = (c->nodeID == engine_rank); + const int has_particles = + (c->hydro.count > 0) || (c->grav.count > 0) || (c->stars.count > 0); + + if (is_local) { + c->hydro.parts = finger; + 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]; + + /* Add this cell to the list of local cells */ + s->local_cells_top[s->nr_local_cells] = k; + s->nr_local_cells++; } + + if (is_local && has_particles) { + + /* Add this cell to the list of non-empty cells */ + s->local_cells_with_particles_top[s->nr_local_cells_with_particles] = k; + s->nr_local_cells_with_particles++; + } + } + if (verbose) { + message("Have %d local top-level cells with particles (total=%d)", + s->nr_local_cells_with_particles, s->nr_cells); + message("Have %d local top-level cells (total=%d)", s->nr_local_cells, + s->nr_cells); + message("hooking up cells took %.3f %s.", + clocks_from_ticks(getticks() - tic2), clocks_getunit()); } - // message( "hooking up cells took %.3f %s." , - // clocks_from_ticks(getticks() - tic), 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. */ - space_split(s, cells_top, s->nr_cells, verbose); + space_split(s, verbose); #ifdef SWIFT_DEBUG_CHECKS /* Check that the multipole construction went OK */ @@ -1013,22 +1175,21 @@ void space_rebuild(struct space *s, int verbose) { } /** - * @brief Split particles between cells of a hierarchy + * @brief Split particles between cells of a hierarchy. * * This is done in parallel using threads in the #threadpool. + * Only do this for the local non-empty top-level cells. * * @param s The #space. - * @param cells The cell hierarchy. - * @param nr_cells The number of cells. * @param verbose Are we talkative ? */ -void space_split(struct space *s, struct cell *cells, int nr_cells, - int verbose) { +void space_split(struct space *s, int verbose) { const ticks tic = getticks(); - threadpool_map(&s->e->threadpool, space_split_mapper, cells, nr_cells, - sizeof(struct cell), 0, s); + threadpool_map(&s->e->threadpool, space_split_mapper, + s->local_cells_with_particles_top, + s->nr_local_cells_with_particles, sizeof(int), 0, s); if (verbose) message("took %.3f %s.", clocks_from_ticks(getticks() - tic), @@ -1098,6 +1259,7 @@ 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; /* Loop over the parts. */ for (int k = 0; k < nr_parts; k++) { @@ -1129,8 +1291,15 @@ void space_parts_get_cell_index_mapper(void *map_data, int nr_parts, pos_z); #endif - ind[k] = index; - cell_counts[index]++; + /* Is this particle to be removed? */ + if (p->time_bin == time_bin_inhibited) { + ind[k] = -1; + ++count_inhibited_part; + } else { + /* List its top-level cell index */ + ind[k] = index; + cell_counts[index]++; + } /* Compute minimal mass */ min_mass = min(min_mass, hydro_get_mass(p)); @@ -1149,6 +1318,9 @@ 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 back the minimal part mass and velocity sum */ atomic_min_f(&s->min_part_mass, min_mass); atomic_add_f(&s->sum_part_vel_norm, sum_vel_norm); @@ -1187,6 +1359,7 @@ 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; for (int k = 0; k < nr_gparts; k++) { @@ -1217,12 +1390,22 @@ void space_gparts_get_cell_index_mapper(void *map_data, int nr_gparts, pos_z); #endif - ind[k] = index; - cell_counts[index]++; + /* Is this particle to be removed? */ + if (gp->time_bin == time_bin_inhibited) { + ind[k] = -1; + ++count_inhibited_gpart; + } else { + /* List its top-level cell index */ + ind[k] = index; + cell_counts[index]++; + } - /* Compute minimal mass */ if (gp->type == swift_type_dark_matter) { + + /* 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]; @@ -1239,6 +1422,9 @@ 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 back the minimal part mass and velocity sum */ atomic_min_f(&s->min_gpart_mass, min_mass); atomic_add_f(&s->sum_gpart_vel_norm, sum_vel_norm); @@ -1277,6 +1463,7 @@ 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; for (int k = 0; k < nr_sparts; k++) { @@ -1307,8 +1494,15 @@ void space_sparts_get_cell_index_mapper(void *map_data, int nr_sparts, pos_z); #endif - ind[k] = index; - cell_counts[index]++; + /* Is this particle to be removed? */ + if (sp->time_bin == time_bin_inhibited) { + ind[k] = -1; + ++count_inhibited_spart; + } else { + /* List its top-level cell index */ + ind[k] = index; + cell_counts[index]++; + } /* Compute minimal mass */ min_mass = min(min_mass, sp->mass); @@ -1328,6 +1522,9 @@ 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 back the minimal part mass and velocity sum */ atomic_min_f(&s->min_spart_mass, min_mass); atomic_add_f(&s->sum_spart_vel_norm, sum_vel_norm); @@ -1341,11 +1538,11 @@ void space_sparts_get_cell_index_mapper(void *map_data, int nr_sparts, * @param s The #space. * @param ind The array of indices to fill. * @param cell_counts The cell counters to update. - * @param cells The array of #cell to update. + * @param count_inhibited_parts (return) The number of #part to remove. * @param verbose Are we talkative ? */ void space_parts_get_cell_index(struct space *s, int *ind, int *cell_counts, - struct cell *cells, int verbose) { + int *count_inhibited_parts, int verbose) { const ticks tic = getticks(); @@ -1356,13 +1553,17 @@ void space_parts_get_cell_index(struct space *s, int *ind, int *cell_counts, /* Pack the extra information */ struct index_data data; data.s = s; - data.cells = cells; data.ind = ind; data.cell_counts = cell_counts; + data.count_inhibited_part = 0; + data.count_inhibited_gpart = 0; + data.count_inhibited_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; + if (verbose) message("took %.3f %s.", clocks_from_ticks(getticks() - tic), clocks_getunit()); @@ -1376,11 +1577,11 @@ void space_parts_get_cell_index(struct space *s, int *ind, int *cell_counts, * @param s The #space. * @param gind The array of indices to fill. * @param cell_counts The cell counters to update. - * @param cells The array of #cell to update. + * @param count_inhibited_gparts (return) The number of #gpart to remove. * @param verbose Are we talkative ? */ void space_gparts_get_cell_index(struct space *s, int *gind, int *cell_counts, - struct cell *cells, int verbose) { + int *count_inhibited_gparts, int verbose) { const ticks tic = getticks(); @@ -1391,13 +1592,17 @@ void space_gparts_get_cell_index(struct space *s, int *gind, int *cell_counts, /* Pack the extra information */ struct index_data data; data.s = s; - data.cells = cells; data.ind = gind; data.cell_counts = cell_counts; + data.count_inhibited_part = 0; + data.count_inhibited_gpart = 0; + data.count_inhibited_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; + if (verbose) message("took %.3f %s.", clocks_from_ticks(getticks() - tic), clocks_getunit()); @@ -1411,11 +1616,11 @@ void space_gparts_get_cell_index(struct space *s, int *gind, int *cell_counts, * @param s The #space. * @param sind The array of indices to fill. * @param cell_counts The cell counters to update. - * @param cells The array of #cell to update. + * @param count_inhibited_sparts (return) The number of #spart to remove. * @param verbose Are we talkative ? */ void space_sparts_get_cell_index(struct space *s, int *sind, int *cell_counts, - struct cell *cells, int verbose) { + int *count_inhibited_sparts, int verbose) { const ticks tic = getticks(); @@ -1426,13 +1631,17 @@ void space_sparts_get_cell_index(struct space *s, int *sind, int *cell_counts, /* Pack the extra information */ struct index_data data; data.s = s; - data.cells = cells; data.ind = sind; data.cell_counts = cell_counts; + data.count_inhibited_part = 0; + data.count_inhibited_gpart = 0; + data.count_inhibited_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; + if (verbose) message("took %.3f %s.", clocks_from_ticks(getticks() - tic), clocks_getunit()); @@ -1449,8 +1658,9 @@ void space_sparts_get_cell_index(struct space *s, int *sind, int *cell_counts, * @param num_bins Total number of bins (length of count). * @param parts_offset Offset of the #part array from the global #part array. */ -void space_parts_sort(struct part *parts, struct xpart *xparts, int *ind, - int *counts, int num_bins, ptrdiff_t parts_offset) { +void space_parts_sort(struct part *parts, struct xpart *xparts, + int *restrict ind, int *restrict counts, int num_bins, + ptrdiff_t parts_offset) { /* Create the offsets array. */ size_t *offsets = NULL; if (posix_memalign((void **)&offsets, SWIFT_STRUCT_ALIGNMENT, @@ -1511,8 +1721,9 @@ void space_parts_sort(struct part *parts, struct xpart *xparts, int *ind, * @param sparts_offset Offset of the #spart array from the global #spart. * array. */ -void space_sparts_sort(struct spart *sparts, int *ind, int *counts, - int num_bins, ptrdiff_t sparts_offset) { +void space_sparts_sort(struct spart *sparts, int *restrict ind, + int *restrict counts, int num_bins, + ptrdiff_t sparts_offset) { /* Create the offsets array. */ size_t *offsets = NULL; if (posix_memalign((void **)&offsets, SWIFT_STRUCT_ALIGNMENT, @@ -1571,8 +1782,8 @@ void space_sparts_sort(struct spart *sparts, int *ind, int *counts, * @param num_bins Total number of bins (length of counts). */ void space_gparts_sort(struct gpart *gparts, struct part *parts, - struct spart *sparts, int *ind, int *counts, - int num_bins) { + struct spart *sparts, int *restrict ind, + int *restrict counts, int num_bins) { /* Create the offsets array. */ size_t *offsets = NULL; if (posix_memalign((void **)&offsets, SWIFT_STRUCT_ALIGNMENT, @@ -1632,9 +1843,9 @@ void space_gparts_sort(struct gpart *gparts, struct part *parts, void space_map_clearsort(struct cell *c, void *data) { for (int i = 0; i < 13; i++) - if (c->sort[i] != NULL) { - free(c->sort[i]); - c->sort[i] = NULL; + if (c->hydro.sort[i] != NULL) { + free(c->hydro.sort[i]); + c->hydro.sort[i] = NULL; } } @@ -1651,7 +1862,7 @@ static void rec_map_parts(struct cell *c, void *data) { /* No progeny? */ if (!c->split) - for (int k = 0; k < c->count; k++) fun(&c->parts[k], c, data); + for (int k = 0; k < c->hydro.count; k++) fun(&c->hydro.parts[k], c, data); /* Otherwise, recurse. */ else @@ -1687,7 +1898,8 @@ static void rec_map_parts_xparts(struct cell *c, /* No progeny? */ if (!c->split) - for (int k = 0; k < c->count; k++) fun(&c->parts[k], &c->xparts[k], c); + for (int k = 0; k < c->hydro.count; k++) + fun(&c->hydro.parts[k], &c->hydro.xparts[k], c); /* Otherwise, recurse. */ else @@ -1783,31 +1995,32 @@ void space_map_cells_pre(struct space *s, int full, * @param s The #space in which the cell lives. * @param c The #cell to split recursively. * @param buff A buffer for particle sorting, should be of size at least - * c->count or @c NULL. + * c->hydro.count or @c NULL. * @param sbuff A buffer for particle sorting, should be of size at least - * c->scount or @c NULL. + * c->stars.count or @c NULL. * @param gbuff A buffer for particle sorting, should be of size at least - * c->gcount or @c NULL. + * c->grav.count or @c NULL. */ void space_split_recursive(struct space *s, struct cell *c, struct cell_buff *buff, struct cell_buff *sbuff, struct cell_buff *gbuff) { - const int count = c->count; - const int gcount = c->gcount; - const int scount = c->scount; + 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 depth = c->depth; int maxdepth = 0; float h_max = 0.0f; + float stars_h_max = 0.f; integertime_t ti_hydro_end_min = max_nr_timesteps, ti_hydro_end_max = 0, ti_hydro_beg_max = 0; integertime_t ti_gravity_end_min = max_nr_timesteps, ti_gravity_end_max = 0, ti_gravity_beg_max = 0; - struct part *parts = c->parts; - struct gpart *gparts = c->gparts; - struct spart *sparts = c->sparts; - struct xpart *xparts = c->xparts; + struct part *parts = c->hydro.parts; + struct gpart *gparts = c->grav.parts; + struct spart *sparts = c->stars.parts; + struct xpart *xparts = c->hydro.xparts; struct engine *e = s->e; const integertime_t ti_current = e->ti_current; @@ -1819,6 +2032,10 @@ void space_split_recursive(struct space *s, struct cell *c, sizeof(struct cell_buff) * count) != 0) error("Failed to allocate temporary indices."); for (int k = 0; k < count; k++) { +#ifdef SWIFT_DEBUG_CHECKS + if (parts[k].time_bin == time_bin_inhibited) + error("Inhibited particle present in space_split()"); +#endif buff[k].x[0] = parts[k].x[0]; buff[k].x[1] = parts[k].x[1]; buff[k].x[2] = parts[k].x[2]; @@ -1829,6 +2046,10 @@ void space_split_recursive(struct space *s, struct cell *c, sizeof(struct cell_buff) * gcount) != 0) error("Failed to allocate temporary indices."); for (int k = 0; k < gcount; k++) { +#ifdef SWIFT_DEBUG_CHECKS + if (gparts[k].time_bin == time_bin_inhibited) + error("Inhibited particle present in space_split()"); +#endif gbuff[k].x[0] = gparts[k].x[0]; gbuff[k].x[1] = gparts[k].x[1]; gbuff[k].x[2] = gparts[k].x[2]; @@ -1839,6 +2060,10 @@ void space_split_recursive(struct space *s, struct cell *c, sizeof(struct cell_buff) * scount) != 0) error("Failed to allocate temporary indices."); for (int k = 0; k < scount; k++) { +#ifdef SWIFT_DEBUG_CHECKS + if (sparts[k].time_bin == time_bin_inhibited) + error("Inhibited particle present in space_split()"); +#endif sbuff[k].x[0] = sparts[k].x[0]; sbuff[k].x[1] = sparts[k].x[1]; sbuff[k].x[2] = sparts[k].x[2]; @@ -1869,12 +2094,12 @@ void space_split_recursive(struct space *s, struct cell *c, space_getcells(s, 8, c->progeny); for (int k = 0; k < 8; k++) { struct cell *cp = c->progeny[k]; - cp->count = 0; - cp->gcount = 0; - cp->scount = 0; - cp->ti_old_part = c->ti_old_part; - cp->ti_old_gpart = c->ti_old_gpart; - cp->ti_old_multipole = c->ti_old_multipole; + cp->hydro.count = 0; + cp->grav.count = 0; + cp->stars.count = 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; cp->loc[0] = c->loc[0]; cp->loc[1] = c->loc[1]; cp->loc[2] = c->loc[2]; @@ -1887,19 +2112,21 @@ void space_split_recursive(struct space *s, struct cell *c, if (k & 1) cp->loc[2] += cp->width[2]; cp->depth = c->depth + 1; cp->split = 0; - cp->h_max = 0.f; - cp->dx_max_part = 0.f; - cp->dx_max_sort = 0.f; + cp->hydro.h_max = 0.f; + cp->hydro.dx_max_part = 0.f; + cp->hydro.dx_max_sort = 0.f; + cp->stars.h_max = 0.f; + cp->stars.dx_max_part = 0.f; cp->nodeID = c->nodeID; cp->parent = c; cp->super = NULL; - cp->super_hydro = NULL; - cp->super_gravity = NULL; - cp->do_sub_sort = 0; - cp->do_grav_sub_drift = 0; - cp->do_sub_drift = 0; + cp->hydro.super = NULL; + cp->grav.super = NULL; + cp->hydro.do_sub_sort = 0; + cp->grav.do_sub_drift = 0; + cp->hydro.do_sub_drift = 0; #ifdef WITH_MPI - cp->tag = -1; + cp->mpi.tag = -1; #endif // WITH_MPI #ifdef SWIFT_DEBUG_CHECKS cp->cellID = last_cell_id++; @@ -1907,8 +2134,8 @@ void space_split_recursive(struct space *s, struct cell *c, } /* Split the cell's partcle data. */ - cell_split(c, c->parts - s->parts, c->sparts - s->sparts, buff, sbuff, - gbuff); + cell_split(c, c->hydro.parts - s->parts, c->stars.parts - s->sparts, buff, + sbuff, gbuff); /* Buffers for the progenitors */ struct cell_buff *progeny_buff = buff, *progeny_gbuff = gbuff, @@ -1920,7 +2147,7 @@ void space_split_recursive(struct space *s, struct cell *c, struct cell *cp = c->progeny[k]; /* Remove any progeny with zero particles. */ - if (cp->count == 0 && cp->gcount == 0 && cp->scount == 0) { + if (cp->hydro.count == 0 && cp->grav.count == 0 && cp->stars.count == 0) { space_recycle(s, cp); c->progeny[k] = NULL; @@ -1932,18 +2159,19 @@ void space_split_recursive(struct space *s, struct cell *c, progeny_gbuff); /* Update the pointers in the buffers */ - progeny_buff += cp->count; - progeny_gbuff += cp->gcount; - progeny_sbuff += cp->scount; + progeny_buff += cp->hydro.count; + progeny_gbuff += cp->grav.count; + progeny_sbuff += cp->stars.count; /* Update the cell-wide properties */ - h_max = max(h_max, cp->h_max); - ti_hydro_end_min = min(ti_hydro_end_min, cp->ti_hydro_end_min); - ti_hydro_end_max = max(ti_hydro_end_max, cp->ti_hydro_end_max); - ti_hydro_beg_max = max(ti_hydro_beg_max, cp->ti_hydro_beg_max); - ti_gravity_end_min = min(ti_gravity_end_min, cp->ti_gravity_end_min); - ti_gravity_end_max = max(ti_gravity_end_max, cp->ti_gravity_end_max); - ti_gravity_beg_max = max(ti_gravity_beg_max, cp->ti_gravity_beg_max); + h_max = max(h_max, cp->hydro.h_max); + stars_h_max = max(h_max, cp->stars.h_max); + ti_hydro_end_min = min(ti_hydro_end_min, cp->hydro.ti_end_min); + ti_hydro_end_max = max(ti_hydro_end_max, cp->hydro.ti_end_max); + ti_hydro_beg_max = max(ti_hydro_beg_max, cp->hydro.ti_beg_max); + ti_gravity_end_min = min(ti_gravity_end_min, cp->grav.ti_end_min); + ti_gravity_end_max = max(ti_gravity_end_max, cp->grav.ti_end_max); + ti_gravity_beg_max = max(ti_gravity_beg_max, cp->grav.ti_beg_max); /* Increase the depth */ if (cp->maxdepth > maxdepth) maxdepth = cp->maxdepth; @@ -1954,7 +2182,7 @@ void space_split_recursive(struct space *s, struct cell *c, if (s->gravity) { /* Reset everything */ - gravity_reset(c->multipole); + gravity_reset(c->grav.multipole); /* Compute CoM and bulk velocity from all progenies */ double CoM[3] = {0., 0., 0.}; @@ -1965,7 +2193,7 @@ void space_split_recursive(struct space *s, struct cell *c, for (int k = 0; k < 8; ++k) { if (c->progeny[k] != NULL) { - const struct gravity_tensors *m = c->progeny[k]->multipole; + const struct gravity_tensors *m = c->progeny[k]->grav.multipole; mass += m->m_pole.M_000; @@ -1989,20 +2217,20 @@ void space_split_recursive(struct space *s, struct cell *c, /* Final operation on the CoM and bulk velocity */ const double inv_mass = 1. / mass; - c->multipole->CoM[0] = CoM[0] * inv_mass; - c->multipole->CoM[1] = CoM[1] * inv_mass; - c->multipole->CoM[2] = CoM[2] * inv_mass; - c->multipole->m_pole.vel[0] = vel[0] * inv_mass; - c->multipole->m_pole.vel[1] = vel[1] * inv_mass; - c->multipole->m_pole.vel[2] = vel[2] * inv_mass; + c->grav.multipole->CoM[0] = CoM[0] * inv_mass; + c->grav.multipole->CoM[1] = CoM[1] * inv_mass; + c->grav.multipole->CoM[2] = CoM[2] * inv_mass; + c->grav.multipole->m_pole.vel[0] = vel[0] * inv_mass; + c->grav.multipole->m_pole.vel[1] = vel[1] * inv_mass; + c->grav.multipole->m_pole.vel[2] = vel[2] * inv_mass; /* Min max velocity along each axis */ - c->multipole->m_pole.max_delta_vel[0] = max_delta_vel[0]; - c->multipole->m_pole.max_delta_vel[1] = max_delta_vel[1]; - c->multipole->m_pole.max_delta_vel[2] = max_delta_vel[2]; - c->multipole->m_pole.min_delta_vel[0] = min_delta_vel[0]; - c->multipole->m_pole.min_delta_vel[1] = min_delta_vel[1]; - c->multipole->m_pole.min_delta_vel[2] = min_delta_vel[2]; + c->grav.multipole->m_pole.max_delta_vel[0] = max_delta_vel[0]; + c->grav.multipole->m_pole.max_delta_vel[1] = max_delta_vel[1]; + c->grav.multipole->m_pole.max_delta_vel[2] = max_delta_vel[2]; + c->grav.multipole->m_pole.min_delta_vel[0] = min_delta_vel[0]; + c->grav.multipole->m_pole.min_delta_vel[1] = min_delta_vel[1]; + c->grav.multipole->m_pole.min_delta_vel[2] = min_delta_vel[2]; /* Now shift progeny multipoles and add them up */ struct multipole temp; @@ -2010,45 +2238,52 @@ void space_split_recursive(struct space *s, struct cell *c, for (int k = 0; k < 8; ++k) { if (c->progeny[k] != NULL) { const struct cell *cp = c->progeny[k]; - const struct multipole *m = &cp->multipole->m_pole; + const struct multipole *m = &cp->grav.multipole->m_pole; /* Contribution to multipole */ - gravity_M2M(&temp, m, c->multipole->CoM, cp->multipole->CoM); - gravity_multipole_add(&c->multipole->m_pole, &temp); + gravity_M2M(&temp, m, c->grav.multipole->CoM, + cp->grav.multipole->CoM); + gravity_multipole_add(&c->grav.multipole->m_pole, &temp); /* Upper limit of max CoM<->gpart distance */ - const double dx = c->multipole->CoM[0] - cp->multipole->CoM[0]; - const double dy = c->multipole->CoM[1] - cp->multipole->CoM[1]; - const double dz = c->multipole->CoM[2] - cp->multipole->CoM[2]; + const double dx = + c->grav.multipole->CoM[0] - cp->grav.multipole->CoM[0]; + const double dy = + c->grav.multipole->CoM[1] - cp->grav.multipole->CoM[1]; + const double dz = + c->grav.multipole->CoM[2] - cp->grav.multipole->CoM[2]; const double r2 = dx * dx + dy * dy + dz * dz; - r_max = max(r_max, cp->multipole->r_max + sqrt(r2)); + r_max = max(r_max, cp->grav.multipole->r_max + sqrt(r2)); } } /* Alternative upper limit of max CoM<->gpart distance */ - const double dx = c->multipole->CoM[0] > c->loc[0] + c->width[0] / 2. - ? c->multipole->CoM[0] - c->loc[0] - : c->loc[0] + c->width[0] - c->multipole->CoM[0]; - const double dy = c->multipole->CoM[1] > c->loc[1] + c->width[1] / 2. - ? c->multipole->CoM[1] - c->loc[1] - : c->loc[1] + c->width[1] - c->multipole->CoM[1]; - const double dz = c->multipole->CoM[2] > c->loc[2] + c->width[2] / 2. - ? c->multipole->CoM[2] - c->loc[2] - : c->loc[2] + c->width[2] - c->multipole->CoM[2]; + const double dx = + c->grav.multipole->CoM[0] > c->loc[0] + c->width[0] / 2. + ? c->grav.multipole->CoM[0] - c->loc[0] + : c->loc[0] + c->width[0] - c->grav.multipole->CoM[0]; + const double dy = + c->grav.multipole->CoM[1] > c->loc[1] + c->width[1] / 2. + ? c->grav.multipole->CoM[1] - c->loc[1] + : c->loc[1] + c->width[1] - c->grav.multipole->CoM[1]; + const double dz = + c->grav.multipole->CoM[2] > c->loc[2] + c->width[2] / 2. + ? c->grav.multipole->CoM[2] - c->loc[2] + : c->loc[2] + c->width[2] - c->grav.multipole->CoM[2]; /* Take minimum of both limits */ - c->multipole->r_max = min(r_max, sqrt(dx * dx + dy * dy + dz * dz)); + c->grav.multipole->r_max = min(r_max, sqrt(dx * dx + dy * dy + dz * dz)); /* Store the value at rebuild time */ - c->multipole->r_max_rebuild = c->multipole->r_max; - c->multipole->CoM_rebuild[0] = c->multipole->CoM[0]; - c->multipole->CoM_rebuild[1] = c->multipole->CoM[1]; - c->multipole->CoM_rebuild[2] = c->multipole->CoM[2]; + c->grav.multipole->r_max_rebuild = c->grav.multipole->r_max; + c->grav.multipole->CoM_rebuild[0] = c->grav.multipole->CoM[0]; + c->grav.multipole->CoM_rebuild[1] = c->grav.multipole->CoM[1]; + c->grav.multipole->CoM_rebuild[2] = c->grav.multipole->CoM[2]; /* We know the first-order multipole (dipole) is 0. */ - c->multipole->m_pole.M_100 = 0.f; - c->multipole->m_pole.M_010 = 0.f; - c->multipole->m_pole.M_001 = 0.f; + c->grav.multipole->m_pole.M_100 = 0.f; + c->grav.multipole->m_pole.M_010 = 0.f; + c->grav.multipole->m_pole.M_001 = 0.f; } /* Deal with gravity */ } /* Split or let it be? */ @@ -2100,6 +2335,12 @@ void space_split_recursive(struct space *s, struct cell *c, #endif gravity_time_bin_min = min(gravity_time_bin_min, sparts[k].time_bin); gravity_time_bin_max = max(gravity_time_bin_max, sparts[k].time_bin); + stars_h_max = max(stars_h_max, sparts[k].h); + + /* Reset x_diff */ + sparts[k].x_diff[0] = 0.f; + sparts[k].x_diff[1] = 0.f; + sparts[k].x_diff[2] = 0.f; } /* Convert into integer times */ @@ -2116,50 +2357,51 @@ void space_split_recursive(struct space *s, struct cell *c, if (s->gravity) { if (gcount > 0) { - gravity_P2M(c->multipole, c->gparts, c->gcount); + gravity_P2M(c->grav.multipole, c->grav.parts, c->grav.count); } else { /* No gparts in that leaf cell */ /* Set the values to something sensible */ - gravity_multipole_init(&c->multipole->m_pole); + gravity_multipole_init(&c->grav.multipole->m_pole); if (c->nodeID == engine_rank) { - c->multipole->CoM[0] = c->loc[0] + c->width[0] / 2.; - c->multipole->CoM[1] = c->loc[1] + c->width[1] / 2.; - c->multipole->CoM[2] = c->loc[2] + c->width[2] / 2.; - c->multipole->r_max = 0.; + c->grav.multipole->CoM[0] = c->loc[0] + c->width[0] / 2.; + c->grav.multipole->CoM[1] = c->loc[1] + c->width[1] / 2.; + c->grav.multipole->CoM[2] = c->loc[2] + c->width[2] / 2.; + c->grav.multipole->r_max = 0.; } } /* Store the value at rebuild time */ - c->multipole->r_max_rebuild = c->multipole->r_max; - c->multipole->CoM_rebuild[0] = c->multipole->CoM[0]; - c->multipole->CoM_rebuild[1] = c->multipole->CoM[1]; - c->multipole->CoM_rebuild[2] = c->multipole->CoM[2]; + c->grav.multipole->r_max_rebuild = c->grav.multipole->r_max; + c->grav.multipole->CoM_rebuild[0] = c->grav.multipole->CoM[0]; + c->grav.multipole->CoM_rebuild[1] = c->grav.multipole->CoM[1]; + c->grav.multipole->CoM_rebuild[2] = c->grav.multipole->CoM[2]; } } /* Set the values for this cell. */ - c->h_max = h_max; - c->ti_hydro_end_min = ti_hydro_end_min; - c->ti_hydro_end_max = ti_hydro_end_max; - c->ti_hydro_beg_max = ti_hydro_beg_max; - c->ti_gravity_end_min = ti_gravity_end_min; - c->ti_gravity_end_max = ti_gravity_end_max; - c->ti_gravity_beg_max = ti_gravity_beg_max; + c->hydro.h_max = h_max; + c->hydro.ti_end_min = ti_hydro_end_min; + c->hydro.ti_end_max = ti_hydro_end_max; + c->hydro.ti_beg_max = ti_hydro_beg_max; + c->grav.ti_end_min = ti_gravity_end_min; + c->grav.ti_end_max = ti_gravity_end_max; + c->grav.ti_beg_max = ti_gravity_beg_max; + c->stars.h_max = stars_h_max; c->maxdepth = maxdepth; /* Set ownership according to the start of the parts array. */ if (s->nr_parts > 0) - c->owner = - ((c->parts - s->parts) % s->nr_parts) * s->nr_queues / s->nr_parts; + c->owner = ((c->hydro.parts - s->parts) % s->nr_parts) * s->nr_queues / + s->nr_parts; else if (s->nr_sparts > 0) - c->owner = - ((c->sparts - s->sparts) % s->nr_sparts) * s->nr_queues / s->nr_sparts; + c->owner = ((c->stars.parts - s->sparts) % s->nr_sparts) * s->nr_queues / + s->nr_sparts; else if (s->nr_gparts > 0) - c->owner = - ((c->gparts - s->gparts) % s->nr_gparts) * s->nr_queues / s->nr_gparts; + c->owner = ((c->grav.parts - s->gparts) % s->nr_gparts) * s->nr_queues / + s->nr_gparts; else c->owner = 0; /* Ok, there is really nothing on this rank... */ @@ -2183,10 +2425,12 @@ void space_split_mapper(void *map_data, int num_cells, void *extra_data) { /* Unpack the inputs. */ struct space *s = (struct space *)extra_data; - struct cell *restrict cells_top = (struct cell *)map_data; + struct cell *cells_top = s->cells_top; + int *local_cells_with_particles = (int *)map_data; + /* Loop over the non-empty cells */ for (int ind = 0; ind < num_cells; ind++) { - struct cell *c = &cells_top[ind]; + struct cell *c = &cells_top[local_cells_with_particles[ind]]; space_split_recursive(s, c, NULL, NULL, NULL); } @@ -2194,8 +2438,8 @@ void space_split_mapper(void *map_data, int num_cells, void *extra_data) { /* All cells and particles should have consistent h_max values. */ for (int ind = 0; ind < num_cells; ind++) { int depth = 0; - if (!checkCellhdxmax(&cells_top[ind], &depth)) - message(" at cell depth %d", depth); + const struct cell *c = &cells_top[local_cells_with_particles[ind]]; + if (!checkCellhdxmax(c, &depth)) message(" at cell depth %d", depth); } #endif } @@ -2209,8 +2453,8 @@ void space_split_mapper(void *map_data, int num_cells, void *extra_data) { void space_recycle(struct space *s, struct cell *c) { /* Clear the cell. */ - if (lock_destroy(&c->lock) != 0 || lock_destroy(&c->glock) != 0 || - lock_destroy(&c->mlock) != 0 || lock_destroy(&c->slock) != 0) + if (lock_destroy(&c->lock) != 0 || lock_destroy(&c->grav.plock) != 0 || + lock_destroy(&c->mlock) != 0 || lock_destroy(&c->stars.lock) != 0) error("Failed to destroy spinlocks."); /* Lock the space. */ @@ -2218,8 +2462,8 @@ void space_recycle(struct space *s, struct cell *c) { /* Hook the multipole back in the buffer */ if (s->gravity) { - c->multipole->next = s->multipoles_sub; - s->multipoles_sub = c->multipole; + c->grav.multipole->next = s->multipoles_sub; + s->multipoles_sub = c->grav.multipole; } /* Hook this cell into the buffer. */ @@ -2258,8 +2502,8 @@ void space_recycle_list(struct space *s, struct cell *cell_list_begin, /* Clean up the list of cells. */ for (struct cell *c = cell_list_begin; c != NULL; c = c->next) { /* Clear the cell. */ - if (lock_destroy(&c->lock) != 0 || lock_destroy(&c->glock) != 0 || - lock_destroy(&c->mlock) != 0 || lock_destroy(&c->slock) != 0) + if (lock_destroy(&c->lock) != 0 || lock_destroy(&c->grav.plock) != 0 || + lock_destroy(&c->mlock) != 0 || lock_destroy(&c->stars.lock) != 0) error("Failed to destroy spinlocks."); /* Count this cell. */ @@ -2338,8 +2582,8 @@ void space_getcells(struct space *s, int nr_cells, struct cell **cells) { /* Hook the multipole */ if (s->gravity) { - cells[j]->multipole = s->multipoles_sub; - s->multipoles_sub = cells[j]->multipole->next; + cells[j]->grav.multipole = s->multipoles_sub; + s->multipoles_sub = cells[j]->grav.multipole->next; } } @@ -2349,13 +2593,15 @@ void space_getcells(struct space *s, int nr_cells, struct cell **cells) { /* Init some things in the cell we just got. */ for (int j = 0; j < nr_cells; j++) { for (int k = 0; k < 13; k++) - if (cells[j]->sort[k] != NULL) free(cells[j]->sort[k]); - struct gravity_tensors *temp = cells[j]->multipole; + if (cells[j]->hydro.sort[k] != NULL) free(cells[j]->hydro.sort[k]); + struct gravity_tensors *temp = cells[j]->grav.multipole; bzero(cells[j], sizeof(struct cell)); - cells[j]->multipole = temp; + cells[j]->grav.multipole = temp; cells[j]->nodeID = -1; - if (lock_init(&cells[j]->lock) != 0 || lock_init(&cells[j]->glock) != 0 || - lock_init(&cells[j]->mlock) != 0 || lock_init(&cells[j]->slock) != 0) + if (lock_init(&cells[j]->hydro.lock) != 0 || + lock_init(&cells[j]->grav.plock) != 0 || + lock_init(&cells[j]->grav.mlock) != 0 || + lock_init(&cells[j]->stars.lock) != 0) error("Failed to initialize cell spinlocks."); } } @@ -2369,55 +2615,56 @@ void space_free_buff_sort_indices(struct space *s) { for (struct cell *finger = s->cells_sub; finger != NULL; finger = finger->next) { for (int k = 0; k < 13; k++) - if (finger->sort[k] != NULL) { - free(finger->sort[k]); - finger->sort[k] = NULL; + if (finger->hydro.sort[k] != NULL) { + free(finger->hydro.sort[k]); + finger->hydro.sort[k] = NULL; } } } /** * @brief Construct the list of top-level cells that have any tasks in - * their hierarchy on this MPI rank. + * their hierarchy on this MPI rank. Also construct the list of top-level + * cells on any rank that have > 0 particles (of any kind). * * This assumes the list has been pre-allocated at a regrid. * * @param s The #space. */ -void space_list_cells_with_tasks(struct space *s) { +void space_list_useful_top_level_cells(struct space *s) { + + const ticks tic = getticks(); s->nr_local_cells_with_tasks = 0; + s->nr_cells_with_particles = 0; + + for (int i = 0; i < s->nr_cells; ++i) { + struct cell *c = &s->cells_top[i]; - for (int i = 0; i < s->nr_cells; ++i) - if (cell_has_tasks(&s->cells_top[i])) { + if (cell_has_tasks(c)) { s->local_cells_with_tasks_top[s->nr_local_cells_with_tasks] = i; s->nr_local_cells_with_tasks++; } - if (s->e->verbose) - message("Have %d local top-level cells with tasks (total=%d)", - s->nr_local_cells_with_tasks, s->nr_cells); -} - -/** - * @brief Construct the list of local top-level cells. - * - * This assumes the list has been pre-allocated at a regrid. - * - * @param s The #space. - */ -void space_list_local_cells(struct space *s) { - s->nr_local_cells = 0; + const int has_particles = + (c->hydro.count > 0) || (c->grav.count > 0) || (c->stars.count > 0) || + (c->grav.multipole != NULL && c->grav.multipole->m_pole.M_000 > 0.f); - for (int i = 0; i < s->nr_cells; ++i) - if (s->cells_top[i].nodeID == engine_rank) { - s->local_cells_top[s->nr_local_cells] = i; - s->nr_local_cells++; + if (has_particles) { + s->cells_with_particles_top[s->nr_cells_with_particles] = i; + s->nr_cells_with_particles++; } + } + if (s->e->verbose) { + message("Have %d local top-level cells with tasks (total=%d)", + s->nr_local_cells_with_tasks, s->nr_cells); + message("Have %d top-level cells with particles (total=%d)", + s->nr_cells_with_particles, s->nr_cells); + } if (s->e->verbose) - message("Have %d local top-level cells (total=%d)", s->nr_local_cells, - s->nr_cells); + message("took %.3f %s.", clocks_from_ticks(getticks() - tic), + clocks_getunit()); } void space_synchronize_particle_positions_mapper(void *map_data, int nr_gparts, @@ -2465,11 +2712,17 @@ void space_synchronize_particle_positions_mapper(void *map_data, int nr_gparts, void space_synchronize_particle_positions(struct space *s) { + const ticks tic = getticks(); + if ((s->nr_gparts > 0 && s->nr_parts > 0) || (s->nr_gparts > 0 && s->nr_sparts > 0)) threadpool_map(&s->e->threadpool, space_synchronize_particle_positions_mapper, s->gparts, s->nr_gparts, sizeof(struct gpart), 0, (void *)s); + + if (s->e->verbose) + message("took %.3f %s.", clocks_from_ticks(getticks() - tic), + clocks_getunit()); } void space_first_init_parts_mapper(void *restrict map_data, int count, @@ -2515,6 +2768,9 @@ void space_first_init_parts_mapper(void *restrict map_data, int count, for (int k = 0; k < count; k++) { hydro_first_init_part(&p[k], &xp[k]); +#ifdef WITH_LOGGER + logger_part_data_init(&xp[k].logger_data); +#endif /* Overwrite the internal energy? */ if (u_init > 0.f) hydro_set_init_internal_energy(&p[k], u_init); @@ -2849,7 +3105,7 @@ void space_init(struct space *s, struct swift_params *params, /* Are we generating gas from the DM-only ICs? */ if (generate_gas_in_ics) { - space_generate_gas(s, cosmo, verbose); + space_generate_gas(s, cosmo, periodic, dim, verbose); parts = s->parts; gparts = s->gparts; Npart = s->nr_parts; @@ -3162,10 +3418,12 @@ void space_replicate(struct space *s, int replicate, int verbose) { * * @param s The #space to create the particles in. * @param cosmo The current #cosmology model. + * @param periodic Are we using periodic boundary conditions? + * @param dim The size of the box (for periodic wrapping). * @param verbose Are we talkative? */ void space_generate_gas(struct space *s, const struct cosmology *cosmo, - int verbose) { + int periodic, const double dim[3], int verbose) { /* Check that this is a sensible ting to do */ if (!s->hydro) @@ -3207,7 +3465,7 @@ void space_generate_gas(struct space *s, const struct cosmology *cosmo, /* Compute some constants */ const double mass_ratio = cosmo->Omega_b / cosmo->Omega_m; - const double bg_density = cosmo->Omega_m * cosmo->critical_density; + const double bg_density = cosmo->Omega_m * cosmo->critical_density_0; const double bg_density_inv = 1. / bg_density; /* Update the particle properties */ @@ -3221,9 +3479,11 @@ void space_generate_gas(struct space *s, const struct cosmology *cosmo, p->id = gp_gas->id_or_neg_offset * 2 + 1; gp_dm->id_or_neg_offset *= 2; - if (gp_dm->id_or_neg_offset <= 0) error("DM particle ID overflowd"); + if (gp_dm->id_or_neg_offset < 0) + error("DM particle ID overflowd (DM id=%lld gas id=%lld)", + gp_dm->id_or_neg_offset, p->id); - if (p->id <= 0) error("gas particle ID overflowd"); + if (p->id < 0) error("gas particle ID overflowd (id=%lld)", p->id); /* Set the links correctly */ p->gpart = gp_gas; @@ -3232,8 +3492,8 @@ void space_generate_gas(struct space *s, const struct cosmology *cosmo, /* Compute positions shift */ const double d = cbrt(gp_dm->mass * bg_density_inv); - const double shift_dm = d * mass_ratio; - const double shift_gas = d * (1. - mass_ratio); + const double shift_dm = 0.5 * d * mass_ratio; + const double shift_gas = 0.5 * d * (1. - mass_ratio); /* Set the masses */ gp_dm->mass *= (1. - mass_ratio); @@ -3244,20 +3504,35 @@ void space_generate_gas(struct space *s, const struct cosmology *cosmo, gp_dm->x[0] += shift_dm; gp_dm->x[1] += shift_dm; gp_dm->x[2] += shift_dm; - gp_gas->x[0] += shift_gas; - gp_gas->x[1] += shift_gas; - gp_gas->x[2] += shift_gas; + gp_gas->x[0] -= shift_gas; + gp_gas->x[1] -= shift_gas; + gp_gas->x[2] -= shift_gas; + + /* Make sure the positions are identical between linked particles */ p->x[0] = gp_gas->x[0]; p->x[1] = gp_gas->x[1]; p->x[2] = gp_gas->x[2]; + /* Box-wrap the whole thing to be safe */ + if (periodic) { + gp_dm->x[0] = box_wrap(gp_dm->x[0], 0., dim[0]); + gp_dm->x[1] = box_wrap(gp_dm->x[1], 0., dim[1]); + gp_dm->x[2] = box_wrap(gp_dm->x[2], 0., dim[2]); + gp_gas->x[0] = box_wrap(gp_gas->x[0], 0., dim[0]); + gp_gas->x[1] = box_wrap(gp_gas->x[1], 0., dim[1]); + gp_gas->x[2] = box_wrap(gp_gas->x[2], 0., dim[2]); + p->x[0] = box_wrap(p->x[0], 0., dim[0]); + p->x[1] = box_wrap(p->x[1], 0., dim[1]); + p->x[2] = box_wrap(p->x[2], 0., dim[2]); + } + /* Also copy the velocities */ p->v[0] = gp_gas->v_full[0]; p->v[1] = gp_gas->v_full[1]; p->v[2] = gp_gas->v_full[2]; /* Set the smoothing length to the mean inter-particle separation */ - p->h = 30. * d; + p->h = d; /* Note that the thermodynamic properties (u, S, ...) will be set later */ } @@ -3409,6 +3684,8 @@ void space_clean(struct space *s) { free(s->multipoles_top); free(s->local_cells_top); free(s->local_cells_with_tasks_top); + free(s->cells_with_particles_top); + free(s->local_cells_with_particles_top); free(s->parts); free(s->xparts); free(s->gparts); @@ -3465,7 +3742,11 @@ void space_struct_restore(struct space *s, FILE *stream) { s->multipoles_sub = NULL; s->local_cells_top = NULL; s->local_cells_with_tasks_top = NULL; + s->cells_with_particles_top = NULL; + s->local_cells_with_particles_top = NULL; s->grav_top_level = NULL; + s->nr_local_cells_with_tasks = 0; + s->nr_cells_with_particles = 0; #ifdef WITH_MPI s->parts_foreign = NULL; s->size_parts_foreign = 0; diff --git a/src/space.h b/src/space.h index 003a2c3a348db2d43d7ced6b4931000c4c11662a..064d657a84bd2a32602af15ac76247931133c1f3 100644 --- a/src/space.h +++ b/src/space.h @@ -119,6 +119,12 @@ struct space { /*! Number of *local* top-level cells with tasks */ int nr_local_cells_with_tasks; + /*! Number of top-level cells that have >0 particle (of any kind) */ + int nr_cells_with_particles; + + /*! Number of top-level cells that have >0 particle (of any kind) */ + int nr_local_cells_with_particles; + /*! The (level 0) cells themselves. */ struct cell *cells_top; @@ -137,6 +143,12 @@ struct space { /*! The indices of the *local* top-level cells with tasks */ int *local_cells_with_tasks_top; + /*! The indices of the top-level cells that have >0 particles (of any kind) */ + int *cells_with_particles_top; + + /*! 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; @@ -146,6 +158,15 @@ struct space { /*! The total number of g-parts in the space. */ size_t nr_sparts, size_sparts; + /*! Number of inhibted gas particles in the space */ + size_t nr_inhibited_parts; + + /*! Number of inhibted gravity particles in the space */ + size_t nr_inhibited_gparts; + + /*! Number of inhibted star particles in the space */ + size_t nr_inhibited_sparts; + /*! The particle data (cells have pointers to this). */ struct part *parts; @@ -214,7 +235,7 @@ struct space { #endif }; -/* function prototypes. */ +/* Function prototypes. */ void space_free_buff_sort_indices(struct space *s); void space_parts_sort(struct part *parts, struct xpart *xparts, int *ind, int *counts, int num_bins, ptrdiff_t parts_offset); @@ -241,23 +262,21 @@ void space_map_parts_xparts(struct space *s, struct cell *c)); void space_map_cells_post(struct space *s, int full, void (*fun)(struct cell *c, void *data), void *data); -void space_rebuild(struct space *s, int verbose); +void space_rebuild(struct space *s, int repartitioned, int verbose); void space_recycle(struct space *s, struct cell *c); void space_recycle_list(struct space *s, struct cell *cell_list_begin, struct cell *cell_list_end, struct gravity_tensors *multipole_list_begin, struct gravity_tensors *multipole_list_end); -void space_split(struct space *s, struct cell *cells, int nr_cells, - int verbose); +void space_split(struct space *s, int verbose); void space_split_mapper(void *map_data, int num_elements, void *extra_data); -void space_list_local_cells(struct space *s); -void space_list_cells_with_tasks(struct space *s); +void space_list_useful_top_level_cells(struct space *s); void space_parts_get_cell_index(struct space *s, int *ind, int *cell_counts, - struct cell *cells, int verbose); + int *count_inibibited_parts, int verbose); void space_gparts_get_cell_index(struct space *s, int *gind, int *cell_counts, - struct cell *cells, int verbose); + int *count_inibibited_gparts, int verbose); void space_sparts_get_cell_index(struct space *s, int *sind, int *cell_counts, - struct cell *cells, int verbose); + int *count_inibibited_sparts, int verbose); void space_synchronize_particle_positions(struct space *s); void space_do_parts_sort(void); void space_do_gparts_sort(void); @@ -277,7 +296,7 @@ void space_check_top_multipoles_drift_point(struct space *s, void space_check_timesteps(struct space *s); void space_replicate(struct space *s, int replicate, int verbose); void space_generate_gas(struct space *s, const struct cosmology *cosmo, - int verbose); + int periodic, const double dim[3], int verbose); void space_check_cosmology(struct space *s, const struct cosmology *cosmo, int rank); void space_reset_task_counters(struct space *s); diff --git a/src/stars/Default/stars_part.h b/src/stars/Default/stars_part.h index fe5be3c7f6f190adea2c81ee14c0cad7a10fbd2c..1922cc0e260a3c0f2052649a87252019514e637f 100644 --- a/src/stars/Default/stars_part.h +++ b/src/stars/Default/stars_part.h @@ -38,6 +38,9 @@ struct spart { /*! Particle position. */ double x[3]; + /* Offset between current position and position at last tree rebuild. */ + float x_diff[3]; + /*! Particle velocity. */ float v[3]; diff --git a/src/statistics.c b/src/statistics.c index 22ddc2e971cd6ce16c5310c7fcbf19927c549ceb..47365dd9e388940a187aa5a4568e60bc62bbe934 100644 --- a/src/statistics.c +++ b/src/statistics.c @@ -166,8 +166,8 @@ void stats_collect_part_mapper(void *map_data, int nr_parts, void *extra_data) { hydro_get_drifted_velocities(p, xp, dt_kick_hydro, dt_kick_grav, v); const double x[3] = {p->x[0], p->x[1], p->x[2]}; const float m = hydro_get_mass(p); - const float entropy = hydro_get_physical_entropy(p, cosmo); - const float u_inter = hydro_get_physical_internal_energy(p, cosmo); + const float entropy = hydro_get_drifted_physical_entropy(p, cosmo); + const float u_inter = hydro_get_drifted_physical_internal_energy(p, cosmo); /* Collect mass */ stats.mass += m; diff --git a/src/swift.h b/src/swift.h index 4398f3f69a66320e13d0ed1a6a0a63fafc7d1e52..153c4ae0d4440d083f1b0c9850e1f2649c0df6fb 100644 --- a/src/swift.h +++ b/src/swift.h @@ -46,6 +46,7 @@ #include "hydro_properties.h" #include "lock.h" #include "logger.h" +#include "logger_io.h" #include "map.h" #include "mesh_gravity.h" #include "multipole.h" diff --git a/src/swift_velociraptor_part.h b/src/swift_velociraptor_part.h index 80ee94ba612299dbe8b451cf1ef9d0ee45f8bf53..adae884c2f930c44edf4d48f47f168475bc65885 100644 --- a/src/swift_velociraptor_part.h +++ b/src/swift_velociraptor_part.h @@ -19,6 +19,8 @@ #ifndef SWIFT_VELOCIRAPTOR_PART_H #define SWIFT_VELOCIRAPTOR_PART_H +#include "part_type.h" + /* SWIFT/VELOCIraptor particle. */ struct swift_vel_part { diff --git a/src/task.c b/src/task.c index fd1fbe0e2e8bdf11190124f86ac06b699d6a6282..996c5113bac9935f70a3aafafd58da965b13f5aa 100644 --- a/src/task.c +++ b/src/task.c @@ -48,16 +48,17 @@ /* Task type names. */ const char *taskID_names[task_type_count] = { - "none", "sort", "self", - "pair", "sub_self", "sub_pair", - "init_grav", "init_grav_out", "ghost_in", - "ghost", "ghost_out", "extra_ghost", - "drift_part", "drift_gpart", "end_force", - "kick1", "kick2", "timestep", - "send", "recv", "grav_long_range", - "grav_mm", "grav_down_in", "grav_down", - "grav_mesh", "cooling", "sourceterms", - "stars_ghost_in", "stars_ghost", "stars_ghost_out"}; + "none", "sort", "self", + "pair", "sub_self", "sub_pair", + "init_grav", "init_grav_out", "ghost_in", + "ghost", "ghost_out", "extra_ghost", + "drift_part", "drift_gpart", "end_force", + "kick1", "kick2", "timestep", + "send", "recv", "grav_long_range", + "grav_mm", "grav_down_in", "grav_down", + "grav_mesh", "cooling", "star_formation", + "sourceterms", "logger", "stars_ghost_in", + "stars_ghost", "stars_ghost_out"}; /* Sub-task type names. */ const char *subtaskID_names[task_subtype_count] = { @@ -95,9 +96,9 @@ MPI_Comm subtaskMPI_comms[task_subtype_count]; return 0; \ } -TASK_CELL_OVERLAP(part, parts, count); -TASK_CELL_OVERLAP(gpart, gparts, gcount); -TASK_CELL_OVERLAP(spart, sparts, scount); +TASK_CELL_OVERLAP(part, hydro.parts, hydro.count); +TASK_CELL_OVERLAP(gpart, grav.parts, grav.count); +TASK_CELL_OVERLAP(spart, stars.parts, stars.count); /** * @brief Returns the #task_actions for a given task. @@ -122,6 +123,9 @@ __attribute__((always_inline)) INLINE static enum task_actions task_acts_on( return task_action_part; break; + case task_type_star_formation: + return task_action_all; + case task_type_stars_ghost: return task_action_spart; break; @@ -157,14 +161,15 @@ __attribute__((always_inline)) INLINE static enum task_actions task_acts_on( case task_type_end_force: case task_type_kick1: case task_type_kick2: + case task_type_logger: case task_type_timestep: case task_type_send: case task_type_recv: - if (t->ci->count > 0 && t->ci->gcount > 0) + if (t->ci->hydro.count > 0 && t->ci->grav.count > 0) return task_action_all; - else if (t->ci->count > 0) + else if (t->ci->hydro.count > 0) return task_action_part; - else if (t->ci->gcount > 0) + else if (t->ci->grav.count > 0) return task_action_gpart; else error("Task without particles"); @@ -172,13 +177,13 @@ __attribute__((always_inline)) INLINE static enum task_actions task_acts_on( case task_type_init_grav: case task_type_grav_mm: + case task_type_grav_long_range: return task_action_multipole; break; case task_type_drift_gpart: case task_type_grav_down: case task_type_grav_mesh: - case task_type_grav_long_range: return task_action_gpart; break; @@ -228,10 +233,10 @@ float task_overlap(const struct task *restrict ta, /* Compute the union of the cell data. */ size_t size_union = 0; - if (ta->ci != NULL) size_union += ta->ci->count; - if (ta->cj != NULL) size_union += ta->cj->count; - if (tb->ci != NULL) size_union += tb->ci->count; - if (tb->cj != NULL) size_union += tb->cj->count; + if (ta->ci != NULL) size_union += ta->ci->hydro.count; + if (ta->cj != NULL) size_union += ta->cj->hydro.count; + if (tb->ci != NULL) size_union += tb->ci->hydro.count; + if (tb->cj != NULL) size_union += tb->cj->hydro.count; /* Compute the intersection of the cell data. */ const size_t size_intersect = task_cell_overlap_part(ta->ci, tb->ci) + @@ -247,10 +252,10 @@ float task_overlap(const struct task *restrict ta, /* Compute the union of the cell data. */ size_t size_union = 0; - if (ta->ci != NULL) size_union += ta->ci->gcount; - if (ta->cj != NULL) size_union += ta->cj->gcount; - if (tb->ci != NULL) size_union += tb->ci->gcount; - if (tb->cj != NULL) size_union += tb->cj->gcount; + if (ta->ci != NULL) size_union += ta->ci->grav.count; + if (ta->cj != NULL) size_union += ta->cj->grav.count; + if (tb->ci != NULL) size_union += tb->ci->grav.count; + if (tb->cj != NULL) size_union += tb->cj->grav.count; /* Compute the intersection of the cell data. */ const size_t size_intersect = task_cell_overlap_gpart(ta->ci, tb->ci) + @@ -266,10 +271,10 @@ float task_overlap(const struct task *restrict ta, /* Compute the union of the cell data. */ size_t size_union = 0; - if (ta->ci != NULL) size_union += ta->ci->scount; - if (ta->cj != NULL) size_union += ta->cj->scount; - if (tb->ci != NULL) size_union += tb->ci->scount; - if (tb->cj != NULL) size_union += tb->cj->scount; + if (ta->ci != NULL) size_union += ta->ci->stars.count; + if (ta->cj != NULL) size_union += ta->cj->stars.count; + if (tb->ci != NULL) size_union += tb->ci->stars.count; + if (tb->cj != NULL) size_union += tb->cj->stars.count; /* Compute the intersection of the cell data. */ const size_t size_intersect = task_cell_overlap_spart(ta->ci, tb->ci) + @@ -301,6 +306,7 @@ void task_unlock(struct task *t) { case task_type_end_force: case task_type_kick1: case task_type_kick2: + case task_type_logger: case task_type_timestep: cell_unlocktree(ci); cell_gunlocktree(ci); @@ -396,8 +402,9 @@ int task_lock(struct task *t) { case task_type_end_force: case task_type_kick1: case task_type_kick2: + case task_type_logger: case task_type_timestep: - if (ci->hold || ci->ghold) return 0; + if (ci->hydro.hold || ci->grav.phold) return 0; if (cell_locktree(ci) != 0) return 0; if (cell_glocktree(ci) != 0) { cell_unlocktree(ci); @@ -407,13 +414,13 @@ int task_lock(struct task *t) { case task_type_drift_part: case task_type_sort: - if (ci->hold) return 0; + if (ci->hydro.hold) return 0; if (cell_locktree(ci) != 0) return 0; break; case task_type_drift_gpart: case task_type_grav_mesh: - if (ci->ghold) return 0; + if (ci->grav.phold) return 0; if (cell_glocktree(ci) != 0) return 0; break; @@ -421,7 +428,7 @@ int task_lock(struct task *t) { case task_type_sub_self: if (subtype == task_subtype_grav) { /* Lock the gparts and the m-pole */ - if (ci->ghold || ci->mhold) return 0; + if (ci->grav.phold || ci->grav.mhold) return 0; if (cell_glocktree(ci) != 0) return 0; else if (cell_mlocktree(ci) != 0) { @@ -437,7 +444,7 @@ int task_lock(struct task *t) { case task_type_sub_pair: if (subtype == task_subtype_grav) { /* Lock the gparts and the m-pole in both cells */ - if (ci->ghold || cj->ghold) return 0; + if (ci->grav.phold || cj->grav.phold) return 0; if (cell_glocktree(ci) != 0) return 0; if (cell_glocktree(cj) != 0) { cell_gunlocktree(ci); @@ -454,7 +461,7 @@ int task_lock(struct task *t) { } } else { /* Lock the parts in both cells */ - if (ci->hold || cj->hold) return 0; + if (ci->hydro.hold || cj->hydro.hold) return 0; if (cell_locktree(ci) != 0) return 0; if (cell_locktree(cj) != 0) { cell_unlocktree(ci); @@ -465,7 +472,7 @@ int task_lock(struct task *t) { case task_type_grav_down: /* Lock the gparts and the m-poles */ - if (ci->ghold || ci->mhold) return 0; + if (ci->grav.phold || ci->grav.mhold) return 0; if (cell_glocktree(ci) != 0) return 0; else if (cell_mlocktree(ci) != 0) { @@ -476,13 +483,13 @@ int task_lock(struct task *t) { case task_type_grav_long_range: /* Lock the m-poles */ - if (ci->mhold) return 0; + if (ci->grav.mhold) return 0; if (cell_mlocktree(ci) != 0) return 0; break; case task_type_grav_mm: /* Lock both m-poles */ - if (ci->mhold || cj->mhold) return 0; + if (ci->grav.mhold || cj->grav.mhold) return 0; if (cell_mlocktree(ci) != 0) return 0; if (cell_mlocktree(cj) != 0) { cell_munlocktree(ci); diff --git a/src/task.h b/src/task.h index 866465e4997770d3e0e48818c6eebc6e9abf67a2..9b3225fcf27b768059a2984847d20750d184f8d2 100644 --- a/src/task.h +++ b/src/task.h @@ -65,7 +65,9 @@ enum task_types { task_type_grav_down, 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, task_type_stars_ghost_out, diff --git a/src/timers.c b/src/timers.c index 51d0e5f6dc4fd9e4e0567592750b8de45ecda06b..898c833c3b6764f05ed9205efa0db6220e911a7e 100644 --- a/src/timers.c +++ b/src/timers.c @@ -80,6 +80,7 @@ const char* timers_names[timer_count] = { "dorecv_gpart", "dorecv_spart", "do_cooling", + "do_star_formation", "gettask", "qget", "qsteal", @@ -93,6 +94,7 @@ const char* timers_names[timer_count] = { "dopair_subset_stars_density", "dosubpair_stars_density", "dosub_self_stars_density", + "logger", }; /* File to store the timers */ diff --git a/src/timers.h b/src/timers.h index aba6ae33e3b8268c088694863967b96851715153..c43f0154d2aaaa9d1c5aed3ad51b912e4fc5d751 100644 --- a/src/timers.h +++ b/src/timers.h @@ -81,6 +81,7 @@ enum { timer_dorecv_gpart, timer_dorecv_spart, timer_do_cooling, + timer_do_star_formation, timer_gettask, timer_qget, timer_qsteal, @@ -94,6 +95,7 @@ enum { timer_dopair_subset_stars_density, timer_dosubpair_stars_density, timer_dosub_self_stars_density, + timer_logger, timer_count, }; diff --git a/src/timestep.h b/src/timestep.h index 3b957f0c4b9d103023c77837a1a6ca6388856d22..e9943a41a0536b65944f0256c827d43386aadd88 100644 --- a/src/timestep.h +++ b/src/timestep.h @@ -126,8 +126,9 @@ __attribute__((always_inline)) INLINE static integertime_t get_part_timestep( /* Compute the next timestep (cooling condition) */ float new_dt_cooling = FLT_MAX; if (e->policy & engine_policy_cooling) - new_dt_cooling = cooling_timestep(e->cooling_func, e->physical_constants, - e->cosmology, e->internal_units, p); + new_dt_cooling = + cooling_timestep(e->cooling_func, e->physical_constants, e->cosmology, + e->internal_units, e->hydro_properties, p, xp); /* Compute the next timestep (gravity condition) */ float new_dt_grav = FLT_MAX, new_dt_self_grav = FLT_MAX, diff --git a/src/tools.c b/src/tools.c index 93f0c6f970a1fa530951d1d9d8e3ef169a688a70..ff33afbca3fdc97ede61ff09998d8dc27bf0154b 100644 --- a/src/tools.c +++ b/src/tools.c @@ -195,23 +195,23 @@ void pairs_all_density(struct runner *r, struct cell *ci, struct cell *cj) { const float H = cosmo->H; /* Implements a double-for loop and checks every interaction */ - for (int i = 0; i < ci->count; ++i) { + for (int i = 0; i < ci->hydro.count; ++i) { - pi = &ci->parts[i]; + pi = &ci->hydro.parts[i]; hi = pi->h; hig2 = hi * hi * kernel_gamma2; /* Skip inactive particles. */ if (!part_is_active(pi, e)) continue; - for (int j = 0; j < cj->count; ++j) { + for (int j = 0; j < cj->hydro.count; ++j) { - pj = &cj->parts[j]; + pj = &cj->hydro.parts[j]; /* Pairwise distance */ r2 = 0.0f; for (int k = 0; k < 3; k++) { - dx[k] = ci->parts[i].x[k] - cj->parts[j].x[k]; + dx[k] = ci->hydro.parts[i].x[k] - cj->hydro.parts[j].x[k]; dx[k] = nearest(dx[k], dim[k]); r2 += dx[k] * dx[k]; } @@ -227,23 +227,23 @@ void pairs_all_density(struct runner *r, struct cell *ci, struct cell *cj) { } /* Reverse double-for loop and checks every interaction */ - for (int j = 0; j < cj->count; ++j) { + for (int j = 0; j < cj->hydro.count; ++j) { - pj = &cj->parts[j]; + pj = &cj->hydro.parts[j]; hj = pj->h; hjg2 = hj * hj * kernel_gamma2; /* Skip inactive particles. */ if (!part_is_active(pj, e)) continue; - for (int i = 0; i < ci->count; ++i) { + for (int i = 0; i < ci->hydro.count; ++i) { - pi = &ci->parts[i]; + pi = &ci->hydro.parts[i]; /* Pairwise distance */ r2 = 0.0f; for (int k = 0; k < 3; k++) { - dx[k] = cj->parts[j].x[k] - ci->parts[i].x[k]; + dx[k] = cj->hydro.parts[j].x[k] - ci->hydro.parts[i].x[k]; dx[k] = nearest(dx[k], dim[k]); r2 += dx[k] * dx[k]; } @@ -270,25 +270,25 @@ void pairs_all_force(struct runner *r, struct cell *ci, struct cell *cj) { const float H = cosmo->H; /* Implements a double-for loop and checks every interaction */ - for (int i = 0; i < ci->count; ++i) { + for (int i = 0; i < ci->hydro.count; ++i) { - pi = &ci->parts[i]; + pi = &ci->hydro.parts[i]; hi = pi->h; hig2 = hi * hi * kernel_gamma2; /* Skip inactive particles. */ if (!part_is_active(pi, e)) continue; - for (int j = 0; j < cj->count; ++j) { + for (int j = 0; j < cj->hydro.count; ++j) { - pj = &cj->parts[j]; + pj = &cj->hydro.parts[j]; hj = pj->h; hjg2 = hj * hj * kernel_gamma2; /* Pairwise distance */ r2 = 0.0f; for (int k = 0; k < 3; k++) { - dx[k] = ci->parts[i].x[k] - cj->parts[j].x[k]; + dx[k] = ci->hydro.parts[i].x[k] - cj->hydro.parts[j].x[k]; dx[k] = nearest(dx[k], dim[k]); r2 += dx[k] * dx[k]; } @@ -303,25 +303,25 @@ void pairs_all_force(struct runner *r, struct cell *ci, struct cell *cj) { } /* Reverse double-for loop and checks every interaction */ - for (int j = 0; j < cj->count; ++j) { + for (int j = 0; j < cj->hydro.count; ++j) { - pj = &cj->parts[j]; + pj = &cj->hydro.parts[j]; hj = pj->h; hjg2 = hj * hj * kernel_gamma2; /* Skip inactive particles. */ if (!part_is_active(pj, e)) continue; - for (int i = 0; i < ci->count; ++i) { + for (int i = 0; i < ci->hydro.count; ++i) { - pi = &ci->parts[i]; + pi = &ci->hydro.parts[i]; hi = pi->h; hig2 = hi * hi * kernel_gamma2; /* Pairwise distance */ r2 = 0.0f; for (int k = 0; k < 3; k++) { - dx[k] = cj->parts[j].x[k] - ci->parts[i].x[k]; + dx[k] = cj->hydro.parts[j].x[k] - ci->hydro.parts[i].x[k]; dx[k] = nearest(dx[k], dim[k]); r2 += dx[k] * dx[k]; } @@ -347,8 +347,8 @@ void pairs_all_stars_density(struct runner *r, struct cell *ci, const float H = cosmo->H; /* Implements a double-for loop and checks every interaction */ - for (int i = 0; i < ci->scount; ++i) { - struct spart *spi = &ci->sparts[i]; + for (int i = 0; i < ci->stars.count; ++i) { + struct spart *spi = &ci->stars.parts[i]; float hi = spi->h; float hig2 = hi * hi * kernel_gamma2; @@ -356,9 +356,9 @@ void pairs_all_stars_density(struct runner *r, struct cell *ci, /* Skip inactive particles. */ if (!spart_is_active(spi, e)) continue; - for (int j = 0; j < cj->count; ++j) { + for (int j = 0; j < cj->hydro.count; ++j) { - struct part *pj = &cj->parts[j]; + struct part *pj = &cj->hydro.parts[j]; /* Pairwise distance */ r2 = 0.0f; @@ -377,18 +377,18 @@ void pairs_all_stars_density(struct runner *r, struct cell *ci, } /* Reverse double-for loop and checks every interaction */ - for (int j = 0; j < cj->scount; ++j) { + for (int j = 0; j < cj->stars.count; ++j) { - struct spart *spj = &cj->sparts[j]; + struct spart *spj = &cj->stars.parts[j]; float hj = spj->h; float hjg2 = hj * hj * kernel_gamma2; /* Skip inactive particles. */ if (!spart_is_active(spj, e)) continue; - for (int i = 0; i < ci->count; ++i) { + for (int i = 0; i < ci->hydro.count; ++i) { - struct part *pi = &ci->parts[i]; + struct part *pi = &ci->hydro.parts[i]; /* Pairwise distance */ r2 = 0.0f; @@ -416,15 +416,15 @@ void self_all_density(struct runner *r, struct cell *ci) { const float H = cosmo->H; /* Implements a double-for loop and checks every interaction */ - for (int i = 0; i < ci->count; ++i) { + for (int i = 0; i < ci->hydro.count; ++i) { - pi = &ci->parts[i]; + pi = &ci->hydro.parts[i]; hi = pi->h; hig2 = hi * hi * kernel_gamma2; - for (int j = i + 1; j < ci->count; ++j) { + for (int j = i + 1; j < ci->hydro.count; ++j) { - pj = &ci->parts[j]; + pj = &ci->hydro.parts[j]; hj = pj->h; hjg2 = hj * hj * kernel_gamma2; @@ -433,7 +433,7 @@ void self_all_density(struct runner *r, struct cell *ci) { /* Pairwise distance */ r2 = 0.0f; for (int k = 0; k < 3; k++) { - dxi[k] = ci->parts[i].x[k] - ci->parts[j].x[k]; + dxi[k] = ci->hydro.parts[i].x[k] - ci->hydro.parts[j].x[k]; r2 += dxi[k] * dxi[k]; } @@ -469,15 +469,15 @@ void self_all_force(struct runner *r, struct cell *ci) { const float H = cosmo->H; /* Implements a double-for loop and checks every interaction */ - for (int i = 0; i < ci->count; ++i) { + for (int i = 0; i < ci->hydro.count; ++i) { - pi = &ci->parts[i]; + pi = &ci->hydro.parts[i]; hi = pi->h; hig2 = hi * hi * kernel_gamma2; - for (int j = i + 1; j < ci->count; ++j) { + for (int j = i + 1; j < ci->hydro.count; ++j) { - pj = &ci->parts[j]; + pj = &ci->hydro.parts[j]; hj = pj->h; hjg2 = hj * hj * kernel_gamma2; @@ -486,7 +486,7 @@ void self_all_force(struct runner *r, struct cell *ci) { /* Pairwise distance */ r2 = 0.0f; for (int k = 0; k < 3; k++) { - dxi[k] = ci->parts[i].x[k] - ci->parts[j].x[k]; + dxi[k] = ci->hydro.parts[i].x[k] - ci->hydro.parts[j].x[k]; r2 += dxi[k] * dxi[k]; } @@ -510,17 +510,17 @@ void self_all_stars_density(struct runner *r, struct cell *ci) { const float H = cosmo->H; /* Implements a double-for loop and checks every interaction */ - for (int i = 0; i < ci->scount; ++i) { + for (int i = 0; i < ci->stars.count; ++i) { - spi = &ci->sparts[i]; + spi = &ci->stars.parts[i]; hi = spi->h; hig2 = hi * hi * kernel_gamma2; if (!spart_is_active(spi, e)) continue; - for (int j = 0; j < ci->count; ++j) { + for (int j = 0; j < ci->hydro.count; ++j) { - pj = &ci->parts[j]; + pj = &ci->hydro.parts[j]; hj = pj->h; /* Pairwise distance */ diff --git a/src/velociraptor_dummy.c b/src/velociraptor_dummy.c new file mode 100644 index 0000000000000000000000000000000000000000..8f14a3230d341993122f09f2bccf3d8232550fd9 --- /dev/null +++ b/src/velociraptor_dummy.c @@ -0,0 +1,54 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2018 James Willis (james.s.willis@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" + +/* Some standard headers. */ +#include <stddef.h> + +/* Local includes. */ +#include "error.h" +#include "swift_velociraptor_part.h" +#include "velociraptor_interface.h" + +/* Dummy VELOCIraptor interface for testing compilation without linking the + * actual VELOCIraptor library. */ +#ifdef HAVE_DUMMY_VELOCIRAPTOR +struct cosmoinfo {}; +struct unitinfo {}; +struct cell_loc {}; +struct siminfo {}; + +int InitVelociraptor(char *config_name, char *output_name, + struct cosmoinfo cosmo_info, struct unitinfo unit_info, + struct siminfo sim_info) { + + error("This is only a dummy. Call the real one!"); + return 0; +} +int InvokeVelociraptor(const size_t num_gravity_parts, + const size_t num_hydro_parts, + struct swift_vel_part *swift_parts, + const int *cell_node_ids, char *output_name) { + + error("This is only a dummy. Call the real one!"); + return 0; +} +#endif /* HAVE_DUMMY_VELOCIRAPTOR */ diff --git a/src/velociraptor_interface.c b/src/velociraptor_interface.c index 7afaa2e66ee9993166caaead457b9bc226b9548b..7756fe4b937986c108d223c56183f7d31cdfaa98 100644 --- a/src/velociraptor_interface.c +++ b/src/velociraptor_interface.c @@ -35,6 +35,79 @@ #ifdef HAVE_VELOCIRAPTOR +/* Structure for passing cosmological information to VELOCIraptor. */ +struct cosmoinfo { + + /*! Current expansion factor of the Universe. (cosmology.a) */ + double atime; + + /*! Reduced Hubble constant (H0 / (100km/s/Mpc) (cosmology.h) */ + double littleh; + + /*! Matter density parameter (cosmology.Omega_m) */ + double Omega_m; + + /*! Baryon density parameter (cosmology.Omega_b) */ + double Omega_b; + + /*! Radiation constant density parameter (cosmology.Omega_lambda) */ + double Omega_Lambda; + + /*! Dark matter density parameter (cosmology.Omega_m - cosmology.Omega_b) */ + double Omega_cdm; + + /*! Dark-energy equation of state at the current time (cosmology.w)*/ + double w_de; +}; + +/* Structure for passing unit information to VELOCIraptor. */ +struct unitinfo { + + /* Length conversion factor to kpc. */ + double lengthtokpc; + + /* Velocity conversion factor to km/s. */ + double velocitytokms; + + /* Mass conversion factor to solar masses. */ + double masstosolarmass; + + /* Potential conversion factor. */ + double energyperunitmass; + + /*! Newton's gravitationl constant (phys_const.const_newton_G)*/ + double gravity; + + /*! Hubble constant at the current redshift (cosmology.H) */ + double hubbleunit; +}; + +/* Structure to hold the location of a top-level cell. */ +struct cell_loc { + + /* Coordinates x,y,z */ + double loc[3]; +}; + +/* Structure for passing simulation information to VELOCIraptor. */ +struct siminfo { + double period, zoomhigresolutionmass, interparticlespacing, spacedimension[3]; + + /* Number of top-cells. */ + int numcells; + + /*! Locations of top-level cells. */ + struct cell_loc *cell_loc; + + /*! Top-level cell width. */ + double cellwidth[3]; + + /*! Inverse of the top-level cell width. */ + double icellwidth[3]; + + int icosmologicalsim; +}; + /* VELOCIraptor interface. */ int InitVelociraptor(char *config_name, char *output_name, struct cosmoinfo cosmo_info, struct unitinfo unit_info, @@ -185,6 +258,7 @@ void velociraptor_invoke(struct engine *e) { struct space *s = e->s; struct gpart *gparts = s->gparts; struct part *parts = s->parts; + struct xpart *xparts = s->xparts; const size_t nr_gparts = s->nr_gparts; const size_t nr_hydro_parts = s->nr_parts; const int nr_cells = s->nr_cells; @@ -261,7 +335,8 @@ void velociraptor_invoke(struct engine *e) { swift_parts[i].id = parts[-gparts[i].id_or_neg_offset].id; swift_parts[i].u = hydro_get_physical_internal_energy( - &parts[-gparts[i].id_or_neg_offset], e->cosmology) * + &parts[-gparts[i].id_or_neg_offset], + &xparts[-gparts[i].id_or_neg_offset], e->cosmology) * energy_scale; } else if (gparts[i].type == swift_type_dark_matter) { swift_parts[i].id = gparts[i].id_or_neg_offset; diff --git a/src/velociraptor_interface.h b/src/velociraptor_interface.h index 0f6b8d339471f4bb1409baae62475a74e68cb5b1..1f29be11c9dd8e267c87201b0a438979fec3775b 100644 --- a/src/velociraptor_interface.h +++ b/src/velociraptor_interface.h @@ -22,81 +22,16 @@ /* Config parameters. */ #include "../config.h" -/* Forward declaration */ -struct engine; - -/* Structure for passing cosmological information to VELOCIraptor. */ -struct cosmoinfo { - - /*! Current expansion factor of the Universe. (cosmology.a) */ - double atime; - - /*! Reduced Hubble constant (H0 / (100km/s/Mpc) (cosmology.h) */ - double littleh; - - /*! Matter density parameter (cosmology.Omega_m) */ - double Omega_m; - - /*! Baryon density parameter (cosmology.Omega_b) */ - double Omega_b; - - /*! Radiation constant density parameter (cosmology.Omega_lambda) */ - double Omega_Lambda; - - /*! Dark matter density parameter (cosmology.Omega_m - cosmology.Omega_b) */ - double Omega_cdm; - - /*! Dark-energy equation of state at the current time (cosmology.w)*/ - double w_de; +/** + * @brief The different formats for when to run structure finding. + */ +enum io_stf_output_format { + io_stf_steps = 0, /*!< Output every N steps */ + io_stf_time /*!< Output at fixed time intervals */ }; -/* Structure for passing unit information to VELOCIraptor. */ -struct unitinfo { - - /* Length conversion factor to kpc. */ - double lengthtokpc; - - /* Velocity conversion factor to km/s. */ - double velocitytokms; - - /* Mass conversion factor to solar masses. */ - double masstosolarmass; - - /* Potential conversion factor. */ - double energyperunitmass; - - /*! Newton's gravitationl constant (phys_const.const_newton_G)*/ - double gravity; - - /*! Hubble constant at the current redshift (cosmology.H) */ - double hubbleunit; -}; - -/* Structure to hold the location of a top-level cell. */ -struct cell_loc { - - /* Coordinates x,y,z */ - double loc[3]; -}; - -/* Structure for passing simulation information to VELOCIraptor. */ -struct siminfo { - double period, zoomhigresolutionmass, interparticlespacing, spacedimension[3]; - - /* Number of top-cells. */ - int numcells; - - /*! Locations of top-level cells. */ - struct cell_loc *cell_loc; - - /*! Top-level cell width. */ - double cellwidth[3]; - - /*! Inverse of the top-level cell width. */ - double icellwidth[3]; - - int icosmologicalsim; -}; +/* Forward declaration */ +struct engine; /* VELOCIraptor wrapper functions. */ void velociraptor_init(struct engine *e); diff --git a/tests/Makefile.am b/tests/Makefile.am index 640c837b3bd1c3bf19d3d57ef080839b170427bf..9698e66d1a7a80566a9347bb629e9670eafbb98c 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -20,7 +20,7 @@ AM_CFLAGS = -I$(top_srcdir)/src $(HDF5_CPPFLAGS) $(GSL_INCS) $(FFTW_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) # List of programs and scripts to run in the test suite -TESTS = testGreetings testMaths testReading.sh testSingle testKernel testSymmetry \ +TESTS = testGreetings testMaths testReading.sh testSingle testKernel \ testActivePair.sh test27cells.sh test27cellsPerturbed.sh \ testParser.sh testSPHStep test125cells.sh test125cellsPerturbed.sh testFFT \ testAdiabaticIndex \ diff --git a/tests/logger.yml b/tests/logger.yml new file mode 100644 index 0000000000000000000000000000000000000000..eaf8731f0e09df40b891c7b57be35cd9e14fc5cc --- /dev/null +++ b/tests/logger.yml @@ -0,0 +1,5 @@ +# Parameters governing the logger snapshot system +Logger: + delta_step: 10 # (Optional) Update the particle log every this many updates + initial_buffer_size: .1 # buffer size in GB + basename: indice # Common part of the filenames diff --git a/tests/test125cells.c b/tests/test125cells.c index 2a2c20dbb064539b481e169b49b74389e79a8174..93a85bea87eb1b7c204f0cf9e6ea37ecea6d18f4 100644 --- a/tests/test125cells.c +++ b/tests/test125cells.c @@ -31,19 +31,12 @@ #include "swift.h" #if defined(WITH_VECTORIZATION) -#define DOSELF2 runner_doself2_force_vec -#define DOPAIR2 runner_dopair2_branch_force #define DOSELF2_NAME "runner_doself2_force_vec" #define DOPAIR2_NAME "runner_dopair2_force_vec" #endif -#ifndef DOSELF2 -#define DOSELF2 runner_doself2_force +#ifndef DOSELF2_NAME #define DOSELF2_NAME "runner_doself2_density" -#endif - -#ifndef DOPAIR2 -#define DOPAIR2 runner_dopair2_branch_force #define DOPAIR2_NAME "runner_dopair2_force" #endif @@ -152,19 +145,19 @@ void get_solution(const struct cell *main_cell, struct solution_part *solution, float density, enum velocity_field vel, enum pressure_field press, float size) { - for (int i = 0; i < main_cell->count; ++i) { + for (int i = 0; i < main_cell->hydro.count; ++i) { - solution[i].id = main_cell->parts[i].id; + solution[i].id = main_cell->hydro.parts[i].id; - solution[i].x[0] = main_cell->parts[i].x[0]; - solution[i].x[1] = main_cell->parts[i].x[1]; - solution[i].x[2] = main_cell->parts[i].x[2]; + solution[i].x[0] = main_cell->hydro.parts[i].x[0]; + solution[i].x[1] = main_cell->hydro.parts[i].x[1]; + solution[i].x[2] = main_cell->hydro.parts[i].x[2]; - solution[i].v[0] = main_cell->parts[i].v[0]; - solution[i].v[1] = main_cell->parts[i].v[1]; - solution[i].v[2] = main_cell->parts[i].v[2]; + solution[i].v[0] = main_cell->hydro.parts[i].v[0]; + solution[i].v[1] = main_cell->hydro.parts[i].v[1]; + solution[i].v[2] = main_cell->hydro.parts[i].v[2]; - solution[i].h = main_cell->parts[i].h; + solution[i].h = main_cell->hydro.parts[i].h; solution[i].rho = density; @@ -213,9 +206,9 @@ void reset_particles(struct cell *c, struct hydro_space *hs, enum velocity_field vel, enum pressure_field press, float size, float density) { - for (int i = 0; i < c->count; ++i) { + for (int i = 0; i < c->hydro.count; ++i) { - struct part *p = &c->parts[i]; + struct part *p = &c->hydro.parts[i]; set_velocity(p, vel, size); set_energy_state(p, press, size, density); @@ -272,20 +265,20 @@ struct cell *make_cell(size_t n, const double offset[3], double size, double h, struct cell *cell = (struct cell *)malloc(sizeof(struct cell)); bzero(cell, sizeof(struct cell)); - if (posix_memalign((void **)&cell->parts, part_align, + if (posix_memalign((void **)&cell->hydro.parts, part_align, count * sizeof(struct part)) != 0) error("couldn't allocate particles, no. of particles: %d", (int)count); - if (posix_memalign((void **)&cell->xparts, xpart_align, + if (posix_memalign((void **)&cell->hydro.xparts, xpart_align, count * sizeof(struct xpart)) != 0) error("couldn't allocate particles, no. of x-particles: %d", (int)count); - bzero(cell->parts, count * sizeof(struct part)); - bzero(cell->xparts, count * sizeof(struct xpart)); + bzero(cell->hydro.parts, count * sizeof(struct part)); + bzero(cell->hydro.xparts, count * sizeof(struct xpart)); float h_max = 0.f; /* Construct the parts */ - struct part *part = cell->parts; - struct xpart *xpart = cell->xparts; + struct part *part = cell->hydro.parts; + struct xpart *xpart = cell->hydro.xparts; for (size_t x = 0; x < n; ++x) { for (size_t y = 0; y < n; ++y) { for (size_t z = 0; z < n; ++z) { @@ -346,11 +339,11 @@ struct cell *make_cell(size_t n, const double offset[3], double size, double h, /* Cell properties */ cell->split = 0; - cell->h_max = h_max; - cell->count = count; - cell->gcount = 0; - cell->dx_max_part = 0.; - cell->dx_max_sort = 0.; + cell->hydro.h_max = h_max; + cell->hydro.count = count; + cell->grav.count = 0; + cell->hydro.dx_max_part = 0.; + cell->hydro.dx_max_sort = 0.; cell->width[0] = size; cell->width[1] = size; cell->width[2] = size; @@ -358,24 +351,24 @@ struct cell *make_cell(size_t n, const double offset[3], double size, double h, cell->loc[1] = offset[1]; cell->loc[2] = offset[2]; - cell->ti_old_part = 8; - cell->ti_hydro_end_min = 8; - cell->ti_hydro_end_max = 8; + cell->hydro.ti_old_part = 8; + cell->hydro.ti_end_min = 8; + cell->hydro.ti_end_max = 8; cell->nodeID = NODE_ID; - // shuffle_particles(cell->parts, cell->count); + // shuffle_particles(cell->hydro.parts, cell->hydro.count); - cell->sorted = 0; - for (int k = 0; k < 13; k++) cell->sort[k] = NULL; + cell->hydro.sorted = 0; + for (int k = 0; k < 13; k++) cell->hydro.sort[k] = NULL; return cell; } void clean_up(struct cell *ci) { - free(ci->parts); - free(ci->xparts); + free(ci->hydro.parts); + free(ci->hydro.xparts); for (int k = 0; k < 13; k++) - if (ci->sort[k] != NULL) free(ci->sort[k]); + if (ci->hydro.sort[k] != NULL) free(ci->hydro.sort[k]); free(ci); } @@ -397,37 +390,41 @@ void dump_particle_fields(char *fileName, struct cell *main_cell, fprintf(file, "# Main cell --------------------------------------------\n"); /* Write main cell */ - for (int pid = 0; pid < main_cell->count; pid++) { + for (int pid = 0; pid < main_cell->hydro.count; pid++) { fprintf(file, "%6llu %8.5f %8.5f %8.5f %8.5f %8.5f %8.5f %8.5f %8.5f %8.5f %8.5f " "%8.5f " "%8.5f %8.5f %13e %13e %13e %13e %13e %8.5f %8.5f\n", - main_cell->parts[pid].id, main_cell->parts[pid].x[0], - main_cell->parts[pid].x[1], main_cell->parts[pid].x[2], - main_cell->parts[pid].v[0], main_cell->parts[pid].v[1], - main_cell->parts[pid].v[2], main_cell->parts[pid].h, - hydro_get_comoving_density(&main_cell->parts[pid]), + main_cell->hydro.parts[pid].id, main_cell->hydro.parts[pid].x[0], + main_cell->hydro.parts[pid].x[1], main_cell->hydro.parts[pid].x[2], + main_cell->hydro.parts[pid].v[0], main_cell->hydro.parts[pid].v[1], + main_cell->hydro.parts[pid].v[2], main_cell->hydro.parts[pid].h, + hydro_get_comoving_density(&main_cell->hydro.parts[pid]), #if defined(MINIMAL_SPH) || defined(PLANETARY_SPH) || \ defined(GIZMO_MFV_SPH) || defined(SHADOWFAX_SPH) || \ defined(HOPKINS_PU_SPH) 0.f, #else - main_cell->parts[pid].density.div_v, + main_cell->hydro.parts[pid].density.div_v, #endif - hydro_get_comoving_entropy(&main_cell->parts[pid]), - hydro_get_comoving_internal_energy(&main_cell->parts[pid]), - hydro_get_comoving_pressure(&main_cell->parts[pid]), - hydro_get_comoving_soundspeed(&main_cell->parts[pid]), - main_cell->parts[pid].a_hydro[0], main_cell->parts[pid].a_hydro[1], - main_cell->parts[pid].a_hydro[2], main_cell->parts[pid].force.h_dt, + hydro_get_drifted_comoving_entropy(&main_cell->hydro.parts[pid]), + hydro_get_drifted_comoving_internal_energy( + &main_cell->hydro.parts[pid]), + hydro_get_comoving_pressure(&main_cell->hydro.parts[pid]), + hydro_get_comoving_soundspeed(&main_cell->hydro.parts[pid]), + main_cell->hydro.parts[pid].a_hydro[0], + main_cell->hydro.parts[pid].a_hydro[1], + main_cell->hydro.parts[pid].a_hydro[2], + main_cell->hydro.parts[pid].force.h_dt, #if defined(GADGET2_SPH) - main_cell->parts[pid].force.v_sig, main_cell->parts[pid].entropy_dt, - 0.f + main_cell->hydro.parts[pid].force.v_sig, + main_cell->hydro.parts[pid].entropy_dt, 0.f #elif defined(DEFAULT_SPH) - main_cell->parts[pid].force.v_sig, 0.f, - main_cell->parts[pid].force.u_dt + main_cell->hydro.parts[pid].force.v_sig, 0.f, + main_cell->hydro.parts[pid].force.u_dt #elif defined(MINIMAL_SPH) || defined(HOPKINS_PU_SPH) - main_cell->parts[pid].force.v_sig, 0.f, main_cell->parts[pid].u_dt + main_cell->hydro.parts[pid].force.v_sig, 0.f, + main_cell->hydro.parts[pid].u_dt #else 0.f, 0.f, 0.f #endif @@ -438,7 +435,7 @@ void dump_particle_fields(char *fileName, struct cell *main_cell, fprintf(file, "# Solution ---------------------------------------------\n"); - for (int pid = 0; pid < main_cell->count; pid++) { + for (int pid = 0; pid < main_cell->hydro.count; pid++) { fprintf(file, "%6llu %8.5f %8.5f %8.5f %8.5f %8.5f %8.5f %8.5f %8.5f %8.5f " "%8.5f %8.5f " @@ -586,6 +583,7 @@ int main(int argc, char *argv[]) { prog_const.const_newton_G = 1.f; struct hydro_props hp; + hydro_props_init_no_hydro(&hp); hp.eta_neighbours = h; hp.h_tolerance = 1e0; hp.h_max = FLT_MAX; @@ -640,7 +638,7 @@ int main(int argc, char *argv[]) { /* Construct the real solution */ struct solution_part *solution = (struct solution_part *)malloc( - main_cell->count * sizeof(struct solution_part)); + main_cell->hydro.count * sizeof(struct solution_part)); get_solution(main_cell, solution, rho, vel, press, size); ticks timings[27]; @@ -657,22 +655,21 @@ int main(int argc, char *argv[]) { /* Reset particles. */ for (int i = 0; i < 125; ++i) { - for (int pid = 0; pid < cells[i]->count; ++pid) - hydro_init_part(&cells[i]->parts[pid], &space.hs); + for (int pid = 0; pid < cells[i]->hydro.count; ++pid) + hydro_init_part(&cells[i]->hydro.parts[pid], &space.hs); } /* First, sort stuff */ for (int j = 0; j < 125; ++j) runner_do_sort(&runner, cells[j], 0x1FFF, 0, 0); -/* Do the density calculation */ -#if !(defined(MINIMAL_SPH) && defined(WITH_VECTORIZATION)) + /* Do the density calculation */ /* Initialise the particle cache. */ #ifdef WITH_VECTORIZATION runner.ci_cache.count = 0; - cache_init(&runner.ci_cache, 512); runner.cj_cache.count = 0; + cache_init(&runner.ci_cache, 512); cache_init(&runner.cj_cache, 512); #endif @@ -710,18 +707,15 @@ int main(int argc, char *argv[]) { for (int j = 0; j < 27; ++j) runner_doself1_density(&runner, inner_cells[j]); -#endif - /* Ghost to finish everything on the central cells */ for (int j = 0; j < 27; ++j) runner_do_ghost(&runner, inner_cells[j], 0); -/* Do the force calculation */ -#if !(defined(MINIMAL_SPH) && defined(WITH_VECTORIZATION)) + /* Do the force calculation */ #ifdef WITH_VECTORIZATION /* Initialise the cache. */ - runner.ci_cache.count = 0; - runner.cj_cache.count = 0; + cache_clean(&runner.ci_cache); + cache_clean(&runner.cj_cache); cache_init(&runner.ci_cache, 512); cache_init(&runner.cj_cache, 512); #endif @@ -738,7 +732,7 @@ int main(int argc, char *argv[]) { const ticks sub_tic = getticks(); - DOPAIR2(&runner, main_cell, cj); + runner_dopair2_branch_force(&runner, main_cell, cj); timings[ctr++] += getticks() - sub_tic; } @@ -749,10 +743,9 @@ int main(int argc, char *argv[]) { ticks self_tic = getticks(); /* And now the self-interaction for the main cell */ - DOSELF2(&runner, main_cell); + runner_doself2_force(&runner, main_cell); timings[26] += getticks() - self_tic; -#endif /* Finally, give a gentle kick */ runner_do_end_force(&runner, main_cell, 0); @@ -767,8 +760,8 @@ int main(int argc, char *argv[]) { } for (int i = 0; i < 125; ++i) { - for (int pid = 0; pid < cells[i]->count; ++pid) - hydro_init_part(&cells[i]->parts[pid], &space.hs); + for (int pid = 0; pid < cells[i]->hydro.count; ++pid) + hydro_init_part(&cells[i]->hydro.parts[pid], &space.hs); } } @@ -798,18 +791,17 @@ int main(int argc, char *argv[]) { const ticks tic = getticks(); -/* Kick the central cell */ -// runner_do_kick1(&runner, main_cell, 0); + /* Kick the central cell */ + // runner_do_kick1(&runner, main_cell, 0); -/* And drift it */ -// runner_do_drift_particles(&runner, main_cell, 0); + /* And drift it */ + // runner_do_drift_particles(&runner, main_cell, 0); -/* Initialise the particles */ -// for (int j = 0; j < 125; ++j) runner_do_drift_particles(&runner, cells[j], -// 0); + /* Initialise the particles */ + // for (int j = 0; j < 125; ++j) runner_do_drift_particles(&runner, cells[j], + // 0); -/* Do the density calculation */ -#if !(defined(MINIMAL_SPH) && defined(WITH_VECTORIZATION)) + /* Do the density calculation */ /* Run all the pairs (only once !)*/ for (int i = 0; i < 5; i++) { @@ -844,13 +836,10 @@ int main(int argc, char *argv[]) { /* And now the self-interaction for the central cells*/ for (int j = 0; j < 27; ++j) self_all_density(&runner, inner_cells[j]); -#endif - /* Ghost to finish everything on the central cells */ for (int j = 0; j < 27; ++j) runner_do_ghost(&runner, inner_cells[j], 0); -/* Do the force calculation */ -#if !(defined(MINIMAL_SPH) && defined(WITH_VECTORIZATION)) + /* Do the force calculation */ /* Do the pairs (for the central 27 cells) */ for (int i = 1; i < 4; i++) { @@ -867,8 +856,6 @@ int main(int argc, char *argv[]) { /* And now the self-interaction for the main cell */ self_all_force(&runner, main_cell); -#endif - /* Finally, give a gentle kick */ runner_do_end_force(&runner, main_cell, 0); // runner_do_kick2(&runner, main_cell, 0); @@ -886,5 +873,10 @@ int main(int argc, char *argv[]) { for (int i = 0; i < 125; ++i) clean_up(cells[i]); free(solution); +#ifdef WITH_VECTORIZATION + cache_clean(&runner.ci_cache); + cache_clean(&runner.cj_cache); +#endif + return 0; } diff --git a/tests/test27cells.c b/tests/test27cells.c index 1ca6b2c54d901943b0cc748a2241a3a2f9ae9244..ba98d91a4250865f301bd96594b1364d95034bbb 100644 --- a/tests/test27cells.c +++ b/tests/test27cells.c @@ -101,14 +101,14 @@ struct cell *make_cell(size_t n, double *offset, double size, double h, struct cell *cell = (struct cell *)malloc(sizeof(struct cell)); bzero(cell, sizeof(struct cell)); - if (posix_memalign((void **)&cell->parts, part_align, + if (posix_memalign((void **)&cell->hydro.parts, part_align, count * sizeof(struct part)) != 0) { error("couldn't allocate particles, no. of particles: %d", (int)count); } - bzero(cell->parts, count * sizeof(struct part)); + bzero(cell->hydro.parts, count * sizeof(struct part)); /* Construct the parts */ - struct part *part = cell->parts; + struct part *part = cell->hydro.parts; for (size_t x = 0; x < n; ++x) { for (size_t y = 0; y < n; ++y) { for (size_t z = 0; z < n; ++z) { @@ -182,10 +182,10 @@ struct cell *make_cell(size_t n, double *offset, double size, double h, /* Cell properties */ cell->split = 0; - cell->h_max = h_max; - cell->count = count; - cell->dx_max_part = 0.; - cell->dx_max_sort = 0.; + cell->hydro.h_max = h_max; + cell->hydro.count = count; + cell->hydro.dx_max_part = 0.; + cell->hydro.dx_max_sort = 0.; cell->width[0] = size; cell->width[1] = size; cell->width[2] = size; @@ -193,23 +193,23 @@ struct cell *make_cell(size_t n, double *offset, double size, double h, cell->loc[1] = offset[1]; cell->loc[2] = offset[2]; - cell->ti_old_part = 8; - cell->ti_hydro_end_min = 8; - cell->ti_hydro_end_max = 8; + cell->hydro.ti_old_part = 8; + cell->hydro.ti_end_min = 8; + cell->hydro.ti_end_max = 8; cell->nodeID = NODE_ID; - shuffle_particles(cell->parts, cell->count); + shuffle_particles(cell->hydro.parts, cell->hydro.count); - cell->sorted = 0; - for (int k = 0; k < 13; k++) cell->sort[k] = NULL; + cell->hydro.sorted = 0; + for (int k = 0; k < 13; k++) cell->hydro.sort[k] = NULL; return cell; } void clean_up(struct cell *ci) { - free(ci->parts); + free(ci->hydro.parts); for (int k = 0; k < 13; k++) - if (ci->sort[k] != NULL) free(ci->sort[k]); + if (ci->hydro.sort[k] != NULL) free(ci->hydro.sort[k]); free(ci); } @@ -229,8 +229,8 @@ void zero_particle_fields(struct cell *c) { #else struct hydro_space *hspointer = NULL; #endif - for (int pid = 0; pid < c->count; pid++) { - hydro_init_part(&c->parts[pid], hspointer); + for (int pid = 0; pid < c->hydro.count; pid++) { + hydro_init_part(&c->hydro.parts[pid], hspointer); } } @@ -238,12 +238,12 @@ void zero_particle_fields(struct cell *c) { * @brief Ends the loop by adding the appropriate coefficients */ void end_calculation(struct cell *c, const struct cosmology *cosmo) { - for (int pid = 0; pid < c->count; pid++) { - hydro_end_density(&c->parts[pid], cosmo); + for (int pid = 0; pid < c->hydro.count; pid++) { + hydro_end_density(&c->hydro.parts[pid], cosmo); /* Recover the common "Neighbour number" definition */ - c->parts[pid].density.wcount *= pow_dimension(c->parts[pid].h); - c->parts[pid].density.wcount *= kernel_norm; + c->hydro.parts[pid].density.wcount *= pow_dimension(c->hydro.parts[pid].h); + c->hydro.parts[pid].density.wcount *= kernel_norm; } } @@ -264,30 +264,30 @@ void dump_particle_fields(char *fileName, struct cell *main_cell, fprintf(file, "# Main cell --------------------------------------------\n"); /* Write main cell */ - for (int pid = 0; pid < main_cell->count; pid++) { + for (int pid = 0; pid < main_cell->hydro.count; pid++) { fprintf(file, "%6llu %10f %10f %10f %10f %10f %10f %13e %13e %13e %13e %13e " "%13e %13e %13e\n", - main_cell->parts[pid].id, main_cell->parts[pid].x[0], - main_cell->parts[pid].x[1], main_cell->parts[pid].x[2], - main_cell->parts[pid].v[0], main_cell->parts[pid].v[1], - main_cell->parts[pid].v[2], - hydro_get_comoving_density(&main_cell->parts[pid]), + main_cell->hydro.parts[pid].id, main_cell->hydro.parts[pid].x[0], + main_cell->hydro.parts[pid].x[1], main_cell->hydro.parts[pid].x[2], + main_cell->hydro.parts[pid].v[0], main_cell->hydro.parts[pid].v[1], + main_cell->hydro.parts[pid].v[2], + hydro_get_comoving_density(&main_cell->hydro.parts[pid]), #if defined(GIZMO_MFV_SPH) || defined(SHADOWFAX_SPH) 0.f, #elif defined(HOPKINS_PU_SPH) - main_cell->parts[pid].density.pressure_bar_dh, + main_cell->hydro.parts[pid].density.pressure_bar_dh, #else - main_cell->parts[pid].density.rho_dh, + main_cell->hydro.parts[pid].density.rho_dh, #endif - main_cell->parts[pid].density.wcount, - main_cell->parts[pid].density.wcount_dh, + main_cell->hydro.parts[pid].density.wcount, + main_cell->hydro.parts[pid].density.wcount_dh, #if defined(GADGET2_SPH) || defined(DEFAULT_SPH) || defined(HOPKINS_PE_SPH) || \ defined(HOPKINS_PU_SPH) - main_cell->parts[pid].density.div_v, - main_cell->parts[pid].density.rot_v[0], - main_cell->parts[pid].density.rot_v[1], - main_cell->parts[pid].density.rot_v[2] + main_cell->hydro.parts[pid].density.div_v, + main_cell->hydro.parts[pid].density.rot_v[0], + main_cell->hydro.parts[pid].density.rot_v[1], + main_cell->hydro.parts[pid].density.rot_v[2] #else 0., 0., 0., 0. #endif @@ -305,23 +305,28 @@ void dump_particle_fields(char *fileName, struct cell *main_cell, "# Offset: [%2d %2d %2d] -----------------------------------\n", i - 1, j - 1, k - 1); - for (int pjd = 0; pjd < cj->count; pjd++) { + for (int pjd = 0; pjd < cj->hydro.count; pjd++) { fprintf( file, "%6llu %10f %10f %10f %10f %10f %10f %13e %13e %13e %13e %13e " "%13e %13e %13e\n", - cj->parts[pjd].id, cj->parts[pjd].x[0], cj->parts[pjd].x[1], - cj->parts[pjd].x[2], cj->parts[pjd].v[0], cj->parts[pjd].v[1], - cj->parts[pjd].v[2], hydro_get_comoving_density(&cj->parts[pjd]), + cj->hydro.parts[pjd].id, cj->hydro.parts[pjd].x[0], + cj->hydro.parts[pjd].x[1], cj->hydro.parts[pjd].x[2], + cj->hydro.parts[pjd].v[0], cj->hydro.parts[pjd].v[1], + cj->hydro.parts[pjd].v[2], + hydro_get_comoving_density(&cj->hydro.parts[pjd]), #if defined(GIZMO_MFV_SPH) || defined(SHADOWFAX_SPH) 0.f, #else - main_cell->parts[pjd].density.rho_dh, + main_cell->hydro.parts[pjd].density.rho_dh, #endif - cj->parts[pjd].density.wcount, cj->parts[pjd].density.wcount_dh, + cj->hydro.parts[pjd].density.wcount, + cj->hydro.parts[pjd].density.wcount_dh, #if defined(GADGET2_SPH) || defined(DEFAULT_SPH) || defined(HOPKINS_PE_SPH) - cj->parts[pjd].density.div_v, cj->parts[pjd].density.rot_v[0], - cj->parts[pjd].density.rot_v[1], cj->parts[pjd].density.rot_v[2] + cj->hydro.parts[pjd].density.div_v, + cj->hydro.parts[pjd].density.rot_v[0], + cj->hydro.parts[pjd].density.rot_v[1], + cj->hydro.parts[pjd].density.rot_v[2] #else 0., 0., 0., 0. #endif @@ -451,6 +456,7 @@ int main(int argc, char *argv[]) { space.dim[2] = 3.; struct hydro_props hp; + hydro_props_init_no_hydro(&hp); hp.eta_neighbours = h; hp.h_tolerance = 1e0; hp.h_max = FLT_MAX; @@ -514,10 +520,10 @@ int main(int argc, char *argv[]) { #if defined(TEST_DOSELF_SUBSET) || defined(TEST_DOPAIR_SUBSET) int *pid = NULL; int count = 0; - if ((pid = (int *)malloc(sizeof(int) * main_cell->count)) == NULL) + if ((pid = (int *)malloc(sizeof(int) * main_cell->hydro.count)) == NULL) error("Can't allocate memory for pid."); - for (int k = 0; k < main_cell->count; k++) - if (part_is_active(&main_cell->parts[k], &engine)) { + for (int k = 0; k < main_cell->hydro.count; k++) + if (part_is_active(&main_cell->hydro.parts[k], &engine)) { pid[count] = k; ++count; } @@ -529,7 +535,7 @@ int main(int argc, char *argv[]) { const ticks sub_tic = getticks(); #ifdef TEST_DOPAIR_SUBSET - DOPAIR1_SUBSET(&runner, main_cell, main_cell->parts, pid, count, + DOPAIR1_SUBSET(&runner, main_cell, main_cell->hydro.parts, pid, count, cells[j]); #else DOPAIR1(&runner, main_cell, cells[j]); @@ -543,7 +549,7 @@ int main(int argc, char *argv[]) { const ticks self_tic = getticks(); #ifdef TEST_DOSELF_SUBSET - DOSELF1_SUBSET(&runner, main_cell, main_cell->parts, pid, count); + DOSELF1_SUBSET(&runner, main_cell, main_cell->hydro.parts, pid, count); #else DOSELF1(&runner, main_cell); #endif @@ -610,5 +616,10 @@ int main(int argc, char *argv[]) { /* Clean things to make the sanitizer happy ... */ for (int i = 0; i < 27; ++i) clean_up(cells[i]); +#ifdef WITH_VECTORIZATION + cache_clean(&runner.ci_cache); + cache_clean(&runner.cj_cache); +#endif + return 0; } diff --git a/tests/test27cellsStars.c b/tests/test27cellsStars.c index 1ed4798c773c7db01c19d7305365eccf1a9fe8af..3875bf75b1bb315bf48acae13b9553c689416a18 100644 --- a/tests/test27cellsStars.c +++ b/tests/test27cellsStars.c @@ -73,14 +73,14 @@ struct cell *make_cell(size_t n, size_t n_stars, double *offset, double size, struct cell *cell = (struct cell *)malloc(sizeof(struct cell)); bzero(cell, sizeof(struct cell)); - if (posix_memalign((void **)&cell->parts, part_align, + if (posix_memalign((void **)&cell->hydro.parts, part_align, count * sizeof(struct part)) != 0) { error("couldn't allocate particles, no. of particles: %d", (int)count); } - bzero(cell->parts, count * sizeof(struct part)); + bzero(cell->hydro.parts, count * sizeof(struct part)); /* Construct the parts */ - struct part *part = cell->parts; + struct part *part = cell->hydro.parts; for (size_t x = 0; x < n; ++x) { for (size_t y = 0; y < n; ++y) { for (size_t z = 0; z < n; ++z) { @@ -116,13 +116,13 @@ struct cell *make_cell(size_t n, size_t n_stars, double *offset, double size, } /* Construct the sparts */ - if (posix_memalign((void **)&cell->sparts, spart_align, + if (posix_memalign((void **)&cell->stars.parts, spart_align, scount * sizeof(struct spart)) != 0) { error("couldn't allocate particles, no. of particles: %d", (int)scount); } - bzero(cell->sparts, scount * sizeof(struct spart)); + bzero(cell->stars.parts, scount * sizeof(struct spart)); - struct spart *spart = cell->sparts; + struct spart *spart = cell->stars.parts; for (size_t x = 0; x < n_stars; ++x) { for (size_t y = 0; y < n_stars; ++y) { for (size_t z = 0; z < n_stars; ++z) { @@ -159,11 +159,11 @@ struct cell *make_cell(size_t n, size_t n_stars, double *offset, double size, /* Cell properties */ cell->split = 0; - cell->h_max = h_max; - cell->count = count; - cell->scount = scount; - cell->dx_max_part = 0.; - cell->dx_max_sort = 0.; + cell->hydro.h_max = h_max; + cell->hydro.count = count; + cell->stars.count = scount; + cell->hydro.dx_max_part = 0.; + cell->hydro.dx_max_sort = 0.; cell->width[0] = size; cell->width[1] = size; cell->width[2] = size; @@ -171,27 +171,27 @@ struct cell *make_cell(size_t n, size_t n_stars, double *offset, double size, cell->loc[1] = offset[1]; cell->loc[2] = offset[2]; - cell->ti_old_part = 8; - cell->ti_hydro_end_min = 8; - cell->ti_hydro_end_max = 8; - cell->ti_gravity_end_min = 8; - cell->ti_gravity_end_max = 8; + cell->hydro.ti_old_part = 8; + cell->hydro.ti_end_min = 8; + cell->hydro.ti_end_max = 8; + cell->grav.ti_end_min = 8; + cell->grav.ti_end_max = 8; cell->nodeID = NODE_ID; - shuffle_particles(cell->parts, cell->count); - shuffle_sparticles(cell->sparts, cell->scount); + shuffle_particles(cell->hydro.parts, cell->hydro.count); + shuffle_sparticles(cell->stars.parts, cell->stars.count); - cell->sorted = 0; - for (int k = 0; k < 13; k++) cell->sort[k] = NULL; + cell->hydro.sorted = 0; + for (int k = 0; k < 13; k++) cell->hydro.sort[k] = NULL; return cell; } void clean_up(struct cell *ci) { - free(ci->parts); - free(ci->sparts); + free(ci->hydro.parts); + free(ci->stars.parts); for (int k = 0; k < 13; k++) - if (ci->sort[k] != NULL) free(ci->sort[k]); + if (ci->hydro.sort[k] != NULL) free(ci->hydro.sort[k]); free(ci); } @@ -199,8 +199,8 @@ void clean_up(struct cell *ci) { * @brief Initializes all particles field to be ready for a density calculation */ void zero_particle_fields(struct cell *c) { - for (int pid = 0; pid < c->scount; pid++) { - stars_init_spart(&c->sparts[pid]); + for (int pid = 0; pid < c->stars.count; pid++) { + stars_init_spart(&c->stars.parts[pid]); } } @@ -208,12 +208,12 @@ void zero_particle_fields(struct cell *c) { * @brief Ends the loop by adding the appropriate coefficients */ void end_calculation(struct cell *c, const struct cosmology *cosmo) { - for (int pid = 0; pid < c->scount; pid++) { - stars_end_density(&c->sparts[pid], cosmo); + for (int pid = 0; pid < c->stars.count; pid++) { + stars_end_density(&c->stars.parts[pid], cosmo); /* Recover the common "Neighbour number" definition */ - c->sparts[pid].density.wcount *= pow_dimension(c->sparts[pid].h); - c->sparts[pid].density.wcount *= kernel_norm; + c->stars.parts[pid].density.wcount *= pow_dimension(c->stars.parts[pid].h); + c->stars.parts[pid].density.wcount *= kernel_norm; } } @@ -231,11 +231,12 @@ void dump_particle_fields(char *fileName, struct cell *main_cell, fprintf(file, "# Main cell --------------------------------------------\n"); /* Write main cell */ - for (int pid = 0; pid < main_cell->scount; pid++) { - fprintf(file, "%6llu %10f %10f %10f %13e %13e\n", main_cell->sparts[pid].id, - main_cell->sparts[pid].x[0], main_cell->sparts[pid].x[1], - main_cell->sparts[pid].x[2], main_cell->sparts[pid].density.wcount, - main_cell->sparts[pid].density.wcount_dh); + for (int pid = 0; pid < main_cell->stars.count; pid++) { + fprintf(file, "%6llu %10f %10f %10f %13e %13e\n", + main_cell->stars.parts[pid].id, main_cell->stars.parts[pid].x[0], + main_cell->stars.parts[pid].x[1], main_cell->stars.parts[pid].x[2], + main_cell->stars.parts[pid].density.wcount, + main_cell->stars.parts[pid].density.wcount_dh); } /* Write all other cells */ @@ -249,11 +250,12 @@ void dump_particle_fields(char *fileName, struct cell *main_cell, "# Offset: [%2d %2d %2d] -----------------------------------\n", i - 1, j - 1, k - 1); - for (int pjd = 0; pjd < cj->scount; pjd++) { - fprintf(file, "%6llu %10f %10f %10f %13e %13e\n", cj->sparts[pjd].id, - cj->sparts[pjd].x[0], cj->sparts[pjd].x[1], - cj->sparts[pjd].x[2], cj->sparts[pjd].density.wcount, - cj->sparts[pjd].density.wcount_dh); + for (int pjd = 0; pjd < cj->stars.count; pjd++) { + fprintf(file, "%6llu %10f %10f %10f %13e %13e\n", + cj->stars.parts[pjd].id, cj->stars.parts[pjd].x[0], + cj->stars.parts[pjd].x[1], cj->stars.parts[pjd].x[2], + cj->stars.parts[pjd].density.wcount, + cj->stars.parts[pjd].density.wcount_dh); } } } @@ -433,10 +435,10 @@ int main(int argc, char *argv[]) { #if defined(TEST_DOSELF_SUBSET) || defined(TEST_DOPAIR_SUBSET) int *pid = NULL; int scount = 0; - if ((pid = (int *)malloc(sizeof(int) * main_cell->scount)) == NULL) + if ((pid = (int *)malloc(sizeof(int) * main_cell->stars.count)) == NULL) error("Can't allocate memory for pid."); - for (int k = 0; k < main_cell->scount; k++) - if (spart_is_active(&main_cell->sparts[k], &engine)) { + for (int k = 0; k < main_cell->stars.count; k++) + if (spart_is_active(&main_cell->stars.parts[k], &engine)) { pid[scount] = k; ++scount; } @@ -448,7 +450,7 @@ int main(int argc, char *argv[]) { const ticks sub_tic = getticks(); #ifdef TEST_DOPAIR_SUBSET - DOPAIR1_SUBSET(&runner, main_cell, main_cell->sparts, pid, scount, + DOPAIR1_SUBSET(&runner, main_cell, main_cell->stars.parts, pid, scount, cells[j]); #else DOPAIR1(&runner, main_cell, cells[j]); @@ -462,7 +464,7 @@ int main(int argc, char *argv[]) { const ticks self_tic = getticks(); #ifdef TEST_DOSELF_SUBSET - DOSELF1_SUBSET(&runner, main_cell, main_cell->sparts, pid, scount); + DOSELF1_SUBSET(&runner, main_cell, main_cell->stars.parts, pid, scount); #else DOSELF1(&runner, main_cell); #endif diff --git a/tests/testActivePair.c b/tests/testActivePair.c index be9c2928f3f9af1ca05dc6a4cb4f715d0751d490..dd7b4c6277142f4e074fc154aac455c355200816 100644 --- a/tests/testActivePair.c +++ b/tests/testActivePair.c @@ -33,7 +33,8 @@ /* Typdef function pointer for interaction function. */ typedef void (*interaction_func)(struct runner *, struct cell *, struct cell *); -typedef void (*init_func)(struct cell *, const struct cosmology *); +typedef void (*init_func)(struct cell *, const struct cosmology *, + const struct hydro_props *); typedef void (*finalise_func)(struct cell *, const struct cosmology *); /** @@ -62,14 +63,14 @@ struct cell *make_cell(size_t n, double *offset, double size, double h, struct cell *cell = (struct cell *)malloc(sizeof(struct cell)); bzero(cell, sizeof(struct cell)); - if (posix_memalign((void **)&cell->parts, part_align, + if (posix_memalign((void **)&cell->hydro.parts, part_align, count * sizeof(struct part)) != 0) { error("couldn't allocate particles, no. of particles: %d", (int)count); } - bzero(cell->parts, count * sizeof(struct part)); + bzero(cell->hydro.parts, count * sizeof(struct part)); /* Construct the parts */ - struct part *part = cell->parts; + struct part *part = cell->hydro.parts; for (size_t x = 0; x < n; ++x) { for (size_t y = 0; y < n; ++y) { for (size_t z = 0; z < n; ++z) { @@ -135,10 +136,10 @@ struct cell *make_cell(size_t n, double *offset, double size, double h, /* Cell properties */ cell->split = 0; - cell->h_max = h_max; - cell->count = count; - cell->dx_max_part = 0.; - cell->dx_max_sort = 0.; + cell->hydro.h_max = h_max; + cell->hydro.count = count; + cell->hydro.dx_max_part = 0.; + cell->hydro.dx_max_sort = 0.; cell->width[0] = size; cell->width[1] = size; cell->width[2] = size; @@ -146,43 +147,44 @@ struct cell *make_cell(size_t n, double *offset, double size, double h, cell->loc[1] = offset[1]; cell->loc[2] = offset[2]; - cell->ti_old_part = 8; - cell->ti_hydro_end_min = 8; - cell->ti_hydro_end_max = 10; + cell->hydro.ti_old_part = 8; + cell->hydro.ti_end_min = 8; + cell->hydro.ti_end_max = 10; cell->nodeID = NODE_ID; - shuffle_particles(cell->parts, cell->count); + shuffle_particles(cell->hydro.parts, cell->hydro.count); - cell->sorted = 0; - for (int k = 0; k < 13; k++) cell->sort[k] = NULL; + cell->hydro.sorted = 0; + for (int k = 0; k < 13; k++) cell->hydro.sort[k] = NULL; return cell; } void clean_up(struct cell *ci) { - free(ci->parts); + free(ci->hydro.parts); for (int k = 0; k < 13; k++) - if (ci->sort[k] != NULL) free(ci->sort[k]); + if (ci->hydro.sort[k] != NULL) free(ci->hydro.sort[k]); free(ci); } /** * @brief Initializes all particles field to be ready for a density calculation */ -void zero_particle_fields_density(struct cell *c, - const struct cosmology *cosmo) { - for (int pid = 0; pid < c->count; pid++) { - hydro_init_part(&c->parts[pid], NULL); +void zero_particle_fields_density(struct cell *c, const struct cosmology *cosmo, + const struct hydro_props *hydro_props) { + for (int pid = 0; pid < c->hydro.count; pid++) { + hydro_init_part(&c->hydro.parts[pid], NULL); } } /** * @brief Initializes all particles field to be ready for a force calculation */ -void zero_particle_fields_force(struct cell *c, const struct cosmology *cosmo) { - for (int pid = 0; pid < c->count; pid++) { - struct part *p = &c->parts[pid]; - struct xpart *xp = &c->xparts[pid]; +void zero_particle_fields_force(struct cell *c, const struct cosmology *cosmo, + const struct hydro_props *hydro_props) { + for (int pid = 0; pid < c->hydro.count; pid++) { + struct part *p = &c->hydro.parts[pid]; + struct xpart *xp = &c->hydro.xparts[pid]; /* Mimic the result of a density calculation */ #ifdef GADGET2_SPH @@ -219,7 +221,7 @@ void zero_particle_fields_force(struct cell *c, const struct cosmology *cosmo) { #endif /* PRESSURE-ENERGY */ /* And prepare for a round of force tasks. */ - hydro_prepare_force(p, xp, cosmo, 0.); + hydro_prepare_force(p, xp, cosmo, hydro_props, 0.); hydro_reset_acceleration(p); } } @@ -228,12 +230,12 @@ void zero_particle_fields_force(struct cell *c, const struct cosmology *cosmo) { * @brief Ends the density loop by adding the appropriate coefficients */ void end_calculation_density(struct cell *c, const struct cosmology *cosmo) { - for (int pid = 0; pid < c->count; pid++) { - hydro_end_density(&c->parts[pid], cosmo); + for (int pid = 0; pid < c->hydro.count; pid++) { + hydro_end_density(&c->hydro.parts[pid], cosmo); /* Recover the common "Neighbour number" definition */ - c->parts[pid].density.wcount *= pow_dimension(c->parts[pid].h); - c->parts[pid].density.wcount *= kernel_norm; + c->hydro.parts[pid].density.wcount *= pow_dimension(c->hydro.parts[pid].h); + c->hydro.parts[pid].density.wcount *= kernel_norm; } } @@ -241,8 +243,8 @@ void end_calculation_density(struct cell *c, const struct cosmology *cosmo) { * @brief Ends the force loop by adding the appropriate coefficients */ void end_calculation_force(struct cell *c, const struct cosmology *cosmo) { - for (int pid = 0; pid < c->count; pid++) { - hydro_end_force(&c->parts[pid], cosmo); + for (int pid = 0; pid < c->hydro.count; pid++) { + hydro_end_force(&c->hydro.parts[pid], cosmo); } } @@ -257,16 +259,18 @@ void dump_particle_fields(char *fileName, struct cell *ci, struct cell *cj) { fprintf(file, "# ci --------------------------------------------\n"); - for (int pid = 0; pid < ci->count; pid++) { - fprintf(file, "%6llu %13e %13e\n", ci->parts[pid].id, - ci->parts[pid].density.wcount, ci->parts[pid].force.h_dt); + for (int pid = 0; pid < ci->hydro.count; pid++) { + fprintf(file, "%6llu %13e %13e\n", ci->hydro.parts[pid].id, + ci->hydro.parts[pid].density.wcount, + ci->hydro.parts[pid].force.h_dt); } fprintf(file, "# cj --------------------------------------------\n"); - for (int pjd = 0; pjd < cj->count; pjd++) { - fprintf(file, "%6llu %13e %13e\n", cj->parts[pjd].id, - cj->parts[pjd].density.wcount, cj->parts[pjd].force.h_dt); + for (int pjd = 0; pjd < cj->hydro.count; pjd++) { + fprintf(file, "%6llu %13e %13e\n", cj->hydro.parts[pjd].id, + cj->hydro.parts[pjd].density.wcount, + cj->hydro.parts[pjd].force.h_dt); } fclose(file); @@ -297,8 +301,8 @@ void test_pair_interactions(struct runner *runner, struct cell **ci, runner_do_sort(runner, *cj, 0x1FFF, 0, 0); /* Zero the fields */ - init(*ci, runner->e->cosmology); - init(*cj, runner->e->cosmology); + init(*ci, runner->e->cosmology, runner->e->hydro_properties); + init(*cj, runner->e->cosmology, runner->e->hydro_properties); /* Run the test */ vec_interaction(runner, *ci, *cj); @@ -313,8 +317,8 @@ void test_pair_interactions(struct runner *runner, struct cell **ci, /* Now perform a brute-force version for accuracy tests */ /* Zero the fields */ - init(*ci, runner->e->cosmology); - init(*cj, runner->e->cosmology); + init(*ci, runner->e->cosmology, runner->e->hydro_properties); + init(*cj, runner->e->cosmology, runner->e->hydro_properties); /* Run the brute-force test */ serial_interaction(runner, *ci, *cj); @@ -485,6 +489,7 @@ int main(int argc, char *argv[]) { struct space space; struct engine engine; struct cosmology cosmo; + struct hydro_props hydro_props; struct runner *runner; char c; static long long partId = 0; @@ -569,6 +574,8 @@ int main(int argc, char *argv[]) { cosmology_init_no_cosmo(&cosmo); engine.cosmology = &cosmo; + hydro_props_init_no_hydro(&hydro_props); + engine.hydro_properties = &hydro_props; if (posix_memalign((void **)&runner, SWIFT_STRUCT_ALIGNMENT, sizeof(struct runner)) != 0) { diff --git a/tests/testAdiabaticIndex.c b/tests/testAdiabaticIndex.c index 60ecefa264f48bed2d4df205766dc392a1a03d0f..6aa794207f0e23e6a26060f3ef98b7ee841d7a32 100644 --- a/tests/testAdiabaticIndex.c +++ b/tests/testAdiabaticIndex.c @@ -34,7 +34,8 @@ */ void check_value(float a, float b, const char* s) { if (fabsf(a - b) / fabsf(a + b) > 1.e-6f) - error("Values are inconsistent: %12.15e %12.15e (%s)!", a, b, s); + error("Values are inconsistent: %12.15e %12.15e rel=%e (%s)!", a, b, + fabsf(a - b) / fabsf(a + b), s); } /** @@ -77,36 +78,61 @@ void check_constants(void) { void check_functions(float x) { float val_a, val_b; + const double xx = x; + +#if defined(HYDRO_GAMMA_5_3) +#define hydro_gamma_d (5. / 3.) +#elif defined(HYDRO_GAMMA_7_5) +#define hydro_gamma_d (7. / 5.) +#elif defined(HYDRO_GAMMA_4_3) +#define hydro_gamma_d (4. / 3.) +#elif defined(HYDRO_GAMMA_2_1) +#define hydro_gamma_d (2. / 1.) +#else +#error "Need to choose an adiabatic index!" +#endif + + val_a = pow(xx, hydro_gamma_d); + val_b = pow_gamma(x); + check_value(val_a, val_b, "x^gamma"); + + val_a = pow(xx, hydro_gamma_d - 1.0); + val_b = pow_gamma_minus_one(x); + check_value(val_a, val_b, "x^(gamma - 1)"); + + val_a = pow(xx, -(hydro_gamma_d - 1.0)); + val_b = pow_minus_gamma_minus_one(x); + check_value(val_a, val_b, "x^(-(gamma - 1))"); - val_a = powf(x, -hydro_gamma); + val_a = pow(xx, -hydro_gamma_d); val_b = pow_minus_gamma(x); check_value(val_a, val_b, "x^(-gamma)"); - val_a = powf(x, 2.0f / (hydro_gamma - 1.0f)); + val_a = pow(xx, 2.0 / (hydro_gamma_d - 1.0)); val_b = pow_two_over_gamma_minus_one(x); check_value(val_a, val_b, "x^(2/(gamma-1))"); - val_a = powf(x, 2.0f * hydro_gamma / (hydro_gamma - 1.0f)); + val_a = pow(xx, 2.0 * hydro_gamma_d / (hydro_gamma_d - 1.0)); val_b = pow_two_gamma_over_gamma_minus_one(x); check_value(val_a, val_b, "x^((2 gamma)/(gamma-1))"); - val_a = powf(x, 0.5f * (hydro_gamma - 1.0f) / hydro_gamma); + val_a = pow(xx, (hydro_gamma_d - 1.0) / (2.0 * hydro_gamma_d)); val_b = pow_gamma_minus_one_over_two_gamma(x); check_value(val_a, val_b, "x^((gamma-1)/(2 gamma))"); - val_a = powf(x, -0.5f * (hydro_gamma + 1.0f) / hydro_gamma); + val_a = pow(xx, -(hydro_gamma_d + 1.0) / (2.0 * hydro_gamma_d)); val_b = pow_minus_gamma_plus_one_over_two_gamma(x); check_value(val_a, val_b, "x^(-(gamma+1)/(2 gamma))"); - val_a = powf(x, 1.0f / hydro_gamma); + val_a = pow(xx, 1.0 / hydro_gamma_d); val_b = pow_one_over_gamma(x); check_value(val_a, val_b, "x^(1/gamma)"); - val_a = powf(x, 3.f * hydro_gamma - 2.f); + val_a = pow(xx, 3. * hydro_gamma_d - 2.); val_b = pow_three_gamma_minus_two(x); check_value(val_a, val_b, "x^(3gamma - 2)"); - val_a = powf(x, (3.f * hydro_gamma - 5.f) / 2.f); + val_a = pow(xx, (3. * hydro_gamma_d - 5.) / 2.); val_b = pow_three_gamma_minus_five_over_two(x); check_value(val_a, val_b, "x^((3gamma - 5)/2)"); } diff --git a/tests/testCbrt.c b/tests/testCbrt.c index b608f9a00d619570c298f4123038f930584a245c..3663e0e19ad2a5ad35d67703e00f5c0309a3eb00 100644 --- a/tests/testCbrt.c +++ b/tests/testCbrt.c @@ -125,5 +125,6 @@ int main(int argc, char *argv[]) { message("x * icbrtf took %9.3f %s (acc = %18.11e).", clocks_from_ticks(getticks() - tic_ours), clocks_getunit(), acc_ours); + free(data); return 0; } diff --git a/tests/testDump.c b/tests/testDump.c index f47a44256536d6ac1d9676c844f7081a6daa5ca4..878daae9cc0deddd6f9fb02857041f705110743c 100644 --- a/tests/testDump.c +++ b/tests/testDump.c @@ -73,7 +73,7 @@ int main(int argc, char *argv[]) { for (int run = 0; run < num_runs; run++) { /* Ensure capacity. */ - dump_ensure(&d, 7 * chunk_size); + dump_ensure(&d, 7 * chunk_size, 7 * chunk_size); /* Dump a few numbers. */ printf("dumping %i chunks...\n", chunk_size); diff --git a/tests/testInteractions.c b/tests/testInteractions.c index 306f14a35ca047430f67e33e9fd63848e9207b68..19eb44fa79759f50da2611cd764a1b59bd1dc579 100644 --- a/tests/testInteractions.c +++ b/tests/testInteractions.c @@ -16,12 +16,16 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * ******************************************************************************/ +#include "../config.h" +/* Some standard headers. */ #include <fenv.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> + +/* Local includes */ #include "swift.h" /* Other schemes need to be added here if they are not vectorized, otherwise @@ -141,7 +145,8 @@ void dump_indv_particle_fields(char *fileName, struct part *p) { #else p->density.div_v, #endif - hydro_get_comoving_entropy(p), hydro_get_comoving_internal_energy(p), + hydro_get_drifted_comoving_entropy(p), + hydro_get_drifted_comoving_internal_energy(p), hydro_get_comoving_pressure(p), hydro_get_comoving_soundspeed(p), p->a_hydro[0], p->a_hydro[1], p->a_hydro[2], p->force.h_dt, #if defined(GADGET2_SPH) diff --git a/tests/testLogger.c b/tests/testLogger.c index ee933500ab585d286c9dea7370b0d208573ca7d2..c5be0d7cc18742bdc2fa6167462579c45fd43e92 100644 --- a/tests/testLogger.c +++ b/tests/testLogger.c @@ -20,7 +20,8 @@ /* Config parameters. */ #include "../config.h" -#ifdef HAVE_POSIX_FALLOCATE /* Are we on a sensible platform? */ +#if defined(HAVE_POSIX_FALLOCATE) && \ + defined(WITH_LOGGER) /* Are we on a sensible platform? */ /* Some standard headers. */ #include <stdio.h> @@ -31,7 +32,8 @@ /* Local headers. */ #include "swift.h" -void test_log_parts(struct dump *d) { +void test_log_parts(struct logger *log) { + struct dump *d = log->dump; /* Write several copies of a part to the dump. */ struct part p; @@ -43,22 +45,22 @@ void test_log_parts(struct dump *d) { size_t offset = d->count; /* Write the full part. */ - logger_log_part(&p, + logger_log_part(log, &p, logger_mask_x | logger_mask_v | logger_mask_a | logger_mask_u | logger_mask_h | logger_mask_rho | logger_mask_consts, - &offset, d); + &offset); printf("Wrote part at offset %#016zx.\n", offset); /* Write only the position. */ p.x[0] = 2.0; - logger_log_part(&p, logger_mask_x, &offset, d); + logger_log_part(log, &p, logger_mask_x, &offset); printf("Wrote part at offset %#016zx.\n", offset); /* Write the position and velocity. */ p.x[0] = 3.0; p.v[0] = 0.3; - logger_log_part(&p, logger_mask_x | logger_mask_v, &offset, d); + logger_log_part(log, &p, logger_mask_x | logger_mask_v, &offset); printf("Wrote part at offset %#016zx.\n", offset); /* Recover the last part from the dump. */ @@ -101,7 +103,8 @@ void test_log_parts(struct dump *d) { } } -void test_log_gparts(struct dump *d) { +void test_log_gparts(struct logger *log) { + struct dump *d = log->dump; /* Write several copies of a part to the dump. */ struct gpart p; @@ -113,21 +116,21 @@ void test_log_gparts(struct dump *d) { size_t offset = d->count; /* Write the full part. */ - logger_log_gpart(&p, + logger_log_gpart(log, &p, logger_mask_x | logger_mask_v | logger_mask_a | logger_mask_h | logger_mask_consts, - &offset, d); + &offset); printf("Wrote gpart at offset %#016zx.\n", offset); /* Write only the position. */ p.x[0] = 2.0; - logger_log_gpart(&p, logger_mask_x, &offset, d); + logger_log_gpart(log, &p, logger_mask_x, &offset); printf("Wrote gpart at offset %#016zx.\n", offset); /* Write the position and velocity. */ p.x[0] = 3.0; p.v_full[0] = 0.3; - logger_log_gpart(&p, logger_mask_x | logger_mask_v, &offset, d); + logger_log_gpart(log, &p, logger_mask_x | logger_mask_v, &offset); printf("Wrote gpart at offset %#016zx.\n", offset); /* Recover the last part from the dump. */ @@ -170,82 +173,100 @@ void test_log_gparts(struct dump *d) { } } -void test_log_timestamps(struct dump *d) { +void test_log_timestamps(struct logger *log) { + struct dump *d = log->dump; /* The timestamp to log. */ unsigned long long int t = 10; + double time = 0.1; /* Start with an offset at the end of the dump. */ size_t offset = d->count; /* Log three consecutive timestamps. */ - logger_log_timestamp(t, &offset, d); + logger_log_timestamp(log, t, time, &offset); printf("Logged timestamp %020llu at offset %#016zx.\n", t, offset); t += 10; - logger_log_timestamp(t, &offset, d); + time = 0.2; + logger_log_timestamp(log, t, time, &offset); printf("Logged timestamp %020llu at offset %#016zx.\n", t, offset); t += 10; - logger_log_timestamp(t, &offset, d); + time = 0.3; + logger_log_timestamp(log, t, time, &offset); printf("Logged timestamp %020llu at offset %#016zx.\n", t, offset); /* Recover the three timestamps. */ size_t offset_old = offset; t = 0; - int mask = logger_read_timestamp(&t, &offset, (const char *)d->data); + time = 0; + int mask = logger_read_timestamp(&t, &time, &offset, (const char *)d->data); printf("Recovered timestamp %020llu at offset %#016zx with mask %#04x.\n", t, offset_old, mask); if (t != 30) { printf("FAIL: could not recover correct timestamp.\n"); abort(); } + if (time != 0.3) { + printf("FAIL: could not recover correct time %g.\n", time); + abort(); + } offset_old = offset; t = 0; - mask = logger_read_timestamp(&t, &offset, (const char *)d->data); + time = 0; + mask = logger_read_timestamp(&t, &time, &offset, (const char *)d->data); printf("Recovered timestamp %020llu at offset %#016zx with mask %#04x.\n", t, offset_old, mask); if (t != 20) { printf("FAIL: could not recover correct timestamp.\n"); abort(); } + if (time != 0.2) { + printf("FAIL: could not recover correct time.\n"); + abort(); + } offset_old = offset; t = 0; - mask = logger_read_timestamp(&t, &offset, (const char *)d->data); + time = 0; + mask = logger_read_timestamp(&t, &time, &offset, (const char *)d->data); printf("Recovered timestamp %020llu at offset %#016zx with mask %#04x.\n", t, offset_old, mask); if (t != 10) { printf("FAIL: could not recover correct timestamp.\n"); abort(); } + if (time != 0.1) { + printf("FAIL: could not recover correct time.\n"); + abort(); + } } int main(int argc, char *argv[]) { - /* Some constants. */ - char filename[256]; - const int now = time(NULL); - sprintf(filename, "/tmp/SWIFT_logger_test_%d.out", now); - - /* Prepare a dump. */ - struct dump d; - dump_init(&d, filename, 1024 * 1024); + /* Prepare a logger. */ + struct logger log; + struct swift_params params; + parser_read_file("logger.yml", ¶ms); + logger_init(&log, ¶ms); /* Test writing/reading parts. */ - test_log_parts(&d); + test_log_parts(&log); /* Test writing/reading gparts. */ - test_log_gparts(&d); + test_log_gparts(&log); /* Test writing/reading timestamps. */ - test_log_timestamps(&d); - - /* Finalize the dump. */ - dump_close(&d); + test_log_timestamps(&log); /* Be clean */ + char filename[256]; + sprintf(filename, "%s.dump", log.base_name); remove(filename); + /* Clean the logger. */ + logger_clean(&log); + /* Return a happy number. */ return 0; } diff --git a/tests/testMatrixInversion.c b/tests/testMatrixInversion.c index a15e0dab7ec793cf4a914b6eb89c63863ab24fb0..8cd0f4e272a6b7e587619117e1aa143409976c51 100644 --- a/tests/testMatrixInversion.c +++ b/tests/testMatrixInversion.c @@ -16,9 +16,13 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * ******************************************************************************/ +#include "../config.h" +/* Some standard headers. */ #include <stdlib.h> #include <string.h> + +/* Local headers */ #include "const.h" #include "dimension.h" #include "error.h" diff --git a/tests/testOutputList.c b/tests/testOutputList.c index b7df197405ee095cf9bf0a63e8cf7f00585f269f..cd9c62c3abc7462406950e24fa330788b76ed249 100644 --- a/tests/testOutputList.c +++ b/tests/testOutputList.c @@ -76,7 +76,7 @@ void test_no_cosmo(struct engine *e, char *name, int with_assert) { output_time = (double)(ti_next * e->time_base) + e->time_begin; } - output_list_clean(list); + output_list_clean(&list); }; void test_cosmo(struct engine *e, char *name, int with_assert) { @@ -112,7 +112,7 @@ void test_cosmo(struct engine *e, char *name, int with_assert) { output_time = (double)exp(ti_next * e->time_base) * e->cosmology->a_begin; } - output_list_clean(list); + output_list_clean(&list); }; int main(int argc, char *argv[]) { @@ -151,6 +151,8 @@ int main(int argc, char *argv[]) { test_cosmo(&e, "ScaleFactor", with_assert); test_cosmo(&e, "Time", without_assert); + cosmology_clean(&cosmo); + /* Write message and leave */ message("Test done"); return 0; diff --git a/tests/testParser.c b/tests/testParser.c index 3944e86fa19a1f623623383eabefe1094bf5addf..84ce70ff44fad0482573c740d5a174285655c08d 100644 --- a/tests/testParser.c +++ b/tests/testParser.c @@ -114,6 +114,8 @@ int main(int argc, char *argv[]) { int haveoptwords1 = parser_get_opt_param_string_array( ¶m_file, "Simulation:optwords", &nvar_result, &var_result, noptwords, optwords); + parser_free_param_string_array(nvar_result, var_result); + /* Check if we can read it again */ int haveoptwords2 = parser_get_opt_param_string_array( ¶m_file, "Simulation:optwords", &nvar_result, &var_result, noptwords, diff --git a/tests/testPeriodicBC.c b/tests/testPeriodicBC.c index de30b1af9ac8595cb081eb0702e9a7e7da13a162..e4a5a85845f92bfbecae85d9dc9453b38b9b7646 100644 --- a/tests/testPeriodicBC.c +++ b/tests/testPeriodicBC.c @@ -81,16 +81,16 @@ struct cell *make_cell(size_t n, double *offset, double size, double h, struct cell *cell = (struct cell *)malloc(sizeof(struct cell)); bzero(cell, sizeof(struct cell)); - if (posix_memalign((void **)&cell->parts, part_align, + if (posix_memalign((void **)&cell->hydro.parts, part_align, count * sizeof(struct part)) != 0) { error("couldn't allocate particles, no. of particles: %d", (int)count); } - bzero(cell->parts, count * sizeof(struct part)); + bzero(cell->hydro.parts, count * sizeof(struct part)); float h_max = 0.f; /* Construct the parts */ - struct part *part = cell->parts; + struct part *part = cell->hydro.parts; for (size_t x = 0; x < n; ++x) { for (size_t y = 0; y < n; ++y) { for (size_t z = 0; z < n; ++z) { @@ -161,10 +161,10 @@ struct cell *make_cell(size_t n, double *offset, double size, double h, /* Cell properties */ cell->split = 0; - cell->h_max = h_max; - cell->count = count; - cell->dx_max_part = 0.; - cell->dx_max_sort = 0.; + cell->hydro.h_max = h_max; + cell->hydro.count = count; + cell->hydro.dx_max_part = 0.; + cell->hydro.dx_max_sort = 0.; cell->width[0] = size; cell->width[1] = size; cell->width[2] = size; @@ -172,23 +172,23 @@ struct cell *make_cell(size_t n, double *offset, double size, double h, cell->loc[1] = offset[1]; cell->loc[2] = offset[2]; - cell->ti_old_part = 8; - cell->ti_hydro_end_min = 8; - cell->ti_hydro_end_max = 8; + cell->hydro.ti_old_part = 8; + cell->hydro.ti_end_min = 8; + cell->hydro.ti_end_max = 8; cell->nodeID = NODE_ID; - shuffle_particles(cell->parts, cell->count); + shuffle_particles(cell->hydro.parts, cell->hydro.count); - cell->sorted = 0; - for (int k = 0; k < 13; k++) cell->sort[k] = NULL; + cell->hydro.sorted = 0; + for (int k = 0; k < 13; k++) cell->hydro.sort[k] = NULL; return cell; } void clean_up(struct cell *ci) { - free(ci->parts); + free(ci->hydro.parts); for (int k = 0; k < 13; k++) - if (ci->sort[k] != NULL) free(ci->sort[k]); + if (ci->hydro.sort[k] != NULL) free(ci->hydro.sort[k]); free(ci); } @@ -196,8 +196,8 @@ void clean_up(struct cell *ci) { * @brief Initializes all particles field to be ready for a density calculation */ void zero_particle_fields(struct cell *c) { - for (int pid = 0; pid < c->count; pid++) { - hydro_init_part(&c->parts[pid], NULL); + for (int pid = 0; pid < c->hydro.count; pid++) { + hydro_init_part(&c->hydro.parts[pid], NULL); } } @@ -205,8 +205,8 @@ void zero_particle_fields(struct cell *c) { * @brief Ends the loop by adding the appropriate coefficients */ void end_calculation(struct cell *c, const struct cosmology *cosmo) { - for (int pid = 0; pid < c->count; pid++) { - hydro_end_density(&c->parts[pid], cosmo); + for (int pid = 0; pid < c->hydro.count; pid++) { + hydro_end_density(&c->hydro.parts[pid], cosmo); } } @@ -228,27 +228,27 @@ void dump_particle_fields(char *fileName, struct cell *main_cell, int i, int j, i, j, k); /* Write main cell */ - for (int pid = 0; pid < main_cell->count; pid++) { + for (int pid = 0; pid < main_cell->hydro.count; pid++) { fprintf(file, "%6llu %10f %10f %10f %10f %10f %10f %13e %13e %13e %13e %13e " "%13e %13e %13e\n", - main_cell->parts[pid].id, main_cell->parts[pid].x[0], - main_cell->parts[pid].x[1], main_cell->parts[pid].x[2], - main_cell->parts[pid].v[0], main_cell->parts[pid].v[1], - main_cell->parts[pid].v[2], - hydro_get_comoving_density(&main_cell->parts[pid]), + main_cell->hydro.parts[pid].id, main_cell->hydro.parts[pid].x[0], + main_cell->hydro.parts[pid].x[1], main_cell->hydro.parts[pid].x[2], + main_cell->hydro.parts[pid].v[0], main_cell->hydro.parts[pid].v[1], + main_cell->hydro.parts[pid].v[2], + hydro_get_comoving_density(&main_cell->hydro.parts[pid]), #if defined(GIZMO_MFV_SPH) || defined(SHADOWFAX_SPH) 0.f, #else - main_cell->parts[pid].density.rho_dh, + main_cell->hydro.parts[pid].density.rho_dh, #endif - main_cell->parts[pid].density.wcount, - main_cell->parts[pid].density.wcount_dh, + main_cell->hydro.parts[pid].density.wcount, + main_cell->hydro.parts[pid].density.wcount_dh, #if defined(GADGET2_SPH) || defined(DEFAULT_SPH) || defined(HOPKINS_PE_SPH) - main_cell->parts[pid].density.div_v, - main_cell->parts[pid].density.rot_v[0], - main_cell->parts[pid].density.rot_v[1], - main_cell->parts[pid].density.rot_v[2] + main_cell->hydro.parts[pid].density.div_v, + main_cell->hydro.parts[pid].density.rot_v[0], + main_cell->hydro.parts[pid].density.rot_v[1], + main_cell->hydro.parts[pid].density.rot_v[2] #else 0., 0., 0., 0. #endif diff --git a/tests/testPotentialPair.c b/tests/testPotentialPair.c index 12845bea9c44991ff615fbbf4c74dbb3b1a33520..064c86d42f8df907d1ffaaab164b6a2f8b534b19 100644 --- a/tests/testPotentialPair.c +++ b/tests/testPotentialPair.c @@ -149,11 +149,11 @@ int main(int argc, char *argv[]) { ci.loc[0] = 0.; ci.loc[1] = 0.; ci.loc[2] = 0.; - ci.gcount = 1; - ci.ti_old_gpart = 8; - ci.ti_old_multipole = 8; - ci.ti_gravity_end_min = 8; - ci.ti_gravity_end_max = 8; + ci.grav.count = 1; + ci.grav.ti_old_part = 8; + ci.grav.ti_old_multipole = 8; + ci.grav.ti_end_min = 8; + ci.grav.ti_end_max = 8; cj.nodeID = 0; cj.width[0] = 1.; @@ -162,39 +162,39 @@ int main(int argc, char *argv[]) { cj.loc[0] = 1.; cj.loc[1] = 0.; cj.loc[2] = 0.; - cj.gcount = num_tests; - cj.ti_old_gpart = 8; - cj.ti_old_multipole = 8; - cj.ti_gravity_end_min = 8; - cj.ti_gravity_end_max = 8; + cj.grav.count = num_tests; + cj.grav.ti_old_part = 8; + cj.grav.ti_old_multipole = 8; + cj.grav.ti_end_min = 8; + cj.grav.ti_end_max = 8; /* Allocate multipoles */ - ci.multipole = + ci.grav.multipole = (struct gravity_tensors *)malloc(sizeof(struct gravity_tensors)); - cj.multipole = + cj.grav.multipole = (struct gravity_tensors *)malloc(sizeof(struct gravity_tensors)); - bzero(ci.multipole, sizeof(struct gravity_tensors)); - bzero(cj.multipole, sizeof(struct gravity_tensors)); + bzero(ci.grav.multipole, sizeof(struct gravity_tensors)); + bzero(cj.grav.multipole, sizeof(struct gravity_tensors)); /* Set the multipoles */ - ci.multipole->r_max = 0.1; - cj.multipole->r_max = 0.1; + ci.grav.multipole->r_max = 0.1; + cj.grav.multipole->r_max = 0.1; /* Allocate the particles */ - if (posix_memalign((void **)&ci.gparts, gpart_align, - ci.gcount * sizeof(struct gpart)) != 0) + if (posix_memalign((void **)&ci.grav.parts, gpart_align, + ci.grav.count * sizeof(struct gpart)) != 0) error("Error allocating gparts for cell ci"); - bzero(ci.gparts, ci.gcount * sizeof(struct gpart)); + bzero(ci.grav.parts, ci.grav.count * sizeof(struct gpart)); - if (posix_memalign((void **)&cj.gparts, gpart_align, - cj.gcount * sizeof(struct gpart)) != 0) + if (posix_memalign((void **)&cj.grav.parts, gpart_align, + cj.grav.count * sizeof(struct gpart)) != 0) error("Error allocating gparts for cell ci"); - bzero(cj.gparts, cj.gcount * sizeof(struct gpart)); + bzero(cj.grav.parts, cj.grav.count * sizeof(struct gpart)); /* Create the mass-less test particles */ for (int n = 0; n < num_tests; ++n) { - struct gpart *gp = &cj.gparts[n]; + struct gpart *gp = &cj.grav.parts[n]; gp->x[0] = 1. + (n + 1) / ((double)num_tests); gp->x[1] = 0.5; @@ -205,6 +205,7 @@ int main(int argc, char *argv[]) { gp->id_or_neg_offset = n + 1; #ifdef SWIFT_DEBUG_CHECKS gp->ti_drift = 8; + gp->initialised = 1; #endif } @@ -213,15 +214,16 @@ int main(int argc, char *argv[]) { /***********************************************/ /* Create the massive particle */ - ci.gparts[0].x[0] = 0.; - ci.gparts[0].x[1] = 0.5; - ci.gparts[0].x[2] = 0.5; - ci.gparts[0].mass = 1.; - ci.gparts[0].time_bin = 1; - ci.gparts[0].type = swift_type_dark_matter; - ci.gparts[0].id_or_neg_offset = 1; + ci.grav.parts[0].x[0] = 0.; + ci.grav.parts[0].x[1] = 0.5; + ci.grav.parts[0].x[2] = 0.5; + ci.grav.parts[0].mass = 1.; + ci.grav.parts[0].time_bin = 1; + ci.grav.parts[0].type = swift_type_dark_matter; + ci.grav.parts[0].id_or_neg_offset = 1; #ifdef SWIFT_DEBUG_CHECKS - ci.gparts[0].ti_drift = 8; + ci.grav.parts[0].ti_drift = 8; + ci.grav.parts[0].initialised = 1; #endif /* Now compute the forces */ @@ -229,18 +231,18 @@ int main(int argc, char *argv[]) { /* Verify everything */ for (int n = 0; n < num_tests; ++n) { - const struct gpart *gp = &cj.gparts[n]; - const struct gpart *gp2 = &ci.gparts[0]; + const struct gpart *gp = &cj.grav.parts[n]; + const struct gpart *gp2 = &ci.grav.parts[0]; const double epsilon = gravity_get_softening(gp, &props); #if defined(POTENTIAL_GRAVITY) double pot_true = - potential(ci.gparts[0].mass, gp->x[0] - gp2->x[0], epsilon, rlr); + potential(ci.grav.parts[0].mass, gp->x[0] - gp2->x[0], epsilon, rlr); check_value(gp->potential, pot_true, "potential"); #endif double acc_true = - acceleration(ci.gparts[0].mass, gp->x[0] - gp2->x[0], epsilon, rlr); + acceleration(ci.grav.parts[0].mass, gp->x[0] - gp2->x[0], epsilon, rlr); /* message("x=%e f=%e f_true=%e pot=%e pot_true=%e", gp->x[0] - gp2->x[0], gp->a_grav[0], acc_true, gp->potential, pot_true); */ @@ -251,7 +253,7 @@ int main(int argc, char *argv[]) { message("\n\t\t P-P interactions all good\n"); /* Reset the accelerations */ - for (int n = 0; n < num_tests; ++n) gravity_init_gpart(&cj.gparts[n]); + for (int n = 0; n < num_tests; ++n) gravity_init_gpart(&cj.grav.parts[n]); /**********************************/ /* Test the basic PM interactions */ @@ -260,22 +262,22 @@ int main(int argc, char *argv[]) { /* Set an opening angle that allows P-M interactions */ props.theta_crit2 = 1.; - ci.gparts[0].mass = 0.; - ci.multipole->CoM[0] = 0.; - ci.multipole->CoM[1] = 0.5; - ci.multipole->CoM[2] = 0.5; + ci.grav.parts[0].mass = 0.; + ci.grav.multipole->CoM[0] = 0.; + ci.grav.multipole->CoM[1] = 0.5; + ci.grav.multipole->CoM[2] = 0.5; - bzero(&ci.multipole->m_pole, sizeof(struct multipole)); - bzero(&cj.multipole->m_pole, sizeof(struct multipole)); - ci.multipole->m_pole.M_000 = 1.; + bzero(&ci.grav.multipole->m_pole, sizeof(struct multipole)); + bzero(&cj.grav.multipole->m_pole, sizeof(struct multipole)); + ci.grav.multipole->m_pole.M_000 = 1.; /* Now compute the forces */ runner_dopair_grav_pp(&r, &ci, &cj, 1, 1); /* Verify everything */ for (int n = 0; n < num_tests; ++n) { - const struct gpart *gp = &cj.gparts[n]; - const struct gravity_tensors *mpole = ci.multipole; + const struct gpart *gp = &cj.grav.parts[n]; + const struct gravity_tensors *mpole = ci.grav.multipole; const double epsilon = gravity_get_softening(gp, &props); #if defined(POTENTIAL_GRAVITY) @@ -297,7 +299,7 @@ int main(int argc, char *argv[]) { #ifndef GADGET2_LONG_RANGE_CORRECTION /* Reset the accelerations */ - for (int n = 0; n < num_tests; ++n) gravity_init_gpart(&cj.gparts[n]); + for (int n = 0; n < num_tests; ++n) gravity_init_gpart(&cj.grav.parts[n]); /***************************************/ /* Test the truncated PM interactions */ @@ -314,8 +316,8 @@ int main(int argc, char *argv[]) { /* Verify everything */ for (int n = 0; n < num_tests; ++n) { - const struct gpart *gp = &cj.gparts[n]; - const struct gravity_tensors *mpole = ci.multipole; + const struct gpart *gp = &cj.grav.parts[n]; + const struct gravity_tensors *mpole = ci.grav.multipole; const double epsilon = gravity_get_softening(gp, &props); #if defined(POTENTIAL_GRAVITY) @@ -342,57 +344,58 @@ int main(int argc, char *argv[]) { /************************************************/ /* Reset the accelerations */ - for (int n = 0; n < num_tests; ++n) gravity_init_gpart(&cj.gparts[n]); + for (int n = 0; n < num_tests; ++n) gravity_init_gpart(&cj.grav.parts[n]); #if SELF_GRAVITY_MULTIPOLE_ORDER >= 3 /* Let's make ci more interesting */ - free(ci.gparts); - ci.gcount = 8; - if (posix_memalign((void **)&ci.gparts, gpart_align, - ci.gcount * sizeof(struct gpart)) != 0) + free(ci.grav.parts); + ci.grav.count = 8; + if (posix_memalign((void **)&ci.grav.parts, gpart_align, + ci.grav.count * sizeof(struct gpart)) != 0) error("Error allocating gparts for cell ci"); - bzero(ci.gparts, ci.gcount * sizeof(struct gpart)); + bzero(ci.grav.parts, ci.grav.count * sizeof(struct gpart)); /* Place particles on a simple cube of side-length 0.2 */ for (int n = 0; n < 8; ++n) { if (n & 1) - ci.gparts[n].x[0] = 0.0 - 0.1; + ci.grav.parts[n].x[0] = 0.0 - 0.1; else - ci.gparts[n].x[0] = 0.0 + 0.1; + ci.grav.parts[n].x[0] = 0.0 + 0.1; if (n & 2) - ci.gparts[n].x[1] = 0.5 - 0.1; + ci.grav.parts[n].x[1] = 0.5 - 0.1; else - ci.gparts[n].x[1] = 0.5 + 0.1; + ci.grav.parts[n].x[1] = 0.5 + 0.1; if (n & 2) - ci.gparts[n].x[2] = 0.5 - 0.1; + ci.grav.parts[n].x[2] = 0.5 - 0.1; else - ci.gparts[n].x[2] = 0.5 + 0.1; + ci.grav.parts[n].x[2] = 0.5 + 0.1; - ci.gparts[n].mass = 1. / 8.; + ci.grav.parts[n].mass = 1. / 8.; - ci.gparts[n].time_bin = 1; - ci.gparts[n].type = swift_type_dark_matter; - ci.gparts[n].id_or_neg_offset = 1; + ci.grav.parts[n].time_bin = 1; + ci.grav.parts[n].type = swift_type_dark_matter; + ci.grav.parts[n].id_or_neg_offset = 1; #ifdef SWIFT_DEBUG_CHECKS - ci.gparts[n].ti_drift = 8; + ci.grav.parts[n].ti_drift = 8; + ci.grav.parts[n].initialised = 1; #endif } /* Now let's make a multipole out of it. */ - gravity_reset(ci.multipole); - gravity_P2M(ci.multipole, ci.gparts, ci.gcount); + gravity_reset(ci.grav.multipole); + gravity_P2M(ci.grav.multipole, ci.grav.parts, ci.grav.count); - gravity_multipole_print(&ci.multipole->m_pole); + gravity_multipole_print(&ci.grav.multipole->m_pole); /* Compute the forces */ runner_dopair_grav_pp(&r, &ci, &cj, 1, 1); /* Verify everything */ for (int n = 0; n < num_tests; ++n) { - const struct gpart *gp = &cj.gparts[n]; + const struct gpart *gp = &cj.grav.parts[n]; #if defined(POTENTIAL_GRAVITY) double pot_true = 0; @@ -400,7 +403,7 @@ int main(int argc, char *argv[]) { double acc_true[3] = {0., 0., 0.}; for (int i = 0; i < 8; ++i) { - const struct gpart *gp2 = &ci.gparts[i]; + const struct gpart *gp2 = &ci.grav.parts[i]; const double epsilon = gravity_get_softening(gp, &props); const double dx[3] = {gp2->x[0] - gp->x[0], gp2->x[1] - gp->x[1], @@ -421,7 +424,7 @@ int main(int argc, char *argv[]) { #endif check_value_backend(gp->a_grav[0], acc_true[0], "acceleration", 1e-2, 1e-6); - /* const struct gravity_tensors *mpole = ci.multipole; */ + /* const struct gravity_tensors *mpole = ci.grav.multipole; */ /* message("x=%e f=%e f_true=%e pot=%e pot_true=%e %e %e", */ /* gp->x[0] - mpole->CoM[0], gp->a_grav[0], acc_true[0], * gp->potential, */ @@ -432,9 +435,14 @@ int main(int argc, char *argv[]) { #endif - free(ci.multipole); - free(cj.multipole); - free(ci.gparts); - free(cj.gparts); + free(ci.grav.multipole); + free(cj.grav.multipole); + free(ci.grav.parts); + free(cj.grav.parts); + + /* Clean up the caches */ + gravity_cache_clean(&r.ci_gravity_cache); + gravity_cache_clean(&r.cj_gravity_cache); + return 0; } diff --git a/tests/testPotentialSelf.c b/tests/testPotentialSelf.c index 6bf5dbd405830f1ba1c58d8627606a67111f5fb0..10eb499570a591daaf0de2e011f2346077905e8e 100644 --- a/tests/testPotentialSelf.c +++ b/tests/testPotentialSelf.c @@ -137,32 +137,33 @@ int main(int argc, char *argv[]) { c.loc[0] = 0.; c.loc[1] = 0.; c.loc[2] = 0.; - c.gcount = 1 + num_tests; - c.ti_old_gpart = 8; - c.ti_gravity_end_min = 8; - c.ti_gravity_end_max = 8; + c.grav.count = 1 + num_tests; + c.grav.ti_old_part = 8; + c.grav.ti_end_min = 8; + c.grav.ti_end_max = 8; - if (posix_memalign((void **)&c.gparts, gpart_align, - c.gcount * sizeof(struct gpart)) != 0) + if (posix_memalign((void **)&c.grav.parts, gpart_align, + c.grav.count * sizeof(struct gpart)) != 0) error("Impossible to allocate memory for the gparts."); - bzero(c.gparts, c.gcount * sizeof(struct gpart)); + bzero(c.grav.parts, c.grav.count * sizeof(struct gpart)); /* Create the massive particle */ - c.gparts[0].x[0] = 0.; - c.gparts[0].x[1] = 0.5; - c.gparts[0].x[2] = 0.5; - c.gparts[0].mass = 1.; - c.gparts[0].time_bin = 1; - c.gparts[0].type = swift_type_dark_matter; - c.gparts[0].id_or_neg_offset = 1; + c.grav.parts[0].x[0] = 0.; + c.grav.parts[0].x[1] = 0.5; + c.grav.parts[0].x[2] = 0.5; + c.grav.parts[0].mass = 1.; + c.grav.parts[0].time_bin = 1; + c.grav.parts[0].type = swift_type_dark_matter; + c.grav.parts[0].id_or_neg_offset = 1; #ifdef SWIFT_DEBUG_CHECKS - c.gparts[0].ti_drift = 8; + c.grav.parts[0].ti_drift = 8; + c.grav.parts[0].initialised = 1; #endif /* Create the mass-less particles */ for (int n = 1; n < num_tests + 1; ++n) { - struct gpart *gp = &c.gparts[n]; + struct gpart *gp = &c.grav.parts[n]; gp->x[0] = n / ((double)num_tests); gp->x[1] = 0.5; @@ -173,6 +174,7 @@ int main(int argc, char *argv[]) { gp->id_or_neg_offset = n + 1; #ifdef SWIFT_DEBUG_CHECKS gp->ti_drift = 8; + gp->initialised = 1; #endif } @@ -181,21 +183,27 @@ int main(int argc, char *argv[]) { /* Verify everything */ for (int n = 1; n < num_tests + 1; ++n) { - const struct gpart *gp = &c.gparts[n]; + const struct gpart *gp = &c.grav.parts[n]; const double epsilon = gravity_get_softening(gp, &props); #if defined(POTENTIAL_GRAVITY) - double pot_true = potential(c.gparts[0].mass, gp->x[0], epsilon, rlr); + double pot_true = potential(c.grav.parts[0].mass, gp->x[0], epsilon, rlr); check_value(gp->potential, pot_true, "potential"); #endif - double acc_true = acceleration(c.gparts[0].mass, gp->x[0], epsilon, rlr); + double acc_true = + acceleration(c.grav.parts[0].mass, gp->x[0], epsilon, rlr); check_value(gp->a_grav[0], acc_true, "acceleration"); // message("x=%e f=%e f_true=%e", gp->x[0], gp->a_grav[0], acc_true); } - free(c.gparts); + free(c.grav.parts); + + /* Clean up the caches */ + gravity_cache_clean(&r.ci_gravity_cache); + + /* All done! */ return 0; } diff --git a/tests/testReading.c b/tests/testReading.c index 5e6cee7f1e37f7615eb2c3b4edcaee1d4ebba319..d7d3fcbdae2f3ab744f338bb74e105644a5d88be 100644 --- a/tests/testReading.c +++ b/tests/testReading.c @@ -17,6 +17,9 @@ * ******************************************************************************/ +/* Some standard headers. */ +#include "../config.h" + /* Some standard headers. */ #include <stdlib.h> @@ -26,7 +29,6 @@ int main(int argc, char *argv[]) { size_t Ngas = 0, Ngpart = 0, Nspart = 0; - int periodic = -1; int flag_entropy_ICs = -1; int i, j, k; double dim[3]; @@ -48,8 +50,8 @@ int main(int argc, char *argv[]) { /* Read data */ read_ic_single("input.hdf5", &us, dim, &parts, &gparts, &sparts, &Ngas, - &Ngpart, &Nspart, &periodic, &flag_entropy_ICs, 1, 1, 0, 0, 0, - 1., 1., 1, 0); + &Ngpart, &Nspart, &flag_entropy_ICs, 1, 1, 0, 0, 0, 1., 1., 1, + 0); /* Check global properties read are correct */ assert(dim[0] == boxSize); @@ -57,7 +59,6 @@ int main(int argc, char *argv[]) { assert(dim[2] == boxSize); assert(Ngas == L * L * L); assert(Ngpart == L * L * L); - assert(periodic == 1); /* Check particles */ for (size_t n = 0; n < Ngas; ++n) { diff --git a/tests/testRiemannTRRS.c b/tests/testRiemannTRRS.c index 2c7098367a1ca8db84f097ad01aa2e1e411c433d..e975230c61cd58ad1a077e9b66949044cb7708da 100644 --- a/tests/testRiemannTRRS.c +++ b/tests/testRiemannTRRS.c @@ -16,8 +16,12 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * ******************************************************************************/ +#include "../config.h" +/* Local headers. */ #include <string.h> + +/* Local includes */ #include "error.h" #include "riemann/riemann_trrs.h" #include "tools.h" diff --git a/tests/testSPHStep.c b/tests/testSPHStep.c index 63834d94b7696e160dd7ca487ab7e9f1e943abfb..41694872efbfc4d9611127eb1e6324b2b0fa5500 100644 --- a/tests/testSPHStep.c +++ b/tests/testSPHStep.c @@ -35,19 +35,19 @@ struct cell *make_cell(size_t N, float cellSize, int offset[3], int id_offset) { size_t x, y, z, size; size = count * sizeof(struct part); - if (posix_memalign((void **)&cell->parts, part_align, size) != 0) { + if (posix_memalign((void **)&cell->hydro.parts, part_align, size) != 0) { error("couldn't allocate particles"); } size = count * sizeof(struct xpart); - if (posix_memalign((void **)&cell->xparts, xpart_align, size) != 0) { + if (posix_memalign((void **)&cell->hydro.xparts, xpart_align, size) != 0) { error("couldn't allocate extended particles"); } h = 1.2348 * cellSize / N; - part = cell->parts; - xpart = cell->xparts; + part = cell->hydro.parts; + xpart = cell->hydro.xparts; memset(part, 0, count * sizeof(struct part)); memset(xpart, 0, count * sizeof(struct xpart)); for (x = 0; x < N; ++x) { @@ -68,20 +68,20 @@ struct cell *make_cell(size_t N, float cellSize, int offset[3], int id_offset) { } cell->split = 0; - cell->h_max = h; - cell->count = count; - cell->gcount = 0; - cell->dx_max_part = 0.; - cell->dx_max_sort = 0.; + cell->hydro.h_max = h; + cell->hydro.count = count; + cell->grav.count = 0; + cell->hydro.dx_max_part = 0.; + cell->hydro.dx_max_sort = 0.; cell->width[0] = cellSize; cell->width[1] = cellSize; cell->width[2] = cellSize; - cell->ti_hydro_end_min = 1; - cell->ti_hydro_end_max = 1; + cell->hydro.ti_end_min = 1; + cell->hydro.ti_end_max = 1; - cell->sorted = 0; - for (int k = 0; k < 13; k++) cell->sort[k] = NULL; + cell->hydro.sorted = 0; + for (int k = 0; k < 13; k++) cell->hydro.sort[k] = NULL; return cell; } @@ -128,9 +128,9 @@ int main(int argc, char *argv[]) { /* Set particle properties */ for (j = 0; j < 27; ++j) - for (i = 0; i < cells[j]->count; ++i) { - cells[j]->parts[i].mass = dim * dim * dim * rho / (N * N * N); - cells[j]->parts[i].u = P / (hydro_gamma_minus_one * rho); + for (i = 0; i < cells[j]->hydro.count; ++i) { + cells[j]->hydro.parts[i].mass = dim * dim * dim * rho / (N * N * N); + cells[j]->hydro.parts[i].u = P / (hydro_gamma_minus_one * rho); } message("m=%f", dim * dim * dim * rho / (N * N * N)); @@ -171,7 +171,7 @@ int main(int argc, char *argv[]) { e.ti_current = 1; /* The tracked particle */ - p = &(ci->parts[N * N * N / 2 + N * N / 2 + N / 2]); + p = &(ci->hydro.parts[N * N * N / 2 + N * N / 2 + N / 2]); message("Studying particle p->id=%lld", p->id); @@ -209,10 +209,10 @@ int main(int argc, char *argv[]) { message("ti_end=%d", p->ti_end); for (int j = 0; j < 27; ++j) { - free(cells[j]->parts); - free(cells[j]->xparts); + free(cells[j]->hydro.parts); + free(cells[j]->hydro.xparts); for (int k = 0; k < 13; k++) - if (cells[j]->sort[k] != NULL) free(cells[j]->sort[k]); + if (cells[j]->hydro.sort[k] != NULL) free(cells[j]->hydro.sort[k]); free(cells[j]); } diff --git a/tests/testSelectOutput.c b/tests/testSelectOutput.c index 7a02b7fb7ed0542036c60b125dcbe9a36a331e6d..01c80ce8f15f2be7d264ceecdb397950b822de35 100644 --- a/tests/testSelectOutput.c +++ b/tests/testSelectOutput.c @@ -85,8 +85,8 @@ int main(int argc, char *argv[]) { char *base_name = "testSelectOutput"; size_t Ngas = 0, Ngpart = 0, Nspart = 0; - int periodic = -1; int flag_entropy_ICs = -1; + int periodic = 1; double dim[3]; struct part *parts = NULL; struct gpart *gparts = NULL; @@ -111,8 +111,8 @@ int main(int argc, char *argv[]) { /* Read data */ message("Reading initial conditions."); read_ic_single("input.hdf5", &us, dim, &parts, &gparts, &sparts, &Ngas, - &Ngpart, &Nspart, &periodic, &flag_entropy_ICs, 1, 0, 0, 0, 0, - 1., 1., 1, 0); + &Ngpart, &Nspart, &flag_entropy_ICs, 1, 0, 0, 0, 0, 1., 1., 1, + 0); /* pseudo initialization of the space */ message("Initialization of the space."); diff --git a/tests/testSymmetry.c b/tests/testSymmetry.c index 886290ab984603d0afb3201377611598cd7163e4..ce1e2e9354c4d59a6e58619d43b743864ed38585 100644 --- a/tests/testSymmetry.c +++ b/tests/testSymmetry.c @@ -27,7 +27,10 @@ void print_bytes(void *p, size_t len) { printf("("); - for (size_t i = 0; i < len; ++i) printf("%02x", ((unsigned char *)p)[i]); + for (size_t i = 0; i < len; ++i) { + printf("%02x", ((unsigned char *)p)[i]); + if (i % 4 == 3) printf("|"); + } printf(")\n"); } @@ -162,8 +165,8 @@ void test(void) { if (i_not_ok) { printParticle_single(&pi, &xpi); printParticle_single(&pi2, &xpi); - print_bytes(&pj, sizeof(struct part)); - print_bytes(&pj2, sizeof(struct part)); + print_bytes(&pi, sizeof(struct part)); + print_bytes(&pi2, sizeof(struct part)); error("Particles 'pi' do not match after density (byte = %d)", i_not_ok); } if (j_not_ok) { @@ -220,17 +223,15 @@ void test(void) { j_not_ok |= c_is_d; } #else - i_not_ok = - strncmp((const char *)&pi, (const char *)&pi2, sizeof(struct part)); - j_not_ok = - strncmp((const char *)&pj, (const char *)&pj2, sizeof(struct part)); + i_not_ok = memcmp((char *)&pi, (char *)&pi2, sizeof(struct part)); + j_not_ok = memcmp((char *)&pj, (char *)&pj2, sizeof(struct part)); #endif if (i_not_ok) { printParticle_single(&pi, &xpi); printParticle_single(&pi2, &xpi); - print_bytes(&pj, sizeof(struct part)); - print_bytes(&pj2, sizeof(struct part)); + print_bytes(&pi, sizeof(struct part)); + print_bytes(&pi2, sizeof(struct part)); error("Particles 'pi' do not match after force (byte = %d)", i_not_ok); } if (j_not_ok) { diff --git a/tests/testTimeIntegration.c b/tests/testTimeIntegration.c index 2034c402a2d626a7b503613f6cade821ec438151..b7f5201356ee52419038c8379dde14c9bab82055 100644 --- a/tests/testTimeIntegration.c +++ b/tests/testTimeIntegration.c @@ -83,9 +83,9 @@ int main(int argc, char *argv[]) { xparts[0].v_full[2] = 0.; /* Set the particle in the cell */ - c.parts = parts; - c.xparts = xparts; - c.count = 1; + c.hydro.parts = parts; + c.hydro.xparts = xparts; + c.hydro.count = 1; c.split = 0; /* Create an engine and a fake runner */ @@ -108,11 +108,13 @@ int main(int argc, char *argv[]) { eng.time += dt; /* Compute gravitational acceleration */ - float r2 = - c.parts[0].x[0] * c.parts[0].x[0] + c.parts[0].x[1] * c.parts[0].x[1]; + float r2 = c.hydro.parts[0].x[0] * c.hydro.parts[0].x[0] + + c.hydro.parts[0].x[1] * c.hydro.parts[0].x[1]; float r = sqrtf(r2); - c.parts[0].a_hydro[0] = -(G * M_sun * c.parts[0].x[0] / r * r * r); - c.parts[0].a_hydro[1] = -(G * M_sun * c.parts[0].x[1] / r * r * r); + c.hydro.parts[0].a_hydro[0] = + -(G * M_sun * c.hydro.parts[0].x[0] / r * r * r); + c.hydro.parts[0].a_hydro[1] = + -(G * M_sun * c.hydro.parts[0].x[1] / r * r * r); /* Kick... */ runner_do_kick2(&run, &c, 0); diff --git a/tests/testVoronoi2D.c b/tests/testVoronoi2D.c index 60a71624904c11a3cdb3b90906189df60bfc6956..5057278efaa3ba0e1ccec2ba6b032cd12b029ff9 100644 --- a/tests/testVoronoi2D.c +++ b/tests/testVoronoi2D.c @@ -16,6 +16,9 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * ******************************************************************************/ +#include "../config.h" + +/* Local headers. */ #include "hydro/Shadowswift/voronoi2d_algorithm.h" #include "tools.h" diff --git a/tests/testVoronoi3D.c b/tests/testVoronoi3D.c index db5c33aa6e4ef0792373febd5d773a6d1198db29..5e0288fa9b3e13e0c6a6fb13db202e0f73f29a5b 100644 --- a/tests/testVoronoi3D.c +++ b/tests/testVoronoi3D.c @@ -16,8 +16,12 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * ******************************************************************************/ +#include "../config.h" +/* Some standard headers. */ #include <stdlib.h> + +/* Local headers. */ #include "error.h" #include "hydro/Shadowswift/voronoi3d_algorithm.h" #include "part.h" diff --git a/theory/Multipoles/bibliography.bib b/theory/Multipoles/bibliography.bib index 077525a9e4db781ea58bd46ef2ba109d6c074be0..245a5223d43aff3ed871cc7ce278fb319d88a938 100644 --- a/theory/Multipoles/bibliography.bib +++ b/theory/Multipoles/bibliography.bib @@ -275,6 +275,21 @@ keywords = "adaptive algorithms" adsnote = {Provided by the SAO/NASA Astrophysics Data System} } +@BOOK{Abramowitz1972, + author = {{Abramowitz}, M. and {Stegun}, I.~A.}, + title = "{Handbook of Mathematical Functions}", +booktitle = {Handbook of Mathematical Functions, New York: Dover, 1972}, + year = 1972, + adsurl = {http://cdsads.u-strasbg.fr/abs/1972hmfw.book.....A}, + adsnote = {Provided by the SAO/NASA Astrophysics Data System} +} - +@book{Hastings1955 + author = {Hastings, Cecil}, + title = {Approximations for Digital Computers}, + year = {1955}, + isbn = {0691079145}, + publisher = {Princeton University Press}, + address = {Princeton, NJ, USA}, +}